首先运行一个基于busybox镜像的busybox容器,名字为test1:
docker run -d --name test1 hub.c.163.com/library/busybox:latest /bin/sh -c "while true;do sleep 3600;done"
启动容器后进入容器:
docker exec -it aec1c356e72c /bin/sh
我们在容器中首先输入命令ip a
来查看当前容器的网络接口:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
58: eth0@if59: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
第一个网络接口为本地的Lookback,即回还口。当我们创建一个容器时,也会相应创建一个网络namespace。我们退出容器后,在本地宿主机上执行 ip a
命令时,打印如下:
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
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 52:54:00:5f:94:78 brd ff:ff:ff:ff:ff:ff
inet 10.0.2.15/24 brd 10.0.2.255 scope global noprefixroute dynamic eth0
valid_lft 57642sec preferred_lft 57642sec
inet6 fe80::5054:ff:fe5f:9478/64 scope link
valid_lft forever preferred_lft forever
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:08:96:2b:f9 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:8ff:fe96:2bf9/64 scope link
valid_lft forever preferred_lft forever
59: vetha65affd@if58: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
link/ether 5a:31:ef:f0:fb:64 brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::5831:efff:fef0:fb64/64 scope link
valid_lft forever preferred_lft forever
由此可见主机的网络接口信息和容器的网络接口信息不同,这是由于宿主机也有自己的网络命名空间,和容器的网络命名空间相互隔离。
当我们再启动另外一个容器,并执行docker exec -it hub.c.163.com/library/busybox:latest ip a
来查看网络的接口信息如下:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 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
60: eth0@if61: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
由此发现,创建的这两个容器的网络是相通的,因为172.17.0.2和172.17.0.3位于同一网段,所以可以ping通。
接下来来了解下两个容器能够网络相通的原理。
原理
sudo ip netns list
命令:在宿主机上可以通过来查看当前已有的network namespace。
sudo ip netns delete test1
命令:删除名称为test1的network namespace。
sudo ip netns add test1
命令:新增名为test1的network namespace。
了解上面几个命令后,我们新增test1和test2两个network namespace,并执行命令:
sudo ip netns exec test1 ip a
来查看test1这个network namespace,如下:
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
由上可知test1这个network namespace的lo回还口的状态为Down。再介绍一个命名:
ip link
,它也可以查看network namespace信息,另外可以使用这个 命令将状态为down的网络接口启动起来,使之状态为up。为此我们想将test1这个network namespace的lo端口up起来:
sudo ip netns exec test1 ip link set dev lo up
然后使用sudo ip netns exec test1 ip link
来查看test1的网络接口信息,如下:
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
状态并没有从down变成up,而是变成了unknown状态。这是因为在Linux里面端口是成对出现才会变成up状态。
下面我们来了解下两个命名空间之间通信的原理:
image.png
由上图可知,两个命名空间内部都有一个通信的接口,中间通过类似于网线的Veth pair进行通信,下面我们通过命令来模拟这个实现的过程:
首先我们执行命令如下:
sudo ip link add veth-test1 type veth peer name veth-test2
通过这个命令,我们创建了两个网络端口veth-test1和veth-test2,查看结果:
[vagrant@localhost ~]$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 52:54:00:5f:94:78 brd ff:ff:ff:ff:ff:ff
3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:08:96:2b:f9 brd ff:ff:ff:ff:ff:ff
59: vetha65affd@if58: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 5a:31:ef:f0:fb:64 brd ff:ff:ff:ff:ff:ff link-netnsid 1
61: veth7dcab2c@if60: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default
link/ether 32:87:13:6c:b5:39 brd ff:ff:ff:ff:ff:ff link-netnsid 0
62: veth-test2@veth-test1: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether da:3f:b3:ab:f7:0b brd ff:ff:ff:ff:ff:ff
63: veth-test1@veth-test2: <BROADCAST,MULTICAST,M-DOWN> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether e2:5a:43:9f:c0:a8 brd ff:ff:ff:ff:ff:ff
可以看到现在在最下面多了两个网络端口。
接着我们将创建的这两个网络端口分别添加到两个命名空间中:
sudo ip link set veto-test1 netns test1
sudo ip link set veto-test2 netns test2
添加完后查看命名空间test1和test2的网络接口信息:
[vagrant@localhost ~]$ sudo ip netns exec test1 ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
63: veth-test1@if62: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether e2:5a:43:9f:c0:a8 brd ff:ff:ff:ff:ff:ff link-netnsid 1
[vagrant@localhost ~]$ sudo ip netns exec test2 ip link
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
62: veth-test2@if63: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
link/ether da:3f:b3:ab:f7:0b brd ff:ff:ff:ff:ff:ff link-netnsid 0
可以看出,两个命名空间中已经多了网络端口veth-test1和veth-test2。
但是这两个网络端口状态都是down,并且没有IP地址,为此下面我们给这两个网络端口分配IP地址:
sudo ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1
sudo ip netns exec test2 ip addr add 192.168.1.2/24 dev veth-test2
然后我们将这两个网络端口都up起来:
sudo ip netns exec test1 ip link set dev veth-test1 up
sudo ip netns exec test2 ip link set dev veth-test2 up
由于192.168.1.1和192.168.1.2这两个地址位于同一网段,为此两个命名空间之间就可以互相ping通了:
[vagrant@localhost ~]$ sudo ip netns exec test1 ping 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.062 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.052 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.070 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.058 ms
^C
--- 192.168.1.2 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3007ms
rtt min/avg/max/mdev = 0.052/0.060/0.070/0.010 ms
这就是两个容器也能ping通的原理。
网友评论