一. 导学
在创建容器时,可以声明直接使用宿主机的网络栈(--net=host),即不开启network namespace,这种方式虽然可以为容器提供良好的网络性能,但不可避免的引入网络资源共享的问题,比如端口冲突,在大多情况下,我们都希望容器进程能够使用自己 Network Namespace 里的网络栈,即:拥有自己的IP地址和端口。
补充知识: 网络栈:包括了网卡(Network Interface)、回环设备(Looback Device)、路由表(Routing Table)和 iptables 规则 这时候,一个显而易见的问题是:容器进程如何与容器外的其他进程进行网络通信?
在 Docker 项目中,会默认在宿主机上创建一个名为 docker0 的网桥,通过名为 Veth Pair 的虚拟设备,让容器"连接"到 docker0 网桥上的方式,实现了跟其他容器的数据交换。
Veth Pair 设备: Veth Pair 它被创建出来后,总是以两张虚拟网卡的形式成对出现,其中一个网卡发出的数据包,可以直接出现在它的另一张网卡上。
docker0网桥: 工作在数据链路层的设备,主要根据 MAC 地址学习,将数据帧转发到网桥的不同端口上
二. 容器网络介绍
在 Linux 中,通过 docker run -it busybox /bin/sh 命令启动一个容器,如下:
# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:AC:11:00:03
inet addr:172.17.0.3 Bcast:172.17.255.255 Mask:255.255.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:8 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:656 (656.0 B) TX bytes:0 (0.0 B)
lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:65536 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
通过 ifconfig 命令的输出,我们看到的 eth0 网卡,正是 Veth Pair 设备在容器中的一端。
通过 route 命令,可以查看容器的路由表,第二条路由规则:Gateway 是 0.0.0.0
,说明这是一条直连路由规则,凡是 Destination 属于 172.17.0.0/16 的 IP 包,会经过容器的 eth0 网卡,通过二层设备 docker0 网桥发到目标容器,即同一宿主机上的容器默认是相互连通的。第一条路由规则:Destination 为 default 表示这个是默认路由,对其他网段的请求,都会经过容器的eth0网卡,发往172.17.0.1 网关。
U:Up 表示此路由为启动状态
G:Gateway 需要经过网关
2.1 同一宿主机上不同容器之间的通信过程:
当在 Container-1 容器中,访问 Container-2 容器的 IP 地址(比如:ping 172.17.0.3)时,首先会查看容器中的路由表(如上示),这个时候匹配到的是第二条直连路由规则,即通过二层网络即可到达 Container-2 容器。这个时候需要这个目的 IP 对应的 MAC 地址,Container-1 容器的 eth0 网卡会发送 APR 广播。docker0 网桥收到 ARP 请求之后, 就会扮演二层交换机的角色,把 ARP 广播转发到其他被"插"在 docker0 上的虚拟网卡上,Container-2 容器收到这个 ARP 请求后,就会把 IP 对应的 MAC 地址回复给 Container-1。有了这个目的 MAC 地址,就会对数据包封装,之后 Container-1 容器就可以将数据帧发送出去,docker0 收到这个数据帧后,继续扮演着二层交换机的角色,根据目的 MAC 地址,查看 CAM 表(端口与 MAC 地址的对应表),将数据帧转发给这个端口,Container-2 容器接收到后,会对请求进行处理,将响应(Pong) 返回到 Container-1
ARP协议: 通过三层的 IP 地址查到到对应二层 MAC 地址的协议
2.2 宿主机访问其上容器的通信过程:
粗略描述:在宿主机上,访问其上容器 IP 地址时,这个请求包会首先根据路由规则,达到 docker0 网桥,对数据帧完成解封装和封装操作,根据 CAM 表,转发到对应的 Veth Pair 设备,最后出现在容器中
2.3宿主机上容器访问另一台宿主机的通信过程:
粗略描述:当宿主机上的一个容器连接另外一个宿主机时(比如:ping 10.168.0.3),发出的请求包首先会经过 docker0 网桥出现在宿主机上,然后根据宿主机路由表上的规则,对访问请求进行处理。这个过程实现的前提是两台宿主机本身会连通的
存在的问题:在 Docker 的默认配置下,一台宿主机上的 docker0 网桥,和其他宿主机上的docker0 网桥没有任何关联,所有并无法实现容器间的跨主机通信问题