介绍
docker大概有4种网络模式:
- host: 公用一个network namespace,使用宿主机的ip和端口
- container: 和已经存在的一个容器共享network namespace
- none: 独立的network namespace,需要手动添加网络配置
- bridge: 默认配置,为容器自动分配namespace,设置IP,并将容器连接到一个虚拟网络
Docker宿主机上可以同时存在多个不同类型的网络。位于不同网络中的容器,彼此之间无法通信。Docker容器的跨网络隔离与通信,是借助了iptables的机制
原理解析
iptables是Linux内核的一个模块,用以管理对网络设备(网卡)的访问,如路由过滤、端口转发、NAT, 用户可以通过配置iptables操作系统的路由表。
iptables传输数据包的过程
① 当一个数据包进入网卡时,它首先进入PREROUTING链,内核根据数据包目的IP判断是否需要转送出去。
② 如果数据包就是进入本机的,它就会沿着图向下移动,到达INPUT链。数据包到了INPUT链后,任何进程都会收到它。本机上运行的程序可以发送数据包,这些数据包会经过OUTPUT链,然后到达POSTROUTING链输出。
③ 如果数据包是要转发出去的,且内核允许转发,数据包就会如图所示向右移动,经过FORWARD链,然后到达POSTROUTING链输出。
iptables的规则表和链:
iptables内置了4个表,即filter表、nat表、mangle表和raw表,分别用于实现包过滤,网络地址转换、包重构(修改)和数据跟踪处理。
链(chains)是数据包传播的路径,每一条链其实就是众多规则中的一个检查清单,每一条链中可以有一 条或数条规则。当一个数据包到达一个链时,iptables就会从链中第一条规则开始检查,看该数据包是否满足规则所定义的条件。如果满足,系统就会根据 该条规则所定义的方法处理该数据包;否则iptables将继续检查下一条规则,如果该数据包不符合链中任一条规则,iptables就会根据该链预先定 义的默认策略来处理数据包。
bridge模式下的容器通信
在bridge模式下连在同一网桥下的容器可以相互通信。
容器发包出去的过程:ip包会从container发往自己默认的网关docker0,到包到达docker0时就时到达了主机,这时候会查询主机的路由表,发现包应该从主机的网卡eth0出去,如下的iptables的规则就起作用,对包做snat转换,将原地址转成eth0的地址,这样对于外部来说docker容器就是不可见的:
![](https://img.haomeiwen.com/i8413433/37e42905140b214e.png)
从该网络模型可以看出,容器从原理上是可以与宿主机乃至外界的其他机器通信的。同一宿主机上,容器之间都是连接到docker0这个网桥上的,它可以作为虚拟交换机使容器可以相互通信。然而,由于宿主机的IP地址与容器veth pair的 IP地址均不在同一个网段,故仅仅依靠veth pair和namespace的技术,还不足以使宿主机以外的网络主动发现容器的存在。为了使外界可以方位容器中的进程,docker采用了端口绑定的方式,也就是通过iptables的NAT,将宿主机上的端口端口流量转发到容器内的端口上。
举一个简单的例子,使用下面的命令创建容器,并将宿主机的3306端口绑定到容器的3306端口:
docker run -tid –name db -p 3306:3306 MySQL
在宿主机上,可以通过iptables -t nat -L -n,查到一条DNAT规则:
DNAT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:3306 to:172.17.0.5:3306
上面的172.17.0.5即为bridge模式下,创建的容器IP。
很明显,bridge模式的容器与外界通信时,必定会占用宿主机上的端口,从而与宿主机竞争端口资源,对宿主机端口的管理会是一个比较大的问题。同时,由于容器与外界通信是基于三层上iptables NAT,性能和效率上的损耗是可以预见的。
网友评论