我是 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 的迁移,尽量削减这样的不合理的共存环境。