【K8s 精选】深入剖析 Kubernetes 网络模型
1 网络基础
1.1 网桥、网卡、MAC
① 网桥:将不同物理层连接在一起。
② 网卡:接收和转换信息的硬件。
③ MAC:MAC 是设备的地址。
网桥、网卡和 MAC 作用于数据链路层。如下图所示,网卡“插入”到网桥和设备中,使用网线连接网桥和设备两端的网卡。
网桥网卡和MAC的关系.jpg1.2 Veth Pair
Veth Pair 可以参考Linux 虚拟网络设备 veth-pair 详解,看这一篇就够了
veth-pair 是一对的虚拟设备接口,一端连着协议栈,一端彼此相连。以网桥的连接方式为例,分析 veth-pair 的使用。网桥相当于交换机,可以中转两个 namespace 的流量。veth-pair 是“插在”设备和网桥之间的网卡。
1.3 iptables
iptables 详解可以参考iptables命令及一些常用规则
iptables 部分命令如下:
-t nat 表示配置的是 nat 表,raw 网址过滤、mangle 数据修改、net 地址转换、filter 包过滤(防火墙规则)
-A PREROUTING 表示添加一个 PREROUTING 链
-i eth0 表示指定数据包进入本机的网络接口
-p tcp --dport 422 代表匹配到的 tcp 协议的数据包,目的端口号是422
-j ACCEPT 表示接收数据包,例如 accept 是接收数据包、drop 是丢弃数据包、redirct 是重定向、snat 是源地址转换、dnat 是目标地址转换、masquerade 是 IP 伪装(NAT)、log 是日志记录
--to 192.168.102.37:22 表示转发到 192.168.102.37:22
#数据报伪装
#将源地址是 192.168.102.0/24 的数据包进行地址伪装
$iptables -t nat -A POSTROUTING -s 192.168.102.0/24 -j MASQUERADE
#将全部来源的数据包进行地址伪装
$iptables -t nat -A POSTROUTING -j MASQUERADE
# 数据包转发:设置 422 端口转发到 22 端口
# 方法1 指定数据包从 192.168.102.37:422 转发到 192.168.102.37:22
$iptables -t nat -A PREROUTING -p tcp -d 192.168.102.37 --dport 422 -j DNAT --to 192.168.102.37:22
#方法2 指定数据包从本机网卡 eth0 端口 443 转发到 192.168.102.37:22
$iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 443 -j DNAT --to 192.168.102.37:22
# 本机网卡 eth0 接收 137 udp 端口、138 tcp 端口的数据包
$iptables –A INPUT –i eth0 –p udp –dport 137 –j ACCEPT
$iptables –A INPUT –i eth0 –p tcp –dport 138 –j ACCEPT
# 防火墙设置
# INPUT 链、FORWARD 链、OUTPUT 链允许全部数据包的传输
iptables -P INPUT ACCEPT
iptables -P FORWARD ACCEPT
iptables -P OUTPUT ACCEPT
如下所示,iptables 与网络分层的关系。
iptables 与网络分层的关系.png2 Kubernetes 网络插件 CNI 的工作流程
image.png3 容器网络入门
关键问题:每个容器都有属于自己的 IP 和端口,被隔离的容器进程,该如何跟其他 Network Namespace 里的容器进程进行交互呢?
3.1 同一个宿主机下容器之间的通信
深入了解 Network Namespace 可以参考一文搞懂 Linux network namespace,
容器利用 Network Namespace 实现网络的隔离,包括网络设备、IPV4 和 IPV6 协议栈、IP 路由表、防火墙、/proc/net 目录、/sys/class/net 目录、端口等。多个 Network Namespace 之间的通信需要利用 Veth Pair + 网桥,其中网桥具有 iptables 功能,只需要设置规则 iptables -A FORWARD -i bridgeA -j ACCEPT
,即可允许数据包在网桥 bridgeA
中转发。
案例分析:同一个宿主机上实现容器 172.17.0.2 到容器 172.17.0.3 的通信。
Container1 172.17.0.2
访问 Container2 172.17.0.3
的流程:
数据包 从 Container1 访问 Container2 172.17.0.3 的时候首先匹配到第二条路由规则(GateWay 0.0.0.0),意味着经过本机的 eth0,通过数据链路层 MAC 协议发送到 Container2 172.17.0.3。Container1 另一端的网卡 veth9c02e56 和 Container2 另一端的网卡 vethb4963f3 都“插入”网桥中。最后Container2 172.17.0.3 也是通过 eth0 接受数据包。
#进入容器 172.17.0.2 后,查看网络设备
$ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe11:2 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 364 bytes 8137175 (7.7 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 281 bytes 21161 (20.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
#分析:虚拟网卡 Veth Pair 的一端 eth0 在“插入”容器中。
#查看容器的路由表
#Destination 表示目标地址或者主机,Gateway 表示网关地址,Genmask 表示子网掩码,Flags-U 表示路由是活动的,Iface 表示 路由表项对应的输出接口
$ 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
#分析:eth0 是容器的默认路由设备。第二行表示网段 172.17.0.0/16 的请求都会交给 eth0 来处理
#登录容器所在的宿主机,查看网络设备
$ifconfig
...
docker0 Link encap:Ethernet HWaddr 02:42:d8:e4:df:c1
inet addr:172.17.0.1 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:d8ff:fee4:dfc1/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:309 errors:0 dropped:0 overruns:0 frame:0
TX packets:372 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:18944 (18.9 KB) TX bytes:8137789 (8.1 MB)
veth9c02e56 Link encap:Ethernet HWaddr 52:81:0b:24:3d:da
inet6 addr: fe80::5081:bff:fe24:3dda/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:288 errors:0 dropped:0 overruns:0 frame:0
TX packets:371 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:21608 (21.6 KB) TX bytes:8137719 (8.1 MB)
#分析:宿主机有虚拟网卡 Veth Pair 的另一端 veth9c02e56
#查看网桥信息
$brctl show
bridge name bridge id STP enabled interfaces
docker0 8000.0242d8e4dfc1 no veth9c02e56
#分析:通过网桥信息可以看到虚拟网卡 veth9c02e56 已经“插入”网桥 docker0 中
结论:被隔离在 Network Namespace 里的容器进程,通过 Veth Pair + 宿主机网桥实现了跟其它容器的数据交换。
3.2 容器与不同宿主机的通信
案例分析:Node1 10.168.0.2 上的 Container1 172.17.0.2 访问 Node2 10.168.0.3。首先数据包通过 container1 eth0 和 docker0 veth9c02e56 传输到 docker0,接着根据 docker0 的 iptables 规则10.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
表示目标地址是 10.168.0.0/24 的数据包都交给 eth0。最后数据包经过 Node1 eth0 转发到住宿机网络,最终达到 Node2 10.168.0.3
容器不通“外网”的定位思路:宿主机网络 》网桥 docker0 》网桥 iptables 防火墙规则。
上述例子 Node1 Container1 到 Node2。首先在 Node1 上 curl Node2,判断宿主机之间的网络有无通。然后在 Node1 上ifconfig
查询 docker0 的 IP 为 172.17.0.1,接着在 Node2 上直接 curl docker0。最后检查 docker0 上的 iptables 规则iptables -A FORWARD -i docker0 -j ACCEPT
,即防火墙有无打开。
4 Kubernetes 网络模型
Fannel-host-gw.png本节以 Fannel-host-gw 为例,讲解 Kubernetes 的三层网络原理。host-gw 模式的原理是将宿主机的 Flannel 子网设置成该宿主机的 IP 地址,数据包通过路由直接在宿主机之间交换。
#CNI 插件 Fannel 在 Node1 上创建这条路由规则
$ip route
10.244.1.0/24 via 10.168.0.3 dev eth0
#这条规则的含义:目的地址属于子网 10.244.1.0/24 的数据包,都会经过本机网卡 eth0,并且下一跳地址是 10.168.0.3
#分析:宿主机 Node1 eth0 到 Node2 eth0 的通信是直接采用路由规则转发,即数据帧是通过二层网络的 mac 协议,实现了在不同宿主机之间的转发。
结合上述 2.1 中容器与宿主机的通信。Node1 的容器 container1 10.244.0.2
到 Node2 的容器 container2 10.244.1.3
的数据包转发流程:
① 10.244.0.2
到 Node1 网桥 cni0:通过 Veth Pair + 网桥 cni0,即容器侧的 eth0 与宿主机网桥 cni0 侧 vethxxxxxxx,实现容器与宿主机的通信。
② 宿主机 Node1 到 Node2:直接配置网桥 cni0 路由规则转发,实现目的地是子网 10.244.1.0/24 的数据包,经过本机网卡 eth0,转发到 10.168.0.3
③ Node2 网桥 cni0 到 10.244.1.3
:同理 ①,即宿主机网桥 cni0 侧 vethxxxxxxx 与 容器侧的 eth0,实与宿主机与容器的通信。