在开发 Kata/远程超主机(remote-hypervisor,也称为 peer-pods)的过程中,我遇到了一个问题,即 Kubernetes 的 pod IP 从工作节点(worker node)不可达。在这篇博客中,我将分享我的 Kubernetes 网络排查经历,希望这能帮助我的读者们。
Kata 远程 hypervisor(peer-pods)方式允许在任何基础设施环境中通过利用环境自带的基础设施管理 API(例如 AWS 或 Microsoft Azure 的 API)创建 Kata 虚拟机,分别在 AWS 或 Azure 上创建 Kata 虚拟机时使用这些 API。CNCF confidential containers 项目中的 cloud-api-adaptor 子项目实现了 Kata 远程 hypervisor 的功能。
如下图所示,在 peer-pods 方法中,pod(Kata)VM 运行在 K8s 工作节点之外,而 pod IP 可以通过 VXLAN 隧道从工作节点访问到。使用隧道确保 pod 网络继续按原样运行,而无需更改 CNI 网络。
使用 Kata 容器时,Kubernetes 中的 pod 在一个虚拟机中运行,因此我们称运行 pod 的虚拟机为 Kata VM。
Pod IP 10.132.2.46
无法从工作节点VM(IP: 192.168.10.163
)访问,它位于Pod VM(IP: 192.168.10.201
)上。
以下是我的环境中VM的详情如下——包含工作节点的VM和pod(Kata)VM。OVN-Kubernetes是我们使用的Kubernetes CNI插件。
+===========================+================+================+ | VM名称 | IP地址 | 说明 | +===========================+================+================+ | ocp-412-ovn-worker-1 | 192.168.10.163 | 工作节点VM | +---------------------------+----------------+----------------+ | podvm-nginx-priv-8b726648 | 192.168.10.201 | Pod VM | +---------------------------+----------------+----------------+
最简单的解决方法本应是向网络专家求助来解决这个问题。然而,在我的情况下,由于其他紧急的任务,专家们无法直接处理这个问题。此外,这种同级节点的网络拓扑是新的,并涉及多个网络栈——Kubernetes CNI、Kata网络和VXLAN隧道,这使得找出根本原因变得困难且耗时。
于是,我抓住这个机会来提高我的 Kubernetes 网络技术,开始在一些 Linux 网络专家的指导下独立学习。
接下来的几节中,我将带领你了解我的调试过程及找到问题根源的方法。这次调试步骤在排查Kubernetes网络问题时能帮到你一些。
总的来说,我采取的方法如下,分为两个步骤。
让我们从工作节点虚拟机 ping 这个 IP 地址 10.132.2.46 并跟踪数据包在网络栈中的路径。
运行ping命令来测试10.132.2.46的网络连接 [root@ocp-412-worker-1 core]# ping 10.132.2.46
Linux 会根据路由表来决定将这个数据包(packet)发送到哪里。
[root@ocp-412-worker-1 core]# ip route get 10.132.2.46 10.132.2.46 dev ovn-k8s-mp0 src 10.132.2.2 uid 0 (注:这里的输出显示了从10.132.2.2到10.132.2.46的路由信息)
所以,通往 pod IP 的路由是通过 ovn-k8s-mp0 接口
让我们先获取工作节点的网络详情,并查一下ovn-k8s-mp0设备的信息。
[root@ocp-412-ovn-worker-1 core]# ip r 默认网关 via 192.168.10.1 dev br-ex proto dhcp src 192.168.10.163 metric 48 10.132.0.0/14 via 10.132.2.1 dev ovn-k8s-mp0 10.132.2.0/23 dev ovn-k8s-mp0 proto kernel scope link src 10.132.2.2 169.254.169.0/29 dev br-ex proto kernel scope link src 169.254.169.2 169.254.169.1 dev br-ex src 192.168.10.163 mtu 1400 169.254.169.3 via 10.132.2.1 dev ovn-k8s-mp0 172.30.0.0/16 via 169.254.169.4 dev br-ex mtu 1400 192.168.10.0/24 dev br-ex proto kernel scope link src 192.168.10.163 metric 48 [root@ocp-412-ovn-worker-1 core]# ip a [省略] 2: ens3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel master ovs-system state UP group default qlen 1000 link/ether 52:54:00:f9:70:58 brd ff:ff:ff:ff:ff:ff 3: ovs-system: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 32:7c:7a:20:6e:5a brd ff:ff:ff:ff:ff:ff 4: genev_sys_6081: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 65000 qdisc noqueue master ovs-system state UNKNOWN group default qlen 1000 link/ether 3a:9c:a8:4e:15:0c brd ff:ff:ff:ff:ff:ff inet6 fe80::389c:a8ff:fe4e:150c/64 scope link 有效时间:永久 首选时间:永久 5: br-int: <BROADCAST,MULTICAST> mtu 1400 qdisc noop state DOWN group default qlen 1000 link/ether d2:b6:67:15:ef:06 brd ff:ff:ff:ff:ff:ff 6: ovn-k8s-mp0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether ee:cb:ed:8e:f9:e0 brd ff:ff:ff:ff:ff:ff inet 10.132.2.2/23 brd 10.132.3.255 scope global ovn-k8s-mp0 有效时间:永久 首选时间:永久 inet6 fe80::eccb:edff:fe8e:f9e0/64 scope link 有效时间:永久 首选时间:永久 8: br-ex: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default qlen 1000 link/ether 52:54:00:f9:70:58 brd ff:ff:ff:ff:ff:ff inet 192.168.10.163/24 brd 192.168.10.255 scope global dynamic 无前缀路由 br-ex 有效时间:2266秒 首选时间:2266秒 inet 169.254.169.2/29 brd 169.254.169.7 scope global br-ex 有效时间:永久 首选时间:永久 inet6 fe80::17f3:957b:5e8d:a4a6/64 scope link 无前缀路由 有效时间:永久 首选时间:永久 [省略]
如上所示,ovn-k8s-mp0
接口的 IP 为 10.132.2.2/23
我们来看看 ovn-k8s-mp0
接口的细节。
如下所示的输出,这个接口是OVS的一个实体(OVS,开放虚拟交换机)。
[root@ocp-412-ovn-worker-1 core]# ip -d li sh dev ovn-k8s-mp0 6: ovn-k8s-mp0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue 状态:未知 模式:默认 组 default 队列长度 以太网链路 ee:cb:ed:8e:f9:e0 广播地址 ff:ff:ff:ff:ff:ff 混杂模式 1 minmtu 68 maxmtu 65535 openvswitch 地址生成模式 eui64 发送队列数 1 接收队列数 1 最大gso大小 65536 最大gso段数 65535
ovn-k8s-mp0
是不是 OVS 桥?
注:根据上下文决定是否需要将 "OVS" 解释为 "开放虚拟交换机"。此处保持原样。
从下面的命令输出来看,ovn-k8s-mp0
不是一个 OVS 桥。工作节点上仅存在两个桥,分别是 br-ex
和 br-int
。
[root@ocp-412-ovn-worker-1 core]# ovs-vsctl list-br br-ex br-int # 此命令列出 Open vSwitch 中的桥接器,输出为 br-ex 和 br-int。
因此**ovn-k8s-mp0**
是一个OVS端口。我们需要找到拥有此端口的OVS桥接。
从下面的命令输出中可以看出,ovn-k8s-mp0
并不是为桥 br-ex
设计的 OVS 端口之一。
[root@ocp-412-ovn-worker-1 core]# ovs-ofctl dump-ports br-ex ovn-k8s-mp0 ovs-ofctl: br-ex: 未知端口 `ovn-k8s-mp0` 不存在
从下面的命令输出可以看出,ovn-k8s-mp0
是桥 br-int
上的一个 OVS 端口。
[root@ocp-412-ovn-worker-1 core]# ovs-ofctl dump-ports br-int ovn-k8s-mp0 OFPST_PORT 消息 (xid=0x4): 1 个端口 端口 "ovn-k8s-mp0": rx 包=1798208, 字节量=665641420, 丢弃=2, 错误=0, 帧=0, 超长包=0, CRC 错误=0, tx 包=2614471, 字节量=1357528110, 丢弃=0, 错误=0
**简而言之,ovn-k8s-mp0
是 br-int
OVS 桥上的一个端口,其 IP 地址为 10.132.2.2/23
。
现在,咱们来看看这个 pod 的网络配置。
要了解pod的网络详情,首先需要知道pod的网络命名空间。下面的命令通过其IP地址找到pod的网络命名空间。
[root@ocp-412-ovn-worker-1 core]# POD_IP=10.132.2.46; for ns in $(ip netns ls | cut -f 1 -d " "); do ip netns exec $ns ip a | grep -q $POD_IP; status=$?; [ $status -eq 0 ] && echo "pod 命名空间: $ns" ; done pod 命名空间: c16c7a01-1bc5-474a-9eb6-15474b5fbf04
一旦确定pod的网络命名空间,就可以找到pod的网络配置详情,如下。
[root@ocp-412-ovn-worker-1 core]# NS=c16c7a01–1bc5–474a-9eb6–15474b5fbf04 [root@ocp-412-ovn-worker-1 core]# ip netns exec $NS ip a 1: lo: <LOOPBACK, UP, LOWER_UP> mtu 65536 qdisc noqueue 状态 未知 组 默认 队列长度 1000 链路/本地回环 00:00:00:00:00:00 广播 00:00:00:00:00:00 inet 127.0.0.1/8 范围 主机 lo 有效时间 永久 优先时间 永久 inet6 ::1/128 范围 主机 有效时间 永久 优先时间 永久 2: eth0@if4256: <BROADCAST, MULTICAST, UP, LOWER_UP> mtu 1400 qdisc noqueue 状态 启用 组 默认 队列长度 1000 链路/以太网 0a:58:0a:84:02:2e 广播 ff:ff:ff:ff:ff:ff 链接-netns 59e250f6–0491–4ff4-bb22-baa3bca249f6 inet 10.132.2.46/23 范围 全局 eth0 有效时间 永久 优先时间 永久 inet6 fe80::858:aff:fe84:22e/64 范围 链路 有效时间 永久 优先时间 永久 4257: vxlan1@if4257: <BROADCAST, MULTICAST, UP, LOWER_UP> mtu 1500 qdisc noqueue 状态 未知 组 默认 队列长度 1000 链路/以太网 ca:40:81:86:fa:73 广播 ff:ff:ff:ff:ff:ff 链接-netns 59e250f6–0491–4ff4-bb22-baa3bca249f6 inet6 fe80::c840:81ff:fe86:fa73/64 范围 链路 有效时间 永久 优先时间 永久 [root@ocp-412-ovn-worker-1 core]# ip netns exec $NS ip r default 经 10.132.2.1 设备 eth0 10.132.2.0/23 设备 eth0 协议 内核 范围 链路 源 10.132.2.46
所以这个主要网络接口就是 eth0@if4256
,它是为 pod 所准备的。
我们来看看 eth0,这个设备的详细信息.
如以下输出所示,在pod网络命名空间中的eth0设备实际上是一个虚拟以太网设备(veth设备)。
[root@ocp-412-ovn-worker-1 core]# ip netns exec $NS ip -d li sh dev eth0 以太网链路 ether 0a:58:0a:84:02:2e 广播地址 ff:ff:ff:ff:ff:ff 链路网络命名空间 59e250f6-0491-4ff4-bb22-baa3bca249f6 veth 地址生成模式 eui64 发送队列 8 接收队列 8 最大GSO大小 65536 最大GSO段数 65535 最大TSO大小 524280 最大TSO段数 65535 最大GRO大小 65536
众所周知,veth设备通常成对出现;一端位于init(或根)命名空间中,另一端位于pod网络命名空间。
让我们在 init 命名空间里找到 pod 对应的 veth
设备对。
[root@ocp-412-ovn-worker-1 core]# ip a | grep -A1 ^4256 (注释:该命令用于查询网络接口,输出包含4256的行及其下一行) 4256: 8b7266486ea2861@if2: <广播,多播,启用,底层启用> 最大传输单元 1400 队列调度器 noqueue 主ovs-system 状态为启用 group 默认组 (例如:接口4256的详细信息,如其MAC地址等) link/ether de:fb:3e:87:0f:d6 brd ff:ff:ff:ff:ff:ff link-netns c16c7a01–1bc5–474a-9eb6–15474b5fbf04 (例如:MAC地址为de:fb:3e:87:0f:d6,广播地址为ff:ff:ff:ff:ff:ff,关联的网络命名空间的唯一标识符)
所以,8b7266486ea2861@if2
是 init 命名空间中 pod 的 veth
设备端。此**veth**
对连接了 init 和 pod 的网络名空间。
让我们查一下 veth
设备端点的详情。
[root@ocp-412-ovn-worker-1 core]# ip -d li sh dev 8b7266486ea2861 4256: 8b7266486ea2861@if2: <广播,多播,UP,LOWER_UP> mtu 1400 qdisc noqueue master ovs-system 状态UP 模式默认 组默认 以太网链路 de:fb:3e:87:0f:d6 brd ff:ff:ff:ff:ff:ff 链接网络命名空间 c16c7a01–1bc5–474a-9eb6–15474b5fbf04 侦听模式 1 最小MTU 68 最大MTU 65535 veth openvswitch从设备 地址生成模式为EUI-64 发送队列数量为4 接收队列数量为4 GSO最大大小为65536字节 GSO最大分段数为65535
因此,8b7266486ea2861@if2
是一个OVS实体。查看OVS交换机的详细信息可以提供哪个OVS桥接器拥有该端口的详情。
如以下输出所示,桥 br-int
包含端口。
注意,使用 ovs-vsctl
命令是之前命令 ovs-ofctl dump-ports <bridge> <port>
的一个替代命令。这表明不同的命令可以帮助探索网络拓扑。
[root@ocp-412-ovn-worker-1 core]# ovs-vsctl show [snap] 桥 br-int 故障模式:安全 数据路径类型:系统 [snip] 端口 "8b7266486ea2861" 接口 "8b7266486ea2861" [snap]
所以**br-int**
拥有包含**veth**
端点的端口,该端口位于init命名空间中。同时,也持有**ovn-k8s-mp0**
端口。
让我们查一下 pod 的 vxlan
相关信息。
如下所示的输出,vxlan
隧道的远程端点是 IP 192.168.10.201
,这是 pod 虚拟机的 IP。
[root@ocp-412-ovn-worker-1 core]# ip netns exec $NS ip -d li sh dev vxlan1 4257: vxlan1@if4257: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue 状态 未知 模式 默认 组 默认 队列长度 1000 链路/以太网 ca:40:81:86:fa:73 brd ff:ff:ff:ff:ff:ff 链接-netns 59e250f6–0491–4ff4-bb22-baa3bca249f6 混杂模式 0 最小MTU 68 最大MTU 65535 vxlan ID 555005, 远程 192.168.10.201, 源端口 0 0, 目标端口 4789, 禁止学习, ttl 自动设置, 年龄 300, udpcsum, 禁用udp6zerocsumtx, 禁用udp6zerocsumrx, 地址生成模式 eui64, 发送队列大小 1, 接收队列大小 1, GSO 最大大小 65536, GSO 最大段数 65535
一个问题就是如何将包从eth0
接口发送到vxlan1
接口。
这可以通过在网络命名空间中设置的Linux Traffic Control (TC) 来实现,用来在eth0
和vxlan1
之间镜像流量。这是从Kata容器的设计中了解到的。然而,我认为在排查网络问题时检查Traffic Control (TC)配置是个好习惯。
以下输出结果展示了在我的环境中 pod 网络命名空间中的设备的 TC 筛选规则。
[root@ocp-412-ovn-worker-1 core]# ip netns exec $NS tc filter show dev eth0 root 过滤规则 parent ffff: 协议 all pref 49152 u32 链 0 过滤规则 parent ffff: 协议 all pref 49152 u32 链 0 fh 800: ht 分段器 1 过滤规则 parent ffff: 协议 all pref 49152 u32 链 0 fh 800::800 顺序 2048 key ht 800 bkt 0 终端 flowid not_in_hw 匹配 00000000/00000000 at 0 动作顺序 1: mirred (Egress Redirect to 设备 vxlan1) 劫持 索引 1 引用数 1 绑定数 1 [root@ocp-412-ovn-worker-1 core]# ip netns exec $NS tc filter show dev vxlan1 root 过滤规则 parent ffff: 协议 all pref 49152 u32 链 0 过滤规则 parent ffff: 协议 all pref 49152 u32 链 0 fh 800: ht 分段器 1 过滤规则 parent ffff: 协议 all pref 49152 u32 链 0 fh 800::800 顺序 2048 key ht 800 bkt 0 终端 flowid not_in_hw 匹配 00000000/00000000 at 0 动作顺序 1: mirred (Egress Redirect to 设备 eth0) 劫持 索引 2 引用数 1 绑定数 1
eth0的出站数据流向被重定向到了vxlan1,与此同时,vxlan1的出站数据流向也被重定向到了eth0。
如下图所示,根据这些细节,可以创建一个工作节点的网络拓扑图,用于参考和进一步的技术分析。
现在,我们来关注一下 pod 虚拟机。
注意,pod 设计为虚拟机,使用了一个固定的网络名称空间,如 podns
。
以下输出显示了 pod 的网络设置
ubuntu@podvm-nginx-priv-8b726648:/home/ubuntu# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 状态 UNKNOWN group default qlen 1000 链路/本地环回 00:00:00:00:00:00 广播 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: ens2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel 状态 UP group default qlen 1000 链路/以太网设备 52:54:00:e1:58:67 广播 ff:ff:ff:ff:ff:ff inet 192.168.10.201/24 广播 192.168.10.255 scope global dynamic ens2 valid_lft 2902sec preferred_lft 2902sec inet6 fe80::5054:ff:fee1:5867/64 scope link valid_lft forever preferred_lft forever root@podvm-nginx-priv-8b726648:/home/ubuntu# ip r 默认路由 via 192.168.10.1 dev ens2 proto dhcp src 192.168.10.201 metric 100 192.168.10.0/24 dev ens2 proto kernel scope link src 192.168.10.201 192.168.10.1 dev ens2 proto dhcp scope link src 192.168.10.201 metric 100 root@podvm-nginx-priv-8b726648:/home/ubuntu# iptables -S -P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
以下显示了 podns
网络名称空间内的网络配置。
root@podvm-nginx-priv-8b726648:/home/ubuntu# ip netns exec podns ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue 状态 UNKNOWN group default qlen 1000 链路/本地环回 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 范围主机 lo inet6 ::1/128 范围主机 3: vxlan0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue 状态 UNKNOWN group default qlen 1000 链路/以太网 7e:e5:f7:e6:f5:1a brd ff:ff:ff:ff:ff:ff 链路-netnsid 0 inet 10.132.2.46/23 范围全局 vxlan0 inet6 fe80::7ce5:f7ff:fee6:f51a/64 范围链 root@podvm-nginx-priv-8b726648:/home/ubuntu# ip netns exec podns ip r 默认路由 via 10.132.2.1 dev vxlan0 10.132.2.0/23 dev vxlan0 协议内核 范围链 源 10.132.2.46 root@podvm-nginx-priv-8b726648:/home/ubuntu# ip netns exec podns ip -d li sh vxlan0 3: vxlan0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue 状态 UNKNOWN 模式默认 group default qlen 1000 链路/以太网 7e:e5:f7:e6:f5:1a brd ff:ff:ff:ff:ff:ff 链路-netnsid 0 促进度 0 最小mtu 68 最大mtu 65535 vxlan ID 555005 远程地址 192.168.10.163 源端口 0 0 目标端口 4789 不学习 TTL 自动 老化 300 udpcsum noudp6zerocsumtx noudp6zerocsumrx 地址生成模式 eui64 tx队列数 1 rx队列数 1 gso_max_size 65536 gso_max_segs 65535 root@podvm-nginx-priv-8b726648:/home/ubuntu# ip netns exec podns iptables -S -P INPUT ACCEPT -P FORWARD ACCEPT -P OUTPUT ACCEPT
这个**vxlan**
隧道的设置看起来没问题。它显示了远程端点的IP**192.168.10.163**
,这是工作节点VM的IP地址。
在 pod 虚拟机里,也没有任何防火墙规则。
然而,在Pod VM中你不会看到像在工作节点中那样的veth
对。这时一个问题是这样的:init和podns
网络命名空间之间是如何通信的,而没有了veth
对呢?值得注意的是,物理设备位于init(即根)命名空间和podns
命名空间中,而vxlan
设备位于podns
命名空间中。
感谢Stefano Brivio提醒了这个Linux内核的更新提交,它让这一切成为可能。
commit f01ec1c017dead42092997a2b8684fcab4cbf126 Author: Nicolas Dichtel <nicolas.dichtel@6wind.com> Date: Thu Apr 24 10:02:49 2014 +0200 vxlan: 添加对 x-netns 的支持 此补丁允许在封装或解封装数据包时切换网络命名空间。 VXLAN 套接字在 I/O 命名空间中打开,即在接收封装数据包的命名空间中打开。套接字查找将在该命名空间中执行,以找到相应的 VXLAN 隧道。解封装后,数据包将被注入到可能位于不同命名空间中的相应接口中。 当其中一个命名空间被删除时,隧道将被销毁。 配置示例: ip netns add netns1 ip netns exec netns1 ip link set lo up ip link add vxlan10 type vxlan id 10 group 239.0.0.10 dev eth0 dstport 0 ip link set vxlan10 netns netns1 ip netns exec netns1 ip address add 192.168.0.249/24 broadcast 192.168.0.255 dev vxlan10 ip netns exec netns1 ip link set vxlan10 up
也有一个StackOverflow上的帖子解释了这个问题。
这些细节让我们对pod VM(即pod虚拟机)的网络拓扑有了一个良好的概览,如图所示。
我们可以在 vxlan0
接口上运行 tcpdump
,看看是否收到了来自工作节点(worker node)的 ICMP 请求。
如下所示的输出,收到了互联网控制消息协议(ICMP)请求,但没有回信。
root@podvm-nginx-priv-8b726648:/home/ubuntu# ip netns exec podns tcpdump -i vxlan0 -s0 -n -vv tcpdump: listening on vxlan0, link-type EN10MB (Ethernet), capture size 262144 bytes [略] 10.132.2.2 > 10.132.2.46: ICMP 回声请求, id 20, 序号 1, 长度 64 10:34:17.389643 IP (tos 0x0, ttl 64, id 27606, offset 0, 标志 [DF], 协议 ICMP (1), 长度 84) 10.132.2.2 > 10.132.2.46: ICMP 回声请求, id 20, 序号 2, 长度 64 10:34:18.413682 IP (tos 0x0, ttl 64, id 27631, offset 0, 标志 [DF], 协议 ICMP (1), 长度 84) 10.132.2.2 > 10.132.2.46: ICMP 回声请求, id 20, 序号 3, 长度 64 10:34:19.002837 IP (tos 0x0, ttl 1, id 28098, offset 0, 标志 [DF], 协议 UDP (17), 长度 69) [略]
咱们现在来盘点一下情况。
完成这个练习后,你对工作节点和 pod 虚拟机的网络结构有了一个不错的理解,并且没有发现任何隧道设置问题的迹象。可以看到 pod 虚拟机接收了 ICMP 数据包,也没有软件防火墙阻止这些数据包。接下来该做什么?
继续往下看,看看接下来会发生什么 :-)
(Markdown格式保持不变,直接翻译文本部分。)
我用 wireshark
分析了正常工作的常规 Kata 设置中的 tcpdump
抓包。使用 Wireshark 的 GUI 可以很容易地理解通过 tcpdump
抓取的网络数据包。
在跟踪中没有看到任何ARP请求或响应。工作节点上的ARP表会被填充,且使用的是pod网络命名空间内的eth0
设备的MAC地址,而不是pod VM中的vxlan0
设备(位于podns
命名空间内)的MAC地址。
? (10.132.2.46) 的 MAC 地址是 0a:58:0a:84:02:2e (MAC地址) [以太网],在 ovn-k8s-mp0 上。
0a:58:0a:84:02:2e 是工作节点上 pod 网络命名空间中的 eth0
接口的 MAC 地址,而 7e:e5:f7:e6:f5:1a 是虚拟机上 podns
命名空间中的 vxlan0
接口的 MAC 地址。
这是因为问题在于从工作节点(worker node)无法访问pod IP。ARP条目应该指向podns
命名空间中vxlan0
设备的MAC地址(比如7e:e5:f7:e6:f5:1a)。
回头想想,我本应该先看看ARP表里的信息。下次遇到类似情况时,我一定会那样做 :)
斯蒂法诺·布里维奥(Stefano Brivio)的一个巧妙的技巧解决了这个问题。在 pod 虚拟机的 vxlan0
接口上使用与工作节点上的 pod 的 eth0
接口相同的 MAC 地址,解决了连接问题。
ip netns exec podns ip link set vxlan0 down # 将vxlan0接口设置为关闭状态 ip netns exec podns ip link set dev vxlan0 address 0a:58:0a:84:02:2e # 设置vxlan0接口的MAC地址 ip netns exec podns ip link set vxlan0 up # 将vxlan0接口设置为开启状态
这就是最终的网络拓扑图。
最后来总结一下
调试 Kubernetes 集群中的网络问题并不简单。采用一种明确的方法,借助专家的帮助以及公开可用的资料,可以找到根本原因并解决问题。在这个过程中学习也挺有趣的。
我希望这对你有用。
下面是我排除故障时发现的一些非常有用的参考资料。