在同一台主机docker里面去创建多个容器,让不同的容器能够互相通信,并且容器能够访问外网
主机上有一个网卡,这个网卡是叫网桥的网络设备,在网桥上可以连接多个其他的网络设备
bridge-0网桥连接了2个veth的网络设备,一端连接到了red的网络命名空间的veth-red设备,一端连接到了blue网络命名空间的veth-blue网络设备。
一个网络命名空间就类似于在docker容器里面启动了一个容器。这两个网络命名空间通过veth设备将网络包传递给网桥,然后网桥再根据他们的目的地址选择是否在主机上面进行网卡之间网络包的转发。
创建两个网络命名空间
ip netns add red
ip netns add blue
ip netns
前置条件
# 允许防火墙,路由转发
iptables -A FORWARD -j ACCEPT
# 内核允许路由转发,修改值为1
vim /proc/sys/net/ipv4/ip_forward
创建两个veth设备
# 创建veth-red网络设备
ip link add veth-red type veth peer name veth-red-br
# 创建veth-blue网络设备
ip link add veth-blue type veth peer name veth-blue-br
创建一个网桥
brctl addbr br0
brctl show
将网络设备放入网络命名空间
# 把veth-red网络设备放到red的网络命名空间当中
ip link set veth-red netns red
# 把veth-blue网络设备放到blue的网络命名空间当中
ip link set veth-blue netns blue
将网络设备链接到网桥上
# 将主机上面的veth-red-br这一头链接到网桥上
ip link set veth-red-br master br0
# 将主机上面的veth-bule-br这一头链接到网桥上
ip link set veth-blue-br master br0
启动网络设备
ip link set br0 up
ip link set veth-red-br up
ip link set veth-blue-br up
ip netns exec red ip link set veth-red up
ip netns exec blue ip link set veth-blue up
把创建的这些网络设备全部都变成一个up的状态
再给这些网络设备赋予ip号
网桥作为veth设备的一个默认网关,网段是192.168.15前面的24位。
首先给veth-red赋值一个ip,再给veth-blue赋值一个ip
ip netns exec red ip addr add 192.168.15.1/24 dev veth-red
ip netns exec blue ip addr add 192.168.15.2/24 dev veth-blue
用red的网络命名空间内的这个veth-red这个ip去ping下veth-blue这张网卡,是否可以ping通?
(此时网桥还没有给它赋值ip地址)
ip netns exec red ping 192.168.15.2
是可以ping通的。
如果ping不通的话,从以下几个方面定位原因
ip netns exec red route -n
路由是能够到达的
ip netns exec blue ip add
red和blue两个网络命名空间中的网卡都是up状态
经过它上面是有ping包请求发出的
网络包在发到网桥的时候,网桥这时是没有一个ip的,知道了这个网络包的下一跳的mac地址,它会转发到veth-blue这个网卡上面,就ping通了
能不能ping一个外网或者ping主机上面的网络?
显然是不能的,因为我的网桥它是没有ip地址的,arp包达到这个网桥上,它只会去寻找网桥链接设备的一个端口,根本没有和主机相连,那如何去和主机通信呢?
比如ping red网络命名空间里面的一个网卡
ping 192.168.15.1
这是ping不通的,因为主机上面没有到达这个网卡的路由,
即使有了这个网卡的路由,要从哪个网卡进去呢?这时候就得为这个网桥赋值一个ip地址,
给网桥设置ip地址
ip addr add 192.168.15.5/24 dev br0
此时就会发现多了一个路由,那访问这个网段就会从这个网桥(网卡)进去,进去之后呢,是不是能够从特定的端口去广播arp协议?首先发网络包之前,先去广播arp协议,然后它发现了在red网络命名空间内的网卡,
这时就可以ping通了。
主机上面通过网桥,搭建一个网络设备之后,给它赋上一个ip,能够让我的主机和我本地上面的容器通过网桥这个网卡互相通信。因为网桥是可以广播arp包的,广播之后呢,它可以获取到它的目的ip所要寻找的mac地址,然后mac地址在通过veth设备传回网桥,此时相当于容器之间的通信已经能够打通。
容器能不能访问外网呢?
在red网络命名空间当中去访问一下8.8.8.8这个谷歌域名地址
ip netns exec red ping 8.8.8.8
网络不可达,因为在red的网络命名空间中,没有一个默认路由。
ip netns exec red route -n
没有匹配到网络段的话,那它就会直接反馈这个错误,给它加上一个默认的路由,它的下一跳地址是网桥这里。
ip netns exec red ip route add default via 192.168.15.5 dev veth-red
现在就有一个默认网关了,此时再ping还是ping不通
失败原因有两个:
(对面上面的2个前置操作)
此时还是不通,抓包看下,首先抓下br0这个网卡上的
tcpdump -i br0
发现这个包在这个网卡上是有icmp协议的request请求出去,那这个请求有没有通过我的主机上面的一个物理网卡出去呢?因为我开启了ip forward之后,它会根据到达网卡的网络包的目的地址看一下主机上面有没有其他网卡也是属于这个目的ip一个网段,如果有的话,它会把这个网卡包转发到另一个网卡。
抓一下ens33这个网卡的网络包
tcpdump -i ens33 host 8.8.8.8 -n
可以发现从这个网卡里也有出去的包。
为什么这个网络IP只有出去的,却没有得到它的回复?你可以看到它的原地址是192.168.15.1,这个是内网ip,在网络传输过程当中呢,它的一个原ip是这个ip,那到时候回来的时候,在公网访问去路由这个ip的时候,肯定是回不来的,因为这个ip仅仅是我们主机上的一个内网ip。
这时候有一个机制叫做snat,它能够让我们的网络包从网卡出去的时候,能够把它的原ip映射成出去的一个物理网卡的一个ip,然后等着包回来,能够把这个包的一个目的ip,也就是物理网卡的那个ip又给转换成出去之前映射的那个局域网ip。
iptables -t nat -A POSTROUTING -s 192.168.15.0/24 -j MASQUERADE
通过防火墙去设置nat的规则,把192.168.15.0这个网段要出去的网络包,通过这个nat规则,代表从哪个网卡出去就把它的这个原地址给替换成要出去的那个物理网卡的地址。
此时再ping就可以发现网络包已经能够正常回来了
这里说了容器如何访问公网,通过snat的机制。那公网如何访问我们的容器呢?对应也有一个dnat的机制,它能够把目的ip给映射成局域网ip,在主机上面开一个端口,然后将目的ip:端口号,映射成局域网的ip:端口号,这样就能够完成公网去访问容器的操作。
| 留言与评论(共有 0 条评论) “” |