同一主机下两个容器间进行通信(二)2021.07

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了同一主机下两个容器间进行通信(二)2021.07相关的知识,希望对你有一定的参考价值。

参考技术A docker run -itd --net=none --privileged=true --name=test1 ubu /bin/bash

docker run -itd --net=none --privileged=true --name=test2 ubu /bin/bash

其中ubu为装了网络命令的Ubuntu系统

网络设置为无网络

必须特殊root权限否则修改不了网络设置

pid1=$(docker inspect -f .State.Pid test1)



pid1=`docker inspect -f .State.Pid test1`

ln -s /proc/$pid1/ns/net /var/run/netns/test1

ip link add tap1 type veth peer name tapb1

ip link add tap2 type veth peer name tapb2

ip link add name br0 type bridge

ip link set tapb1 master br0

ip link set tapb2 master br0

ip link set tap1 netns test1

ip link set tap2 netns test2

ip link set br0 up

ip link set tapb1  up

ip link set tapb2  up

ip netns exec test1 ip link set tap1 up

ip netns exec test2 ip link set tap2 up

ip netns exec test1 ip addr add 10.0.0.1/24 dev tap1

ip netns exec test2 ip addr add 10.0.0.2/24 dev tap2

ip addr add 10.0.0.3/24 dev br0(网桥分不分配ip地址与容器通信无关,但分配地址后主机可以直接访问容器ip,主机的路由表也会增加网桥一项)

ip netns exec test1 ping 10.0.0.2

ip netns exec test2 ping 10.0.0.1

这里的实际建立过程中可能会出现ping不通的情况,可以使用以下命令排查:

tcpdump -i tap1 -nne查看网络流量(-nn可以直接显示ip地址而非端口名和网络名 -e 在输出行打印出数据链路层的头部信息 -i 指定监听的网络接口)

route -v 查看路由表

iptables-save查看防火墙规则

我遇到的是容器流量可以到网桥,但是不能到另一个容器,实际上是我的主机防火墙的FORWORD规则中默认策略(policy)为DROP,而网桥又何主机共享网络名字空间,导致流量在网桥上被丢弃了

使用命令修改即可:

iptables -P FORWRAD ACCEPT

事实上,使用OVS来实现则不会出现这种问题

由于容器1相连的网桥是使用的主机NetworkNamesapce,所以让流量直接走网桥和主机即可,要做的就是设置网络访问规则:

(1)首先使test1的流量默认从网桥出去

ip netns exec test1 ip route add default via 10.0.0.3(容器访问主机)

(2)防火墙设置FILTER表的规则(iptables -nL)

从网桥br0进而不从br0出的流量放行

iptables -A FORWARD -i br0 ! -o br0 -j ACCEPT

允许回包,响应会原路返回,主机对外接口ens3拿到响应后,会经过prerouting链,因为响应的目标地址不是主机(是test1),所以走FORWARD链转给br0,conntrack是状态跟踪

iptables -A FORWARD -o br0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

(3)防火墙设置NAT表的规则(iptables -t nat -nL)

把所有来自10.0.0.0/24网段的请求(且出口不是br0的)请求进行转发(! -o br0可以省略)

iptables -t nat -A POSTROUTING -s 10.0.0.0/24 ! -o br0 -j MASQUERADE

MASQUERADE是地址伪装,算是SNAT中的一种特例,可以实现自动化的SNAT,也可以手动指定snat的地址:

iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -j SNAT --to 10.10.4.253

参考源:https://www.jianshu.com/p/bf0805821f46

OpenvSwitch实现多主机间通信

参考技术A 单个主机上容器之间如果要实现网络互通比较容易实现,一种常见做法是把需要通信的容器网络接口桥接到相同的主机网络接口,这样容器就处在相同的广播域,它们的网络地址是由Docker来负责分配管理,所以会获得同一网段的IP地址,网络互通所需的条件全部满足。
当容器处在不同的主机,情况就大不相同,因为主机的网络环境隔离了容器的网络环境,此时要实现网络互通,就需要做更多的工作。本文依赖OpenvSwitch实现多主机容器间网络通信。
1,使用GRE接口
实验拓扑如下:

用比较通俗的说法解释上图,Host 1上的Container 1连接交换机docker0,docker0连接路由器ovs-br,Host 2上的Container2同理。然后两台路由器ovs-br通过GRE隧道相连。用隧道的原因是容器间的流量必须承载在Host 1和Host 2的网络之上。
配置Host 1:

配置Host 2(为了避免和Host 1上Container 1上的IP地址冲突,可以启动两个容器,将第二个启动的容器作为Container2)

配置完毕后,进入Container 1,ping测试Container 2发现是可以ping通的。
2,使用VxLAN接口
拓扑如下

这次直接把docker自带的网桥docker0去掉,因为它本不是必需的。

Host 2上的配置类似,ovs-br的IP地址设置为192.168.8.4,容器内eth0的IP地址配置为192.168.8.3
配置完毕后,在Host 1的容器里面 ping测试Host 2上的容器,发现是通的。ping测试的同时,在Host 2的网卡eth0抓下包,可以看到VxLAN的身影,如下图所示:

以上是关于同一主机下两个容器间进行通信(二)2021.07的主要内容,如果未能解决你的问题,请参考以下文章

docker网络-2

UNIX Domain Socket(UDS)是什么?同一台主机间进程间通信

OpenvSwitch实现多主机间通信

wwwhy76888com理解容器间link通信机制199O8836661

【swarm】Docker跨主机网络:overlay

docker笔记:docker容器通信参数 --link参数介绍