当我创建一个新的docker容器,如
docker run -it -m 560m --cpuset-cpus=1,2 ubuntu sleep 120
并检查其名称空间,我可以看到已经创建了新的名称空间(例如pid 7047)。
root@dude2:~# ls /proc/7047/ns -la
total 0
dr-x--x--x 2 root root 0 Jul 7 12:17 .
dr-xr-xr-x 9 root root 0 Jul 7 12:16 ..
lrwxrwxrwx 1 root root 0 Jul 7 12:17 ipc -> ipc:[4026532465]
lrwxrwxrwx 1 root root 0 Jul 7 12:17 mnt -> mnt:[4026532463]
lrwxrwxrwx 1 root root 0 Jul 7 12:17 net -> net:[4026532299]
lrwxrwxrwx 1 root root 0 Jul 7 12:17 pid -> pid:[4026532466]
lrwxrwxrwx 1 root root 0 Jul 7 12:17 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul 7 12:17 uts -> uts:[4026532464]
root@dude2:~# ls /proc/self/ns -la
当我检查ip netns list
时,我看不到新的网络命名空间。
dude@dude2:~/docker/testroot$ ip netns list
dude@dude2:~/docker/testroot$
知道为什么吗?
这是因为docker没有创建所需的符号链接:
# (as root)
pid=$(docker inspect -f '{{.State.Pid}}' ${container_id})
mkdir -p /var/run/netns/
ln -sfT /proc/$pid/ns/net /var/run/netns/$container_id
然后,容器的netns名称空间可以用ip netns ${container_id}
检查,例如:
# e.g. show stats about eth0 inside the container
ip netns exec "${container_id}" ip -s link show eth0
如@jary所示,ip netns
命令只适用于/var/run/netns
中的命名空间符号链接。然而,如果你有nsenter
命令可用(util-linux
包的一部分),你可以使用你的docker容器的PID来完成同样的事情。
要获取docker容器的PID,可以运行:
docker inspect --format '{{.State.Pid}}' <container_name_or_Id>
在容器的网络命名空间中获取命令:
nsenter -t <contanier_pid> -n <command>
例句:
$ docker inspect --format '{{.State.Pid}}' weechat
4432
$ sudo nsenter -t 4432 -n ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default
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
75: eth0@if76: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:1b brd ff:ff:ff:ff:ff:ff
inet 172.17.0.27/16 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:1b/64 scope link
valid_lft forever preferred_lft forever
以上操作相当于运行ip netns exec <some_namespace> ip addr show
。
您可以在这里看到,您需要以root权限运行nsenter
。
与@jary的回答相似但不同。
不需要介绍/proc/<pid>/
或netster
。只需下面一个动作就能达到你的目的。因此,您可以操作容器的网络名称空间,就像在主机上手动创建一样。
One Move:
ln -s /var/run/docker/netns /var/run/netns
结果:启动容器:
docker run -tid ubuntu:18.04
列表容器:
root@Light-G:/var/run# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
972909a27ea1 ubuntu:18.04 "/bin/bash" 19 seconds ago Up 18 seconds peaceful_easley
列出该容器的网络命名空间:
root@Light-G:/var/run# ip netns list
733443afef58 (id: 0)
删除容器:
root@Light-G:/var/run# docker rm -f 972909a27ea1
972909a27ea1
再次列出网络命名空间:
root@Light-G:/var/run# ip netns list
root@Light-G:/var/run#
注意:这似乎比符号链接的做法更安全,但仍可能导致严重的安全问题。
在我看来,我们可能违反了容器应该是一个被包含的环境。
这是因为docker没有创建所需的符号链接:
# (as root)
pid=$(docker inspect -f '{{.State.Pid}}' "${container_id}")
mkdir -p /var/run/netns/
touch /var/run/$container_id
mount -o ro,bind "/proc/$pid/ns/net" "/var/run/netns/$container_id"
然后,可以使用ip netns "${container_id}"
检查容器的netns命名空间,例如:
# e.g. show stats about eth0 inside the container
ip netns exec "${container_id}" ip -s link show eth0
谢谢@TheDiveO通知我