浅谈容器网络
直接使用宿主机网络
启动一个 nginx, 直接使用宿主机网络1
[root@k8s01 service]# docker run -d --net=host --name nginx-host nginx
这个容器启动后,直接监听的就是宿主机的 80 端口。像这样直接使用宿主机网络栈的方式,虽然可以为容器提供良好的网络性能,但也会不可避免地引入共享网络资源的问题,比如端口冲突。所以,在大多数情况下,我们都希望容器进程能使用自己 Network Namespace 里的网络栈,即:拥有属于自己的 IP 地址和 Port
可以看到实际使用的宿主机 ip+port
使用 docker0 网桥
宿主机1
2
3
4
5
6
7
8
9
10[root@k8s01 service]# ifconfig
## 省略 docker0 为 172.17.0.1
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
inet6 fe80::42:87ff:fe56:a7bb prefixlen 64 scopeid 0x20<link>
ether 02:42:87:56:a7:bb txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5 bytes 446 (446.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
启动两个 busybox 容器
1 | docker run -d -it --name busybox1 busybox |
查看 ip:
1 | [root@k8s01 service]# docker exec -it busybox1 /bin/sh # 节选 |
图的 node_ip 不重要,盗的图,意思差不多
docker里 这个 eth0 网卡,是一个 Veth Pair,它的一端在这个 busybox 容器的 Network Namespace 里,而另一端则位于宿主机上(Host Namespace)(veth1f4b2a8),并且被“插”在了宿主机的 docker0 网桥上,另一个 busybox2 也是“插”在了宿主机的 docker0 网桥上。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20veth1f4b2a8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::a802:c6ff:fe6c:13c5 prefixlen 64 scopeid 0x20<link>
ether aa:02:c6:6c:13:c5 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
vethdf30199: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::d438:c7ff:fe9d:3cf9 prefixlen 64 scopeid 0x20<link>
ether d6:38:c7:9d:3c:f9 txqueuelen 0 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 13 bytes 1102 (1.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@hdp03 ~]# brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242a434516d no veth1f4b2a8
vethdf30199

宿主机 ping 容器也能 ping 通1
2
3
4[root@k8s01 service]# ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3) 56(84) bytes of data.
64 bytes from 172.17.0.3: icmp_seq=1 ttl=64 time=0.099 ms
64 bytes from 172.17.0.3: icmp_seq=2 ttl=64 time=0.079 ms

在默认情况下,被限制在 Network Namespace 里的容器进程,实际上是通过 Veth Pair 设备 + 宿主机网桥的方式,实现了跟同其他容器的数据交换。
宿主机上,访问该宿主机上的容器的 IP 地址时,这个请求的数据包,也是先根据路由规则到达 docker0 网桥,然后被转发到对应的 Veth Pair 设备,最后出现在容器里
在 192.168.43.102 上启动一个 busybox3
1 | [root@k8s02 ~]# docker run -d -it --name busybox3 busybox |
在 Docker 的默认配置下,不同宿主机上的容器通过 IP 地址进行互相访问是根本做不到的。
192.168.43.101 上的容器 无法 ping 通 192.168.43.102 上的容器。
Overlay Network
flannel Vxlan, Calico BGP, Calico Vxlan
通过软件的方式,创建一个整个集群“公用”的网桥,然后把集群里的所有容器都连接到这个网桥上
需要在已有的宿主机网络上,再通过软件构建一个覆盖在已有宿主机网络之上的、可以把所有容器连通在一起的虚拟网络。所以,这种技术就被称为:Overlay Network(覆盖网络)。
就是将 pod 地址信封装在宿主机地址信息以内,实现跨主机且跨 node 子网的通信报文。性能较差

直接路由
flannel Host-gw, flannel Vxlan directrouting, Calico Directrouting
基于主机路由,实现报文从源主机到目的主机的直接转发,不需要进行报文的叠加封装。性能好
underlay
为 pod 启用单独的虚拟机网络,直接使用宿主机物理网络。pod 甚至可以在 k8s 环境之外的节点直接访问。相当于把 pod 当桥接模式的虚拟机使用(pod 和 宿主机在同一子网)。比较方便 k8s环境之外访问 k8s 环境之内的 pod 中的服务。性能最好