K8s 最强 CNI Cilium 网络故障排查指南
❝本文转自掘金,原文:https://juejin.cn/post/7176184210284085285,版权归原作者所有。欢迎投稿,投稿请添加微信好友:cloud-native-yang
我是 LEE,老李,一个在 IT 行业摸爬滚打 16 年的技术老兵。
事件背景
最近不少 k8s 底层网络模块都从 kubenet 升级到了 cilium,cilium 还是相对比较易用的,就是运维、监控和报警方案需要花点时间来适应。但是最近我们有一组 k8s 结构比较特殊,导致它在从 kubenet 升级到 cilium 的时候出现了一个小插曲:在 kubenet 网络的节点上的 pod 无法访问 cilium 网络的节点上且部署了 networkpolicy 的 pod,导致了这个 k8s 上部分商户在新发应用 pod 时,pod 被调度到 cilium 网络的节点上,此时无法与运行在 kubenet 网络的节点上 pod 互访问题。
现象获取
当我们接到监控系统的报警,以及客户的反馈,所以部分商户出现了服务异常,而且只是少量商户的出现了问题。针对这些商户的服务我第一时间看了下共性,发现这些商户的服务性质,受众群体,以及触发报警时间都不一样,难道是巧合?我随机找一个商户做了简单的排查:
直接测试商户的接口
发现商户接口直接返回:upstream connect error or disconnect/reset before headers. reset reason: connection failure ,单看这个信息,就知道这个应该不是服务返回的内容,应该是后端服务前某一层转发层的问题。
查看但是商户服务的异常日志
查看应用 sidecar 的日志, 把有问题的部分过滤出来,发现是错误代码是 503。
通过上面的故障,我顿时觉得整个问题很奇怪。Http 503 的意思是说后端的服务资源不存在了,但是后端的 IP 还是通的,要不然就会是 502。
所以这里踩了一个小坑,觉得是商户应用的问题,还跟商户确认了很多内容,以及最近发布的情况。但是实际是因为网络层请求被截断,导致数据包无法正常转发,才导致这次故障,具体我们看下一个环节。
原理分析
故障测试
通过大量的排查和分析,而且确定商户的服务启动正常,没有运行报错日志。只是服务无法对外正常提供,我就快速将排障范围缩小到了网络层面。
这里我提供一份网络流量结构图:
Ingress pod:是 istio Ingress gateway App pod: 是商户应用服务的 pod,拥有 istio 的 sidecar
为了确认丢包的位置,我们分在如下几个点抓包测试:
抓包信息汇总表:
测试点 | 抓包结果 |
---|---|
A 点 | 有 request,没有 respond |
B 点 | 有 request,没有 respond |
C 点 | 什么都没有 |
测试完,我大吃一惊,感觉丢包了啊,而且是 cilium 节点把数据包丢了。带着怀疑,有仔细检查了两个 cilium 节点上的 ct 表,以及 networkpolicy 挂载点信息。
ENDPOINT 信息
ENDPOINT POLICY (ingress) POLICY (egress) IDENTITY LABELS (source:key[=value]) IPv6 IPv4 STATUS
ENFORCEMENT ENFORCEMENT
2636 Enabled Disabled 59271 k8s:app=wetown-java 10.242.2.149 ready
k8s:app_id=468205436992_wetown-java
k8s:app_name=wetown-java
k8s:appnew=468205436992_wetown-java
k8s:group=standard
k8s:io.cilium.k8s.namespace.labels.istio-injection=enabled
k8s:io.cilium.k8s.namespace.labels.project_id=468205436992_default
k8s:io.cilium.k8s.namespace.labels.project_name=default
k8s:io.cilium.k8s.namespace.labels.tenant_id=468205436992
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=468205436992-default
k8s:metric_source=customize
k8s:security.istio.io/tlsMode=istio
k8s:service.istio.io/canonical-name=wetown-java
k8s:service.istio.io/canonical-revision=latest
NETWORKPOLICY 信息
Defaulted container "cilium-agent" out of: cilium-agent, mount-cgroup (init), apply-sysctl-overwrites (init), clean-cilium-state (init)
POLICY DIRECTION LABELS (source:key[=value]) PORT/PROTO PROXY PORT BYTES PACKETS
Allow Ingress reserved:unknown 9999/TCP NONE 0 0
Allow Ingress reserved:host ANY NONE 408725 5154
Allow Ingress k8s:app=istiod ANY NONE 11824851 910
k8s:install.operator.istio.io/owning-resource=unknown
k8s:io.cilium.k8s.namespace.labels.istio-injection=disabled
k8s:io.cilium.k8s.namespace.labels.system=true
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=istiod-1-11-8
k8s:io.kubernetes.pod.namespace=istio-system
k8s:istio.io/rev=1-11-8
k8s:istio=istiod
k8s:operator.istio.io/component=Pilot
k8s:sidecar.istio.io/inject=false
Allow Ingress k8s:app=istio-ingressgateway ANY NONE 8007 14
k8s:chart=gateways
k8s:heritage=Tiller
k8s:install.operator.istio.io/owning-resource=unknown
k8s:io.cilium.k8s.namespace.labels.istio-injection=disabled
k8s:io.cilium.k8s.namespace.labels.system=true
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=istio-ingressgateway-service-account
k8s:io.kubernetes.pod.namespace=istio-system
k8s:istio.io/rev=1-11-8
k8s:istio=ingressgateway
k8s:operator.istio.io/component=IngressGateways
k8s:release=istio
k8s:service.istio.io/canonical-name=istio-ingressgateway
k8s:service.istio.io/canonical-revision=1-11-8
k8s:sidecar.istio.io/inject=false
Allow Ingress k8s:app=network-debug ANY NONE 0 0
k8s:io.cilium.k8s.namespace.labels.system=true
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=default
Allow Ingress k8s:app=wetown-java ANY NONE 0 0
k8s:app_id=468205436992_wetown-java
k8s:app_name=wetown-java
k8s:appnew=468205436992_wetown-java
k8s:group=standard
k8s:io.cilium.k8s.namespace.labels.istio-injection=enabled
k8s:io.cilium.k8s.namespace.labels.project_id=468205436992_default
k8s:io.cilium.k8s.namespace.labels.project_name=default
k8s:io.cilium.k8s.namespace.labels.tenant_id=468205436992
k8s:io.cilium.k8s.policy.cluster=default
k8s:io.cilium.k8s.policy.serviceaccount=default
k8s:io.kubernetes.pod.namespace=468205436992-default
k8s:metric_source=customize
k8s:security.istio.io/tlsMode=istio
k8s:service.istio.io/canonical-name=wetown-java
k8s:service.istio.io/canonical-revision=latest
k8s:tenant_id=468205436992
Allow Egress reserved:unknown ANY NONE 990293 6509
CT 信息
TCP IN 10.242.2.153:60064 -> 10.242.2.149:15021 expires=17276052 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17276043 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17276043 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:2464 -> 10.242.2.149:15020 expires=17276618 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17276609 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276609 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:19582 -> 10.242.2.149:15021 expires=17275992 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17275983 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17275983 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:17164 -> 10.242.2.149:15021 expires=17276443 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17276434 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17276434 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:15068 -> 10.242.2.149:15020 expires=17276115 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17276106 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276106 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:3468 -> 10.242.2.149:15021 expires=17276081 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17276072 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17276072 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:60072 -> 10.242.2.149:15021 expires=17276413 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17276404 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17276404 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:13152 -> 10.242.2.149:15021 expires=17276083 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17276074 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17276074 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:60054 -> 10.242.2.149:15021 expires=17276509 RxPackets=18 RxBytes=1392 RxFlagsSeen=0x1b LastRxReport=17276500 TxPackets=12 TxBytes=1113 TxFlagsSeen=0x1b LastTxReport=17276500 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:14902 -> 10.242.2.149:15020 expires=17276263 RxPackets=5 RxBytes=417 RxFlagsSeen=0x1b LastRxReport=17276254 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276254 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:7100 -> 10.242.2.149:15021 expires=17276003 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17275994 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17275994 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:1396 -> 10.242.2.149:15020 expires=17276207 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17276198 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276198 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:11408 -> 10.242.2.149:15020 expires=17275973 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17275964 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17275964 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:60010 -> 10.242.2.149:15020 expires=17276575 RxPackets=63 RxBytes=5171 RxFlagsSeen=0x1b LastRxReport=17276566 TxPackets=60 TxBytes=4512 TxFlagsSeen=0x1b LastTxReport=17276566 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:18134 -> 10.242.2.149:15020 expires=17276315 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17276306 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276306 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:3438 -> 10.242.2.149:15021 expires=17276076 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17276067 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17276067 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:17962 -> 10.242.2.149:15020 expires=17276032 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17276023 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276023 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:10100 -> 10.242.2.149:15020 expires=17276500 RxPackets=5 RxBytes=418 RxFlagsSeen=0x1b LastRxReport=17276491 TxPackets=5 TxBytes=376 TxFlagsSeen=0x1b LastTxReport=17276491 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:8154 -> 10.242.2.149:15021 expires=17276329 RxPackets=12 RxBytes=928 RxFlagsSeen=0x1b LastRxReport=17276320 TxPackets=8 TxBytes=742 TxFlagsSeen=0x1b LastTxReport=17276320 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
TCP IN 10.242.2.153:19556 -> 10.242.2.149:15021 expires=17275986 RxPackets=6 RxBytes=464 RxFlagsSeen=0x1b LastRxReport=17275977 TxPackets=4 TxBytes=371 TxFlagsSeen=0x1b LastTxReport=17275977 Flags=0x0013 [ RxClosing TxClosing SeenNonSyn ] RevNAT=0 SourceSecurityID=1 IfIndex=0
......
通过检查,就是没有发现从 kubenet 网络的节点转发过来的流量。然后回想到应用上有挂载 networkpolicy,我这边果断删除这个业务 pod 上挂载的 networkpolicy,然后在所有测试点抓包。 全部都通了,现在破案了,应该是 networkpolicy 的问题。
这里又来一个隐含的问题,既然在同一个 k8s 内,有 cilium 网络的节点,也有传统的 kubenet 网络的节点。为什么会出现不通呢?为了验证这个问题,我们又做了如下一个实验,还是上图:
在做这个实验前,有一点可以确认:丢包点是在两种不同的网络模型,并不是外部进入 k8s 集群,所以只要关注 C 点流量。
测试方法跟之间一样,然后我们在不同的点抓包,这次结果也让我惊掉了下巴。
测试内容 | 状态介绍 | 测试点 | 测试结果 |
---|---|---|---|
kubenet 节点上 pod 访问 cilium 节点上业务 pod | 1. 发起请求的测试 pod 运行在 kubenet 节点上 2. 被测试业务 pod 运行在 cilium 节点上 3. 被测试业务 pod 配置有 networkpolicy | C 点 | 失败 |
cilium 节点上 pod 访问 kubenet 节点上业务 pod | 1. 发起请求的测试 pod 运行在 kubenet 节点上 2. 被测试业务 pod 运行在 cilium 节点上 3. 被测试业务 pod 配置有 networkpolicy | B 点 | 成功 |
kubenet 节点上 pod 访问 cilium 节点上业务 pod (去除 cilium 节点上 pod 上的 networkpolicy) | 1. 发起请求的测试 pod 运行在 kubenet 节点上 2. 被测试 pod 运行在 cilium 节点上 3. 删除被测试 pod 的 networkpolicy 4. 被测试 pod 监听 8080 端口 5. 测试 pod 发起 tcp 请求到被测试 pod | C 点 | 成功 |
cilium 节点上 pod 访问 kubenet 节点上业务 pod (去除 cilium 节点上 pod 上的 networkpolicy) | 1. 发起请求的测试 pod 运行在 kubenet 节点上 2. 被测试 pod 运行在 cilium 节点上 3. 删除被测试 pod 的 networkpolicy 4. 测试 pod 监听 8080 端口 5. 被测试 pod 发起 tcp 请求到测试 pod | B 点 | 成功 |
总结下: 从 kubenet 网络的节点上 pod 访问带有 networkpolicy 的 cilium 网络的节点上 pod,是不通,其他的场景都是 OK 的。
技术解析
那么是不是有这样一种猜想,cilium 不识别其他的网络模型的节点呢?让我们看看 cilium cluster 信息:
Cluster health: 15/15 reachable (2022-12-12T08:19:02Z)
Name IP Node Endpoints
10.118.201.53 (localhost) 10.118.201.53 reachable reachable
10.118.201.48 10.118.201.48 reachable reachable
10.118.201.49 10.118.201.49 reachable reachable
10.118.201.50 10.118.201.50 reachable reachable
10.118.201.51 10.118.201.51 reachable reachable
10.118.201.52 10.118.201.52 reachable reachable
10.118.201.54 10.118.201.54 reachable reachable
10.118.201.55 10.118.201.55 reachable reachable
10.118.201.56 10.118.201.56 reachable reachable
10.118.201.57 10.118.201.57 reachable reachable
10.118.201.58 10.118.201.58 reachable reachable
10.118.201.59 10.118.201.59 reachable reachable
10.118.201.60 10.118.201.60 reachable reachable
10.118.201.61 10.118.201.61 reachable reachable
10.118.201.62 10.118.201.62 reachable reachable
通过节点信息,我们可以清楚看出,cilium 只管理部署了 cilium agent 的节点。其他的 kubenet 网络节点他是不管的,也就是这些节点对他来说的跟外部服务器一样,从这些节点传入的网络流量都当成外部流量,即便在同一个 k8s 内,cilium 也不看你流量信息,以及来源哪里。
说到这里,不得不提到之前写一篇文章《ebpf 开发入门之核心概念篇》,那里面提到了一个 HOOK 的概念,networkpolicy 就是通过 HOOK 挂载到容器的网卡的 Ingress 上。既然 kubenet 网络的节点 和 cilium 网络的节点都在同一个 k8s 内,但是 cilium 的只管理自己的节点,其他的节点都认为是外部的,如果不匹配 Ingress 的规则,都会被拒绝。
通过抓包测试,以及分析 cilium 的相关信息,我们找到问题所在:cilium 如果没有管理全部的 k8s 所有节点,剩余的节点就按照外部服务器的方式来处理。
处理方法
知道了原因,有了实验验证,那么办法也当然就有了,当然也很简单。
移动所有的 pod 到 cilium 网络的节点 移动 Ingress pod 到 cilium 网络的节点 删除 cilium 受影响 pod 的 networkpolicy
从解决办法上看,最合理也最有可操作性的是:2 号
最终效果
通过调整后,最终结果当然也复合预期,所有的业务互联互通都没有了问题。同时也在加速 pod 的迁移,尽量减少这样的不合理的共存环境。
你可能还喜欢
点击下方图片即可阅读
2022-12-13
2022-12-10
2022-12-04
2022-12-01
云原生是一种信仰 🤘
关注公众号
后台回复◉k8s◉获取史上最方便快捷的 Kubernetes 高可用部署工具,只需一条命令,连 ssh 都不需要!
点击 "阅读原文" 获取更好的阅读体验!
发现朋友圈变“安静”了吗?