查看原文
其他

腾讯面试:如何调试Docker容器

Editor's Note

哈喽哈喽,大家好,最近面试腾讯,聊到Docker的调试,大多时候,为了docker轻量化,容器内部都是没有相关调试命令的,所以Docker调试是云原生时代,运维必须要掌握的,正好薛总之前整理过相关的文章,拿来分享下

The following article is from 云原生生态圈 Author Marionxue


Linux Network Namespace

Linux的Namespace[1]机制提供了一种资源隔离的解决方案,而目前Linux内核里面实现且支持的Namespace有7种,如下表:

名称定义说明
CgroupCLONE_NEWCGROUPCgroup root directory (since Linux 4.6)
IPCCLONE_NEWIPCSystem V IPC, POSIX message queues (since Linux 2.6.19)
NetworkCLONE_NEWNETNetwork devices, stacks, ports, etc. (since Linux 2.6.24)
MountCLONE_NEWNSMount points (since Linux 2.4.19)
PIDCLONE_NEWPIDProcess IDs (since Linux 2.6.24)
UserCLONE_NEWUSERUser and group IDs (started in Linux 2.6.23 and completed in Linux 3.8)
UTSCLONE_NEWUTSHostname and NIS domain name (since Linux 2.6.19)

但是今天只分析一下Network NameSpace以及管理,Network NameSpace是实现网络空间隔离或者说网络虚拟化的基础, 不管是Docker还是虚拟机技术上的程序也都是由Linux内核实现的Network NameSpace隔离开的命令空间内运行。ip netns就是管理命令空间的命令,在学习之前,先了解几个命令unsharereadlinknsenter

unshare

运行一些与父级不共享的某些名称空间的程序。

root@node3:~# unshare --help

Usage:
 unshare [options] <program> [<argument>...]

Run a program with some namespaces unshared from the parent.

Options:
-h,--help
显示帮助文本并退出。
-i,-- ipc 取消共享IPC名称空间。
-m,-- mount 取消共享安装名称空间。
-n,-- net 取消共享网络名称空间。
-p,-- pid 取消共享pid名称空间。另请参见--fork和--mount-proc选项。
-u,-- uts 取消共享UTS名称空间。
-U,--user 取消共享用户名称空间。
-f,-将指定程序fork为取消共享的子进程,而不是直接运行它。这在创建新的pid名称空间时很有用。
--mount-proc [=mountpoint]在运行程序之前,将proc文件系统挂载到mountpoint (默认为/ proc)。这在创建新的pid名称空间时很有用。这也意味着创建一个新的挂载名称空间,因为/ proc挂载否则会破坏系统上的现有程序。新的proc文件系统显式安装为私有文件(由MS_PRIVATE | MS_REC)。
-r,-- map-root-user 仅在当前有效的用户和组ID已映射到新创建的用户名称空间中的超级用户UID和GID之后,才运行该程序。这样即使在没有特权的情况下运行,也可以方便地获得管理新创建的名称空间各个方面所需的功能(例如,在网络名称空间中配置接口或在安装名称空间中安装文件系统)。仅作为一项便利功能,它不支持更复杂的用例,例如映射多个范围的UID和GID。

For more details see unshare(1).

readLink

readlink是Linux系统中一个常用工具,主要用来找出符号链接所指向的位置

root@node3:/etc# readlink /etc/resolv.conf
../run/resolvconf/resolv.conf

nsenter

一个可以在指定进程的命令空间下运行指定程序的命令。这个命令大家在容器网络调试下可能常用,比如在一些没有网络调试工具(ip addresspingtelnetsstcpdump)的容器内利用宿主机上的命令进行容器内网络连通性的调试等等

root@node3:/etc# nsenter --help
...略
options:
-t, --target pid:指定被进入命名空间的目标进程的pid
-m, --mount[=file]:进入mount命令空间。如果指定了file,则进入file的命令空间
-u, --uts[=file]:进入uts命令空间。如果指定了file,则进入file的命令空间
-i, --ipc[=file]:进入ipc命令空间。如果指定了file,则进入file的命令空间
-n, --net[=file]:进入net命令空间。如果指定了file,则进入file的命令空间
-p, --pid[=file]:进入pid命令空间。如果指定了file,则进入file的命令空间
-U, --user[=file]:进入user命令空间。如果指定了file,则进入file的命令空间
-G, --setgid gid:设置运行程序的gid
-S, --setuid uid:设置运行程序的uid
-r, --root[=directory]:设置根目录
-w, --wd[=directory]:设置工作目录

运行一个Demo演示一下


root@node3:/etc# docker run -d --name test nginx
31095893cbddd999a9f2d9e78cd4c057d4f5b3763fe1b5ecd5d68df4e9ce5943
root@node3:/etc# docker inspect -f {{.State.Pid}} test
26308
root@node3:/etc# nsenter -t 26308 -n
root@node3:/etc# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
8: eth0@if9: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
root@node3:/etc# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         172.17.0.1      0.0.0.0         UG    0      0        0 eth0
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 eth0
root@node3:/etc# netstat -unlpt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      26308/nginx: master
tcp6       0      0 :::80                   :::*                    LISTEN      26308/nginx: master
root@node3:/etc# exit
logout

这样看起来是不是很清楚,以后排查容器网络感觉又方便不少了

前期准备工作做了不少,下面好好说说Network NameSpace如何通过ip netns进行管理

Network NameSpace管理

ip netns命令基本很少使用到,所以先来熟悉一番

root@node3:~# ip netns help
Usage: ip netns list
       ip netns add NAME
       ip netns set NAME NETNSID
       ip [-all] netns delete [NAME]
       ip netns identify [PID]
       ip netns pids NAME
       ip [-all] netns exec [NAME] cmd ...
       ip netns monitor
       ip netns list-id

ip netns list

Linux系统下默认是没有network namespace,我们可以通过ls或者ip netns查看

root@node3:~# ip netns list
root@node3:~# ls -al /var/run/netns/
total 0
drwxr-xr-x  2 root root   40 Oct  6 05:07 .
drwxr-xr-x 26 root root 1020 Oct  6 04:57 ..

ip netns add

root@node3:~# ip netns add nsdemo1
root@node3:~# ip netns add nsdemo1 # 重复创建会报错
Cannot create namespace file "/var/run/netns/nsdemo1": File exists
root@node3:~# ip netns add nsdemo2
root@node3:~# ip netns list
nsdemo2
nsdemo1
root@node3:~# ls -al /var/run/netns/
total 0
drwxr-xr-x  2 root root   80 Oct  6 05:08 .
drwxr-xr-x 26 root root 1020 Oct  6 04:57 ..
-r--r--r--  1 root root    0 Oct  6 05:08 nsdemo1
-r--r--r--  1 root root    0 Oct  6 05:08 nsdemo2

ip netns add创建的network namespace会在/var/run/netns目录下创建一个同名的文件,

ip netns del

root@node3:~# ip netns add nsdemo1
root@node3:~# ip netns add nsdemo2
root@node3:~# ip netns list
nsdemo2
nsdemo1
root@node3:~# ip -all netns del
root@node3:~# ip netns list
root@node3:~# ip netns add nsdemo3
root@node3:~# ip netns list
nsdemo3
root@node3:~# ip -all netns delete # 可以使用del,也可以使用delete
root@node3:~# ip netns list
root@node3:~#

ip netns exec

在创建了一个新的network namespace之后,很好奇里面究竟包含哪些东西,此时就可以通过exec进去查看,除了网络信息之外与宿主机是没有区别的

root@node3:~# ip netns add nsdemo3
root@node3:~# ip netns exec nsdemo3 ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    
root@node3:~# ip netns exec nsdemo3 bash
root@node3:~# ip addr # 每个network namespace都存在一个没有启用的lo本地回环网卡
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
root@node3:~# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface

# 在进入nsdemo3这个network namespace之前,给nsdemo3的bash指定配置文件,用来修改bash前缀区分shell
root@node3:~# ip netns exec nsdemo3 /bin/bash --rcfile <(echo "PS1=\"namespace nsdemo3> \"")
namespace nsdemo3> ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
namespace nsdemo3> exit
exit

启用network namespace中的lo网卡

root@node3:~# ip netns del nsdemo3
root@node3:~# ip netns list
root@node3:~# ip netns add nsdemo4
root@node3:~# ip netns list
nsdemo4
root@node3:~# ip netns exec nsdemo4 /bin/bash --rcfile <(echo "PS1=\"namespace nsdemo4> \"")
namespace nsdemo4> ip addr
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
namespace nsdemo4> ip link set lo up # 启用网卡lo
namespace nsdemo4> ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
namespace nsdemo4> ping 192.168.99.128 # 查看与主机之间的网络状态,发现网络不同
connect: Network is unreachable
namespace nsdemo4> exit
exit
root@node3:~# ip netns exec nsdemo4 /bin/bash --rcfile <(echo "PS1=\"namespace nsdemo4> \"")
namespace nsdemo4> ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever

默认情况下,隔离的网络命名空间是无法进行通信的,同样可以利用ip的子命令link创建vethbridge类型的网卡实现两个或者多个隔离的Network NameSpace之间相互通信。这样更有助于理解容器网络之间的隔离与通信。



运维技术交流群

「运维研习社」建立了运维技术交流群,大家可以添加小编微信进行加群。欢迎有想法、乐于分享的朋友们一起进群交流学习。


扫描添加好友邀您进运维交流群

免费知识星球

「运维研习社」同时建立了免费知识星球做运维知识沉淀,大家可以直接扫码进星球。欢迎进星球提问或发表看法。


如何快速搭建kubernetes实验环境?

详解轻量日志聚合系统Loki架构!

MySQL不停机主从搭建

Nginx通过这个配置减少TIME-WAIT

如何从Docker镜像中提取Dockerfile?

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存