这次使用桥接方式

1.新建两个无网络容器:
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权限否则修改不了网络设置
2.查看容器的网络空间号,并在ip命令netns下建立软连接
pid1=$(docker inspect -f {{.State.Pid}} test1)
或
pid1=`docker inspect -f {{.State.Pid}} test1`
ln -s /proc/$pid1/ns/net /var/run/netns/test1
3.新建两对veth-pair和一个linux网桥
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
4.连接容器和网桥
ip link set tapb1 master br0
ip link set tapb2 master br0
ip link set tap1 netns test1
ip link set tap2 netns test2
5.激活设备和分配ip地址
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,主机的路由表也会增加网桥一项)
6.使用ping命令验证容器是否相通
ip netns exec test1 ping 10.0.0.2
ip netns exec test2 ping 10.0.0.1
7.网络故障排查
这里的实际建立过程中可能会出现ping不通的情况,可以使用以下命令排查:
tcpdump -i tap1 -nne查看网络流量(-nn可以直接显示ip地址而非端口名和网络名 -e 在输出行打印出数据链路层的头部信息 -i 指定监听的网络接口)
route -v 查看路由表
iptables-save查看防火墙规则
我遇到的是容器流量可以到网桥,但是不能到另一个容器,实际上是我的主机防火墙的FORWORD规则中默认策略(policy)为DROP,而网桥又何主机共享网络名字空间,导致流量在网桥上被丢弃了
使用命令修改即可:
iptables -P FORWRAD ACCEPT
事实上,使用OVS来实现则不会出现这种问题
8.容器访问外界
由于容器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