docker背景知识1 命名空间Namespace(nsenter、lsns命令)


相关文章:
Linux ip netns 命令

如下操作都是在centos7上执行,通过cat /proc/version查看系统信息。

1. 什么是Linux namespace

linux namespaces是Linux提供的一种内核级别环境隔离的方法,也是Container环境隔离的底层技术,Linux Namespaces共有如下种类

分类系统调用参数相关内核版本
Mount namespacesCLONE_NEWNSLinux 2.4.19
UTS namespacesCLONE_NEWUTSLinux 2.6.19
IPC namespacesCLONE_NEWIPCLinux 2.6.19
PID namespacesCLONE_NEWPIDLinux 2.6.24
Network namespacesCLONE_NEWNETLinux 2.6.29
User namespacesCLONE_NEWUSERLinux 3.8
  • Mount: mount表空间隔离,配合chroot系统调用,使程序有自己的文件系统
  • UTS: hostname(本地主机名)和doaminname隔离,使应用有自己独立的主机名
    假设分配UTS1、UTS2给2个进程P1、P2,那么P1看到的本地主机名H1,P2看到的本地主机名H2。放佛P1、P2是运行在2个不同的机器上一样。
  • IPC: 隔离进程间通讯
  • PID: 使程序包括子程序构造一个独立的程序集,最先创建的程序为1号pid
  • Network: 网络空间隔离,支持在此空间的程序拥有独立的网络栈。
    一个进程属于什么Network命名空间,决定了运行在进程里的应用程序能看见什么网络端口。每个网络接口属于一个命名空间,但是可以从一个命名空间转移到另一个。每个容器都使用属于它自己的网络命名空间,因此每个容器技能看到它自己的一组网络接口。
  • User: 此空间下有独立的uid/gid系统

因此,一个容器拥有一组命名空间,即Mount1、UTS1、IPC1、PID1、Network1、User1组合。

Namespaces操作的可以通过三个系统调用完成clone(),unshare(),setns(),默认情况下子进程继承新父进程的namespaces

2. 探索namespaces

2.1 查询本机所有namespaces

2.1.1 通过lsns命令查看全部ns

❯ sudo lsns
        NS TYPE  NPROCS   PID USER   COMMAND
4026531836 pid      317     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531837 user     318     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531838 uts      317     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531839 ipc      317     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531840 mnt      312     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026531856 mnt        1    91 root   kdevtmpfs
4026531956 net      317     1 root   /usr/lib/systemd/systemd --switched-root --system --deserialize 22
4026532215 mnt        1  5127 chrony /usr/sbin/chronyd
4026532216 mnt        2  5120 root   /usr/sbin/NetworkManager --no-daemon
4026532219 mnt        1  6264 root   /usr/bin/simple
4026532220 uts        1  6264 root   /usr/bin/simple
4026532221 ipc        1  6264 root   /usr/bin/simple
4026532222 pid        1  6264 root   /usr/bin/simple
4026532224 net        1  6264 root   /usr/bin/simple
4026532281 mnt        1  5438 root   /usr/sbin/cupsd -f

lsns -t net 可以过滤出 network相关的命名空间

2.1.2 通过查看proc文件系统查看全部ns

每个进程可能有一组 命名空间

查看某个进程的下的命名空间

# ls  -tl /proc/27293/ns/
total 0
lrwxrwxrwx 1 root root 0 Apr 12 15:49 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Apr 12 13:59 ipc -> ipc:[4026532452]
lrwxrwxrwx 1 root root 0 Apr 12 13:59 mnt -> mnt:[4026532450]
lrwxrwxrwx 1 root root 0 Apr 12 13:59 net -> net:[4026532455]
lrwxrwxrwx 1 root root 0 Apr 12 13:59 pid -> pid:[4026532453]
lrwxrwxrwx 1 root root 0 Apr 12 13:59 uts -> uts:[4026532451]

全部进程的命名空间

❯ sudo ls -l /proc/*/ns/ |awk '{print $11}' |sort -u
ipc:[4026531839]
ipc:[4026532221]
mnt:[4026531840]
mnt:[4026531856]
mnt:[4026532215]
mnt:[4026532216]
mnt:[4026532219]
mnt:[4026532281]
net:[4026531956]
net:[4026532224]
pid:[4026531836]
pid:[4026532222]
user:[4026531837]
uts:[4026531838]
uts:[4026532220]

2.2 查看某个docker 容器的namespaces

>sudo docker inspect  -f "{{.State.Pid}}" 34b48c1d3093  //34b48c1d3093是容器id
>10427    //查询容器对应在主机上的pid
> sudo ls -l /proc/10427/ns     //查看进程下的 ns
lrwxrwxrwx 1 root root 0 Dec 11 16:21 ipc -> ipc:[4026533018]
lrwxrwxrwx 1 root root 0 Dec 11 16:21 mnt -> mnt:[4026533016]
lrwxrwxrwx 1 root root 0 Dec 11 16:21 net -> net:[4026531956]
lrwxrwxrwx 1 root root 0 Dec 11 16:21 pid -> pid:[4026533019]
lrwxrwxrwx 1 root root 0 Dec 11 16:21 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Dec 11 16:21 uts -> uts:[4026533017]

  • 首先查找到容器id
  • 根据容器id查找容器对应的pid
  • 根据pid,查找 /proc/{pid}/ns路径下的命名空间

从结果看,一个容器对应6个命名空间,类型不重复,正好验证了我们之前的结论 “一个容器拥有一组命名空间,即Mount1、UTS1、IPC1、PID1、Network1、User1组合”。

2.3 进入命名空间命令nsenter

nsenter作用是查看某个命令空间内的信息。

nsenter的使用帮忙如下:

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

Run a program with namespaces of other processes.

Options:
 -t, --target <pid>     target process to get namespaces from
 -m, --mount[=<file>]   enter mount namespace
 -u, --uts[=<file>]     enter UTS namespace (hostname etc)
 -i, --ipc[=<file>]     enter System V IPC namespace
 -n, --net[=<file>]     enter network namespace
 -p, --pid[=<file>]     enter pid namespace
 -U, --user[=<file>]    enter user namespace
 -S, --setuid <uid>     set uid in entered namespace
 -G, --setgid <gid>     set gid in entered namespace
      <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>--preserve-credentials do not touch uids or gids
 -r, --root[=<*dir*>]     set the root directory
 -w, --wd[=<*dir*>]       set the working directory
 -F, --no-fork          do not fork before exec'ing <program>
 -Z, --follow-context   set SELinux context according to --target PID

 -h, --help     display this help and exit
 -V, --version  output version information and exit

For more details see nsenter(1).

参数解释:

  • t 基本每个命令都要带的
  • m n p u U 参数是互斥的,因为一个docker映射一组命名空间,你只能进去其中的一个空间

操作特定进程命名空间中的信息,容器就是一个命名空间

进入网络命名空间,查看进程网卡信息,10427 是一个docker的pid (docker inspect 中的pid字段):

sudo nsenter -t 10427 -n ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    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
66: eth0@if67: <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

也可以通过 nsenter -t 10427 -n bash 进入network的命名空间,单独执行ip addr命令


查看容器的Host信息(主机名)

❯ sudo nsenter -t 10427 -u hostname
d911aa5d1a1c   //hostname

等价于进入容器后,执行hostname命令

>docker exec -it 34b48c1d3093 sh    //进入容器
>/home/zenap # hostname
  d911aa5d1a1c   //hostname

3. namespace相关系统调用

clone 创建新进程,flags参数可以用来创建新的namespace
setns 让进程加入存在的namespace
unshare 将调用进程移动到新的namespace中
ioctl_ns 查看namespace的信息

4. 转移设备

我们可以在不同的 Network Namespace 之间转移设备(如veth)。由于一个设备只能属于一个 Network Namespace ,所以转移后在这个 Network Namespace 内就看不到这个设备了。

其中,veth设备属于可转移设备,而很多其它设备(如lo、vxlan、ppp、bridge等)是不可以转移的。

假设主机上有个veth199网卡,当执行下面命令后,在主机的default空间下,就看不到 了:

ip link set veth199 netns netns199 //把veth199 加入到这个新建的空间

你可以进入netns199 中进行查看

5. docker与 主机互找 veth对端

步骤1. 下面是查询docker ae1872516331 对应主机上的pid

$ docker inspect --format '{{.State.Pid}}'  ae1872516331
849053

可以看到 pid =849053

步骤2. 根据pid,查看网络命名空间

 $ ls -l /proc/849053/ns/net
lrwxrwxrwx 1 root root 0 Jul 10 14:47 /proc/849053/ns/net -> 'net:[4026542776]'

可以看到 网络命名空间的标识是 4026542776

步骤3. 根据这个网络标识,去查看 pid

$ lsns -t net |grep 4026542776
4026542776 net      10 152598 root                 91 /run/docker/netns/89f768f4e3ad sleep 1800

这里面的 pid 是152598 , 请问 152598 和步骤1中的pid 849053 是什么关系 ?
我用ps -ef|grep 152598 没搜到进程

答:一般理论分析,应该是同一个pid,不知道为什么实际上是2个pid,并且152598 会变,而849053 不变
chartgpt反馈说,有可能152598 是一个管理ns的进程

注意:pid的值一直在变,这会变成248516 了:

$  lsns -t net |grep 4026542776
4026542776 net      10 248516 65535                91 /run/docker/netns/89f768f4e3ad /pause

也就是说 lsns -t net 命令里面的pid 不能和 docker inspect 中的 pid 划等号。

总结:

1)如果从docker 内 ip a 作为源头,想找到某个虚拟网口对应主机的,比较简单

/home/zenap # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1000
    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

253: eth0@if252: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1450 qdisc noqueue state UP qlen 1000
    link/ether d6:30:1b:47:dd:2f brd ff:ff:ff:ff:ff:ff
    inet 100.100.2.201/16 brd 100.100.255.255 scope global eth0     没有link-netnsid,说明是default命名空间
       valid_lft forever preferred_lft forever
    inet6 fd01::2c9/64 scope global
       valid_lft forever preferred_lft forever
    inet6 fe80::d430:1bff:fe47:dd2f/64 scope link
       valid_lft forever preferred_lft forever

直接 在主机上 ip a|grep 252即可

2)如果从主机 上ip a 作为源头,想找到对端是哪个docker 的(当然也不一定是docker的),稍微复杂

下面是主机的一个信息:

252: vethOv02n33b@if253: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master ovs-system state UP group default qlen 1000
    link/ether a6:f7:33:b5:39:d8 brd ff:ff:ff:ff:ff:ff link-netnsid 91
    inet6 fe80::a4f7:33ff:feb5:39d8/64 scope link
       valid_lft forever preferred_lft forever

直接 根据 link-netnsid 91 作为条件

ls -t net | grep 91 ,找到 网络命名空间的唯一标识符 4026542776 ,
然后写一个脚本,去/proc/[pid]/ns/net下扫描, 找到 值为 4026542776 的,此时[pid] 就是docker的pid,
再去所有的docker中捞pid为[pid]的那个

参考

Linux namespace命名空间
unshare命令详解及案例

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值