测试环境
使用树莓派作为多网卡主机,其具备两张网卡,eth0和wlan0。另外需要一台PC用于测试与树莓派上容器的通信。将两台设备接入同一WiFi,然后再将两设备用网线直连。这样两设备即可以通过WiFi通信,也可以通过网线通信。
WiFi网段为192.168.31.0/24,树莓派IP为192.168.31.154,PC的IP为192.168.31.69。
网线连接的局域网网段为169.254.0.0/16,树莓派IP为169.254.140.68,PC的IP为169.254.140.66。
在树莓派上部署容器(容器为PLC运行环境容器),并对容器做不同的docker网络配置,测试PC与容器的通信,包括PC上的PLC开发环境软件(IDE)是否能接入容器,以及从容器内部是否能ping通PC。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # 树莓派网卡信息 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 link/ether dc:a6:32:de:1f:25 brd ff:ff:ff:ff:ff:ff inet 169.254.140.68/16 brd 169.254.255.255 scope global noprefixroute eth0 valid_lft forever preferred_lft forever inet6 fe80::9b39:2105:8832:4cf6/64 scope link valid_lft forever preferred_lft forever 3: wlan0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether dc:a6:32:de:1f:26 brd ff:ff:ff:ff:ff:ff inet 192.168.31.154/24 brd 192.168.31.255 scope global dynamic noprefixroute wlan0 valid_lft 36699sec preferred_lft 31299sec inet6 fd00:6868:6868::b91/128 scope global dynamic noprefixroute valid_lft 36696sec preferred_lft 36696sec inet6 fd00:6868:6868:0:77e8:ee3:7b24:7a36/64 scope global mngtmpaddr noprefixroute valid_lft forever preferred_lft forever inet6 fe80::215f:7f6a:a210:4d05/64 scope link valid_lft forever preferred_lft forever
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| # PC网卡信息 以太网适配器 以太网 2: 连接特定的 DNS 后缀 . . . . . . . : 本地链接 IPv6 地址. . . . . . . . : fe80::62de:7603:51d9:79cc%17 IPv4 地址 . . . . . . . . . . . . : 169.254.140.66 子网掩码 . . . . . . . . . . . . : 255.255.0.0 默认网关. . . . . . . . . . . . . : 无线局域网适配器 WLAN: 连接特定的 DNS 后缀 . . . . . . . : IPv6 地址 . . . . . . . . . . . . : fd00:6868:6868::69 IPv6 地址 . . . . . . . . . . . . : fd00:6868:6868:0:dbe:a764:e44b:ccec 临时 IPv6 地址. . . . . . . . . . : fd00:6868:6868:0:314c:b64b:89c7:1ef7 本地链接 IPv6 地址. . . . . . . . : fe80::b5c6:65b9:81b9:948f%16 IPv4 地址 . . . . . . . . . . . . : 192.168.31.69 子网掩码 . . . . . . . . . . . . : 255.255.255.0 默认网关. . . . . . . . . . . . . : fe80::cabf:4cff:fe4b:76d7%16 192.168.31.1
|
入向网络配置
入向:网络内其他设备访问主机上部署的容器
host模式
使用host网络模式创建容器,容器直接使用主机的网络配置。
1
| docker run -it --net=host 0375866a09cd
|
所以PC上的IDE以树莓派的两个IP(169.254.140.68、192.168.31.154)作为目的地址都可以接入RTE。
bridge模式(不绑定网卡)
使用bridge网络模式创建容器,会将容器接入docker0虚拟网桥下,网桥网段一般为172.17.0.0/16。这种模式下,主机所在网段内的其他设备无法直接访问主机上的容器,需要在容器与主机间做端口映射。
1
| docker run -it --net=bridge -p 3000:3000 0375866a09cd
|
因为没有绑定网卡,只设置了端口映射,所以IDE以树莓派两个IP(169.254.140.68、192.168.31.154)作为目的地址都可以接入RTE。
bridge模式(绑定网卡)
bridge模式创建容器,可以在设置端口映射时指定网卡IP,这样网络内其他设备只能从指定的主机网卡IP访问到容器。
1
| docker run -it --net=bridge -p 192.168.31.154:3000:3000 0375866a09cd
|
使用上面命令创建容器后,PC上的IDE只有把树莓派IP 192.168.31.154作为目的地址,才能访问到RTE容器。
相应的,如果创建容器时设置容器绑定到169.254.140.68,那IDE只有把树莓派IP 169.254.140.68作为目的地址,才能访问到RTE容器。
出向网络配置
出向:主机上部署的容器访问网络内其他设备
host模式
在容器内ping主机所在的两个网段内的其他设备(如PC的两个网卡IP:192.168.31.69、169.254.140.66)都可以ping通。
bridge模式
使用bridege模式创建容器,可以使用自带的docker0网桥,但缺点是创建容器时不能指定IP。使用自己创建的docker网桥,可以解决这个问题。另外对于docker0以及所有新建的docker网桥,系统会自动添加一条路由规则,使网桥网段内的所有容器都可以访问到主机所在的所有网段。使用命令“iptables -t nat -nvL –line-numbers”查看路由规则。如下面POSTROUTING链中的第一条规则,docker0网段(172.17.0.0/16)下的容器可以访问主机所在的所有网段。
1 2 3
| Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
|
新创建一个名为docker1的docker网络后,重新查看发现多出一条规则。
1 2
| # 创建网络(此处新建的网络本质也是bridge模式) docker network create --dirver bridge --subnet 172.18.0.0/16 --opt "com.docker.network.bridge.name"="docker1" docker1
|
1 2 3 4
| Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 MASQUERADE all -- * !docker1 172.18.0.0/16 0.0.0.0/0 2 17 1234 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
|
然后创建容器,网络使用自己创建的docker1,但就像前面提到的,每个docker网络自动添加的路由规则,会使docker网络下的容器能访问到主机所在的所有网段。创建两个容器(rte1、rte2)测试一下。
1 2 3
| #创建容器,加入docker1 docker run -d --net docker1 -p 3001:3000 --name rte1 0375866a09cd docker run -d --net docker1 -p 3001:3000 --name rte2 0375866a09cd
|
创建容器后,查看规则,没有针对容器IP的出向规则,只有针对整个网段的。
1 2 3 4 5 6
| Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 MASQUERADE all -- * !docker1 172.18.0.0/16 0.0.0.0/0 2 17 1234 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 3 0 0 MASQUERADE tcp -- * * 172.18.0.2 172.18.0.2 tcp dpt:3000 4 0 0 MASQUERADE tcp -- * * 172.18.0.3 172.18.0.3 tcp dpt:3000
|
从两个容器内向192.168.31.0/24和169.254.0.0/16两个网段ping,发现都能ping通。
如果想让某个容器只能访问192.168.31.0/24网段,另一个容器只能访问169.254.0.0/16网段,可以手动添加路由规则。
再创建两个容器(rte3、rte4),在创建时指定两个容器的IP。
1 2 3
| #创建容器,加入docker1,指定IP docker run -d --net docker1 --ip 172.18.0.33 -p 3002:3000 --name rte3 0375866a09cd docker run -d --net docker1 --ip 172.18.0.44 -p 3004:3000 --name rte4 0375866a09cd
|
此时新建的两个容器(rte3、4)都在原本路由规则覆盖下,所以先删除docker1网络自动添加的路由规则。以规则序号为目标删除。
1 2
| # 删除POSTROUTING链下的序号1的规则 iptables -t nat -D POSTROUTING 1
|
重新查看路由规则,docker1的出向路由规则已被删除。在rte3、4内向两个网段ping,都ping不通。
1 2 3 4 5 6 7
| Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 17 1234 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 2 0 0 MASQUERADE tcp -- * * 172.18.0.2 172.18.0.2 tcp dpt:3000 3 0 0 MASQUERADE tcp -- * * 172.18.0.3 172.18.0.3 tcp dpt:3000 4 0 0 MASQUERADE tcp -- * * 172.18.0.33 172.18.0.33 tcp dpt:3000 5 0 0 MASQUERADE tcp -- * * 172.18.0.44 172.18.0.44 tcp dpt:3000
|
然后手动添加规则,完成目标需求。
1 2 3 4 5
| # 配置nat,容器rte3向外发送的数据包源IP转换成192.168.31.154 iptables -t nat -I POSTROUTING -p all -s 172.18.0.33 -j SNAT --to-source 192.168.31.154
# 配置nat,容器rte4向外发送的数据包源IP转换成169.254.140.66 iptables -t nat -I POSTROUTING -p all -s 172.18.0.44 -j SNAT --to-source 169.254.140.68
|
1 2 3 4 5 6 7 8 9
| Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) num pkts bytes target prot opt in out source destination 1 0 0 SNAT all -- * * 172.18.0.44 0.0.0.0/0 to:169.254.140.68 2 0 0 SNAT all -- * * 172.18.0.33 0.0.0.0/0 to:192.168.31.154 3 17 1234 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0 4 0 0 MASQUERADE tcp -- * * 172.18.0.2 172.18.0.2 tcp dpt:3000 5 0 0 MASQUERADE tcp -- * * 172.18.0.3 172.18.0.3 tcp dpt:3000 6 0 0 MASQUERADE tcp -- * * 172.18.0.33 172.18.0.33 tcp dpt:3000 7 0 0 MASQUERADE tcp -- * * 172.18.0.44 172.18.0.44 tcp dpt:3000
|
配置完成后,再次测试,发现在容器rte3中,ping 192.168.31.69能通,ping 169.254.140.66不通;在容器rte4中,ping 169.254.140.66能通,ping 192.168.31.69不通,和目标需求一致。
当然除了可以添加针对IP的规则,也可以添加针对网段的规则,比如:创建了两个docker网络(docker11、docker22),希望docker11下的容器只能访问网段192.168.31.0/24,docker22下的容器只能访问网段169.254.0.0/16。可以如下配置。
1 2 3 4 5 6 7
| # 创建docker网络 docker network create --dirver bridge --subnet 172.19.0.0/16 --opt "com.docker.network.bridge.name"="docker11" docker11 docker network create --dirver bridge --subnet 172.20.0.0/16 --opt "com.docker.network.bridge.name"="docker22" docker22
# 配置nat iptables -t nat -I POSTROUTING -p all -s 172.19.0.0/16 -j SNAT --to-source 192.168.31.154 iptables -t nat -I POSTROUTING -p all -s 172.20.0.0/16 -j SNAT --to-source 169.254.140.68
|
总结
- 入向(网络内其他设备到主机上的容器):创建容器时通过参数(-p)绑定某一网卡后,网络内其他设备只能通过容器绑定的网卡IP访问容器
- 出向(主机上的容器到网络内其他设备):配置nat,将容器IP转换为网卡IP,从而使容器能够访问网卡IP所在网段内的其他设备