我们自定义两个容器网络,network1和network2,如何实现两个网络中容器通信呢?
自定义两个网络network1 (172.19.1.0/24)和network2(172.19.2.0/24)
[root@localhost ~]# docker network create network1 --subnet 172.19.1.0/24
ec6f94effcea558ade7634b90ce9b015952827e968007a660993ba7d86b7cdf4
[root@localhost ~]# docker network create network2 --subnet 172.19.2.0/24
9feb392b7cd01d43ff47fb96e1549aeda7c5a590214585ec8e6c6179e3434bc8
[root@localhost ~]# docker network list
NETWORK ID NAME DRIVER SCOPE
96acf619479a bridge bridge local
b4a586d8b755 host host local
ec6f94effcea network1 bridge local
9feb392b7cd0 network2 bridge local
d66905d1ffee none null local
在两个网络中,分别生成两个容器
[root@localhost ~]# docker run -itd --network network1 --name box1-1 busybox
[root@localhost ~]# docker run -itd --network network1 --name box1-2 busybox
[root@localhost ~]# docker run -itd --network network2 --name box2-1 busybox
[root@localhost ~]# docker run -itd --network network2 --name box2-2 busybox
相同网络中容器能正常通信,不在一个网络中容器,无法通信。如何实现他们能通信呢?
方法一:把容器加入另一个网络中
问题转换下,正常情况下,不在一个网络中物理机如何通信呢?如何物理条件允许,我们可以把一个物理机加入到另一个物理机的网络中,这样就能实现两个物理机通信,前提是物理可达,以及物理机有多个网卡,对应到容器中,我们可以把容器加入到另一个网络中,这样也能实现容器和其他网络中容器通信,
#把box1-1加入到network2中
[root@localhost ~]# docker network connect network2 box1-1
#进入box1-1中查看网络设备
[root@localhost ~]# docker exec -it box1-1 sh
/ # ip addr
1: lo: 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
17: eth0@if18: mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:01:02 brd ff:ff:ff:ff:ff:ff
inet 172.19.1.2/24 brd 172.19.1.255 scope global eth0
valid_lft forever preferred_lft forever
25: eth1@if26: mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:02:04 brd ff:ff:ff:ff:ff:ff
inet 172.19.2.4/24 brd 172.19.2.255 scope global eth1
valid_lft forever preferred_lft forever
#验证
/ # ping -c 2 172.19.2.3
PING 172.19.2.3 (172.19.2.3): 56 data bytes
64 bytes from 172.19.2.3: seq=0 ttl=64 time=0.851 ms
64 bytes from 172.19.2.3: seq=1 ttl=64 time=0.104 ms
--- 172.19.2.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.104/0.477/0.851 ms
/ # ping -c 2 172.19.1.3
PING 172.19.1.3 (172.19.1.3): 56 data bytes
64 bytes from 172.19.1.3: seq=0 ttl=64 time=0.935 ms
64 bytes from 172.19.1.3: seq=1 ttl=64 time=0.087 ms
--- 172.19.1.3 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.087/0.511/0.935 ms
进入容器中,我们看到就是在box1-1中加入了新的veth-pair设备。从之前的文章中,我们可以分析到其实就是把veth-pair的一端放入到box-1-1的命名空间中,一端依附到要加入的网络的网桥中。同时给放入netns中的一端中加入网络地址。
接下来,我们通过手动方式给box1-2添加到network2中,首先恢复下docker隐藏的box1-2的netns:
#获取容器box1-2的进程号
[root@localhost ~]# docker inspect box1-2 |grep Pid
"Pid": 7629,
#将进程网络命名空间恢复到主机目录(没有 /var/run/netns先创建)
ln -s /proc/容器进程号/ns/net /var/run/netns/容器
[root@localhost ~]# ln -s /proc/7629/ns/net /var/run/netns/box1-2
#查看恢复的netns
[root@localhost ~]# ip netns list
box1-2 (id: 2)
增加veth-pair并配置网络
#增加veth-pari对设备
ip link add veth_b_1_2 type veth name peer veth_b_1_2_peer
#把一端放入box1-2的netns中
ip link set veth_b_1_2 ns box1-2
#配置IP地址
ip netns exec box1-2 ip addr add 172.17.2.5/24 dev veth_b_1_2
ip netns exec box1-2 ip link set veth_b_1_2 up
#把一端依附到对应的网桥上
#查看网络对应的网桥
ip addr
#忽略其它的
.......
8: br-9feb392b7cd0: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:0c:c1:a6:7a brd ff:ff:ff:ff:ff:ff
inet 172.19.2.1/24 brd 172.19.2.255 scope global br-9feb392b7cd0
valid_lft forever preferred_lft forever
inet6 fe80::42:cff:fec1:a67a/64 scope link
valid_lft forever preferred_lft forever
.....
ip link set dev veth_b_1_2_peer master br-9feb392b7cd0
ip link set veth_b_1_2_peer up
验证
[root@localhost ~]# ip netns exec box1-2 ping -c 2 172.19.2.2
PING 172.19.2.2 (172.19.2.2) 56(84) bytes of data.
64 bytes from 172.19.2.2: icmp_seq=1 ttl=64 time=0.233 ms
64 bytes from 172.19.2.2: icmp_seq=2 ttl=64 time=0.064 ms
--- 172.19.2.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.064/0.148/0.233/0.085 ms
[root@localhost ~]# docker exec -it box1-2 sh
/ # ip addr
1: lo: 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
19: eth0@if20: mtu 1500 qdisc noqueue
link/ether 02:42:ac:13:01:03 brd ff:ff:ff:ff:ff:ff
inet 172.19.1.3/24 brd 172.19.1.255 scope global eth0
valid_lft forever preferred_lft forever
28: veth_b_1_2@if27: mtu 1500 qdisc noqueue qlen 1000
link/ether 9e:7b:c9:91:7f:b2 brd ff:ff:ff:ff:ff:ff
inet 172.19.2.5/24 scope global veth_b_1_2
valid_lft forever preferred_lft forever
方法二:把需要通信的容器加入到第三方网络中
如果两个容器想要通信,就把两个容器加入第三方网络中,这样两个容器就能通信了,具体思路就是创建第三网络,使用docker connect 命令把两个需要通信的容器加入到这个网络中,实现通信,如果不想让两个容器通信了,就通过docker disconnect删除。底层的原理和上面的方法类似就不展开分析了。
方法三:修改底层的iptables规则实现两个网络通信
方法一和方法二都是通过把容器加入到网络中,想办法把想要通信的容器加入到一个网络中。从《容器网络原理分析一》种可以得到,正常情况下,创建好ns配置好网络以及路由,同一个宿主机中的不同的bridge之间是可以通信的。为什么容器的两个网络之间是无法通信呢?《容器网络原理分析基础篇》中得知是iptables规则给阻拦了。
1.首先找到网络的桥接接口名称
[root@localhost ~]# ip addr
........
7: br-ec6f94effcea: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:be:93:94:2f brd ff:ff:ff:ff:ff:ff
inet 172.19.1.1/24 brd 172.19.1.255 scope global br-ec6f94effcea
valid_lft forever preferred_lft forever
inet6 fe80::42:beff:fe93:942f/64 scope link
valid_lft forever preferred_lft forever
8: br-9feb392b7cd0: mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:0c:c1:a6:7a brd ff:ff:ff:ff:ff:ff
inet 172.19.2.1/24 brd 172.19.2.255 scope global br-9feb392b7cd0
valid_lft forever preferred_lft forever
inet6 fe80::42:cff:fec1:a67a/64 scope link
valid_lft forever preferred_lft forever
........
2.修改iptables规则实现两个子网通信
[root@localhost ~]# iptables -I DOCKER-USER -i br-ec6f94effcea -o br-9feb392b7cd0 -j ACCEPT
[root@localhost ~]# iptables -I DOCKER-USER -i br-9feb392b7cd0 -o br-ec6f94effcea -j ACCEPT