容器网络—学习笔记整理

86 阅读4分钟

一. 导学

在创建容器时,可以声明直接使用宿主机的网络栈(--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 地址的协议

image.png

2.2 宿主机访问其上容器的通信过程:

粗略描述:在宿主机上,访问其上容器 IP 地址时,这个请求包会首先根据路由规则,达到 docker0 网桥,对数据帧完成解封装和封装操作,根据 CAM 表,转发到对应的 Veth Pair 设备,最后出现在容器中

image.png

2.3宿主机上容器访问另一台宿主机的通信过程:

粗略描述:当宿主机上的一个容器连接另外一个宿主机时(比如:ping 10.168.0.3),发出的请求包首先会经过 docker0 网桥出现在宿主机上,然后根据宿主机路由表上的规则,对访问请求进行处理。这个过程实现的前提是两台宿主机本身会连通的

image.png

存在的问题:在 Docker 的默认配置下,一台宿主机上的 docker0 网桥,和其他宿主机上的docker0 网桥没有任何关联,所有并无法实现容器间的跨主机通信问题

学习参考:time.geekbang.org/column/arti…