1、容器网络
linux容器能看见的网络栈,实际上被隔离在它自己的network namespace中。网络栈包含了网卡、回环设备、路由表和iptables规则。
作为一个容器,可以声明直接使用宿主机的网络栈。即:但是,在大多数情况下,我们希望容器进程使用自己network namespace的网络栈。拥有自己的Ip地址和端口
那么,这个被隔离的容器进程,如何和其他的network namespace里的容器进程进行交互呢?
2、docker容器通信的原理
linux中,能够起到虚拟交换机作用的网络设备,是网桥。根据mac地址学习来将数据包转发到网桥的不同端口
docker项目会默认在宿主机上创建一个名为docker0的网桥,凡是连接docker0网桥上的容器,都可以通过它来进行通信。那么如何把容器连接到docker0网桥上呢?
使用到了一个名为veth pair的虚拟设备:这个设备被创建出来后,总是以两张虚拟网卡veth peer的形式成对出现的,而且其中一个网卡发出的数据包,可以直接出现在它对于的另一张网卡上。哪怕这两个网卡在不同netwok namespace的网线。
看一下例子:
假如有一个nginx容器,查看网络设备:容器里面有一个eth0的网卡,它就是一个veth pair设备在容器里的这一端,而使用route查看容器的路由表,eth0网卡是这个容器的默认路由设备,意味着所有172.17.0.0/16网段的请求,也会被交给eth0来处理。
接下来看宿主机上的信息,如下所示:下面就是一个vethxxx的虚拟网卡,然后通过brctl show,可以看到这张网卡被插到了docker0上。
那么此时如果到宿主机上启动另一个nginx的容器,然后再查看,就会发现名为vethb4xxx的虚拟网卡也插到了docker0网桥上。
然后此时在第一个容器里面,ping第二个容器的ip地址,发现是通的。
原理:
1、当在nginx1容器里面访问nginx2容器的ip地址的时候,这个目的ip地址会匹配上nginx1容器里面的第二条路由规则,因为172.17.0.0表示的是172.17.0.1-172.17.0.255这个范围的所有地址哈!!而这条路由规则的网关是0.0.0.0,意味着这是一条直连规则,即:凡是匹配到这条规则的ip包,应该经过本机的eth0网卡,通过二层网络直接发往目的主机。(假如nginx2的Ip地址是172.17.0.3)
2、此时就需要拿到172.17.0.3这个ip地址对应的mac地址,所以nginx1容器通过eth0网卡发送一个arp广播,来通过ip地址找到对应的mac地址,而eth0网卡是一个veth pair,它的一段是nginx1容器的network namespace,另一端在宿主机,并且被插到了宿主机的docker0网桥上,一旦一张虚拟网卡被插到网桥上,就变成了该网桥的从设备,用来接收流入的数据包,然后转发给网桥。
3、此时nginx1容器发出的数据会被转发到docker0网桥,然后又广播转发到所有插到docker0上的虚拟网卡上,这样同样连接在docker0的nginx2容器的网络协议栈就能接收到这个arp请求,然后返回这个容器的mac地址了。
4、有了mac地址以后,Nginx1容器就可以发送数据了。
通信的流程图如下所示:
回顾:
1、宿主机上的docker0是网桥,凡是连接在docker0网桥上的容器,都可以通过它来进行通信
2、然后Veth Pair的作用:能以两张虚拟网卡的形式在不同的network namespace中出现。如下所示,nginx1容器里的veth pair一段就是172.17.0.2,而另一端是宿主机上的veth9c02e56,这意味着容器可以和宿主机虚拟网卡通信
3、而veth pair的虚拟网卡是插在宿主机上的docker0网桥上的,且两个容器的veth pair的虚拟网卡的另一端是插入到了docker0网桥上,相当于两个容器之间就联通了,所以就可以通信了
总而言之,在默认情况下,被限制在network namespace里的容器进程,实际上是通过veth pair设备+宿主机网桥的方式,实现了跟其他容器的数据交换。!!!厉害吖!
而当你在一台宿主机上,访问该宿主机上的容器的Ip地址是,也是先到底docker0网桥,然后转到对应的veth pair设备,如下所示
当一个容器视图连接到另外一个宿主机,如下所示:
所以,当你遇到容器联不通外网的时候,都应该先试试docker0网桥能不能Ping通,然后查看一下跟docker0和veth pair设备相关的iptables规则是不是有异常。!!!
那如果另外一台宿主机上,也有一个docker容器,那么nginx01要如何访问呢?这就是跨主通信问题。
在docker的默认配置下,一台宿主机的docker0网桥和另一台宿主机上的网桥自然不同联通,那要怎么办呢?
可以通过软件的方式,创建一个集群公用的网桥。然后把集群里面所有的容器都连接到这个网桥上。!!!厉害
架构图如下所示:
在已有的宿主机网络上,再通过软件构建一个覆盖在已有宿主机网络之上的,可以把所有容器联通在一起的虚拟网络,就成为覆盖网络。
当 Node 1 上的 Container 1 要访问 Node 2 上的 Container 3 的时候,Node 1 上
的“特殊网桥”在收到数据包之后,能够通过某种方式,把数据包发送到正确的宿主机,比
如 Node 2 上。而 Node 2 上的“特殊网桥”在收到数据包后,也能够通过某种方式,把
数据包转发给正确的容器,比如 Container 3。
3、容器跨主机网络
例子:
5、k8s的CNI网络插件
6、k8s的三层网络方案