【K8s 精选】深入剖析 Kubernetes 网络模型

1 网络基础

1.1 网桥、网卡、MAC

网桥:将不同物理层连接在一起。
网卡:接收和转换信息的硬件。
MAC:MAC 是设备的地址。

网桥、网卡和 MAC 作用于数据链路层。如下图所示,网卡“插入”到网桥和设备中,使用网线连接网桥和设备两端的网卡。

网桥网卡和MAC的关系.jpg

1.2 Veth Pair

Veth Pair 可以参考 Linux 虚拟网络设备 veth-pair 详解,看这一篇就够了

veth-pair 是一对的虚拟设备接口,一端连着协议栈,一端彼此相连。以网桥的连接方式为例,分析 veth-pair 的使用。网桥相当于交换机,可以中转两个 namespace 的流量。veth-pair 是“插在”设备和网桥之间的网卡。

1.3 iptables

【参考】
1.iptables命令参数详解
2.iptables的四表五链与NAT工作原理
3.深入浅出带你理解 iptables 原理

iptables 的工作流程如下,当用户向本机发送数据包时
① 首先经过 PREROUTING 链的过滤规则
② 判断是否为本机数据包,如果是那么经过 INPUT 链规则后到达本机的用户态
③ 如果不是本机数据包通过 FORWARD 链后再通过 POSTROUTING 链到其他地址
当本机向外发送数据包时,经过 OUTPUT 链后再通过 POSTROUTING 链到达其他地址

image.png

语法格式:iptables -t 表名 <-A/I/D/R> 规则链名 <-i/o 网卡名> -p 协议名 <-s 源IP/源子网> --sport 源端口 <-d 目标IP/目标子网> --dport 目标端口 -j 动作

  • 表名、链名:指定 iptables 命令所操作的表和链,其中表分别为 filternatrawmangle,默认使用 filter 表;
  • 管理选项:表示 iptables 规则的操作方式,比如:插入、增加、删除、查看等;
  • 匹配条件:指定要处理的数据包的特征,不符合指定条件的数据包不处理;
  • 控制类型:指数据包的处理方式,比如:允许 accept、拒绝 reject、丢弃 drop、日志 LOG等;
# 1.iptables 的 Commands 选项
 -A:在指定链的末尾添加一条新的规则
 -D:删除指定链中的某一条规则,可删除指定序号或具体内容
 -I:在指定链中插入一条新规则,未指定序号时默认作为第一条规则
 -R:修改、替换指定链中的某一条规则,可指定规则序号或具体内容
 -L:列出指定链中所有的规则,未指定链名,则列出表中的所有链
 -F:清空指定链中所有的规则,未指定链名,则清空表中的所有链
 -P:设置指定链的默认策略
 -n:使用数字形式显示输出结果
 -v:查看规则列表时显示详细的信息
 -h:查看命令帮助信息
 --line-numbers:查看规则列表时,同时显示规则在链中的顺序号

# 2.iptables 的 Options 选项
-p proto,针对协议过滤,例如 tcp
-s source address[/mask][...],源地址
-d destination address[/mask][...],目的地址
-m match,指定要使用的匹配项
-i input name[+],指定进入接口
-j target,跳转到目标规则,例如ACCEPT、DROP、REJECT、SNAT、MASQUERADE、DNAT、REDIRECT
-n 使用数字形式显示输出结果
-t table,指定表,默认是 filter
--line-numbers,显示规则号

iptables 使用样例:

# 本机网卡 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

#数据报伪装
#将源地址是 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

1.4 iptables、bridge 和网络的关系

根据计算机网络体系结构的五层协议,bridge 作用于在数据链路层,iptables 作用于在网络层。

image.png

2 Kubernetes 网络插件 CNI 的工作流程

image.png

3 容器网络入门

关键问题:每个容器都有属于自己的 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 接受数据包。

同一个宿主机下容器之间的通信.png
#进入容器 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

容器与不同宿主机的通信.png

容器不通“外网”的定位思路:宿主机网络 》网桥 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 为例,讲解 Kubernetes 的三层网络原理。host-gw 模式的原理是将宿主机的 Flannel 子网设置成该宿主机的 IP 地址,数据包通过路由直接在宿主机之间交换

Fannel-host-gw.png
#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,实与宿主机与容器的通信。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容