记一次 K8S HostPort 引发的服务故障排错指南

既然在 Node-1 上连接 Mysql-A/Mysql-B 都没有问题,那基本可以排查是 Mysql-A 的问题

经实验,在 Node-2 上所有的服务想要连 Mysql-A 时,都有这个问题,但是访问其它的服务又都没有问题,说明要么是 mysql-A 的 3306 这个端口有问题,通过上一步应该排查了 mysql-A 的问题,那问题只能出在 Node-2 上

在 k8s 中像这样的请求转发出现诡异现象,当排除了一些常见的原因之外,最大的嫌疑就是 iptables 了,作者遇到过多次

这次也不例外,虽然当前集群使用的 ipvs, 但还是照例看下 iptables 规则,查看 Node-2 上的 iptables 与 Node-1 的 iptables 比对,结果有蹊跷, 在 Node-2 上发现有以下的规则在其它节点上没有

-A CNI-DN-xxxx -p tcp -m tcp --dport 3306 -j DNAT --to-destination 10.224.0.222:3306

-A CNI-HOSTPORT-DNAT -m comment --comment “dnat name”: “cni0” id: “xxxxxxxxxxxxx”" -j CNI-DN-xxx

-A CNI-HOSTPORT-SNAT -m comment --comment “snat name”: “cni0” id: “xxxxxxxxxxxxx”" -j CNI-SN-xxx

-A CNI-SN-xxx -s 127.0.0.1/32 -d 10.224.0.222/32 -p tcp -m tcp --dport 80 -j MASQUERADE

其中 10.224.0.222 为 Mysql-B 的 pod ip, xxxxxxxxxxxxx 经查实为 Mysql-B 对应的 pause 容器的 id

从上面的规则总结一下就是目的为 3306 端口的请求都会转发到 10.224.0.222 这个地址,即 Mysql-B

看到这里,作者明白了为什么在 Node-2 上去访问 Node-1 上 Mysql-A 的 3306 会提示密码错误而输入 Mysql-B 的密码却可以正常访问

虽然两个 mysql 的 svc 名不一样,但上面的 iptables 只要目的端口是 3306 就转发到 Mysql-B 了,当请求到达 mysql 后,使用正确的用户名密码自然可以登录成功

原因是找到了,但是又引出来了更多的问题?

  1. 这几条规则是谁入到 iptables 中的?

  2. 怎么解决呢,是不是删掉就可以?

问题复现


同样是 Mysql,为何 Mysql-A 没有呢? 那么比对一下这两个 Mysql 的部署差异

比对发现, 除了用户名密码,ns 不一样外,Mysql-B 部署时使用了 hostPort=3306, 其它的并无异常

难道是因为 hostPort?

作者日常会使用 NodePort,倒却是没怎么在意 hostPort,也就停留在 hostPort 跟 NodePort 的差别在于 NodePort 是所有 Node 上都会开启端口,而 hostPort 只会在运行机器上开启端口,由于 hostPort 使用的也少,也就没太多关注,网上短暂搜了一番,描述的也不是很多,看起来大家也用的不多

那到底是不是因为 hostPort 呢?

Talk is cheap, show me the code

通过实验来验证,这里简单使用了三个 nginx 来说明问题, 其中两个使用了 hostPort,这里特意指定了不同的端口,其它的都完全一样,发布到集群中,yaml 文件如下

apiVersion: apps/v1

kind: Deployment

metadata:

name: nginx-hostport2

labels:

k8s-app: nginx-hostport2

spec:

replicas: 1

selector:

matchLabels:

k8s-app: nginx-hostport2

template:

metadata:

labels:

k8s-app: nginx-hostport2

spec:

nodeName: spring-38

containers:

  • name: nginx

image: nginx:latest

ports:

  • containerPort: 80

hostPort: 31123

Finally,问题复现:

v2-219265984de187c8fb1fc01f68e93d4a_b.jpg

可以肯定,这些规则就是因为使用了 hostPort 而写入的,但是由谁写入的这个问题还是没有解决?

罪魁祸首


作者开始以为这些 iptables 规则是由 kube-proxy 写入的, 但是查看 kubelet 的源码并未发现上述规则的关键字

再次实验及结合网上的探索,可以得到以下结论:

首先从 kubernetes 的官方发现以下描述:

The CNI networking plugin supports hostPort. You can use the official portmap[1] plugin offered by the CNI plugin team or use your own plugin with portMapping functionality.

If you want to enable hostPort support, you must specify portMappings capability in your cni-conf-dir. For example:

{

“name”: “k8s-pod-network”,

“cniVersion”: “0.3.0”,

“plugins”: [

{

…其它的plugin

}

{

“type”: “portmap”,

“capabilities”: {“portMappings”: true}

}

]

}

也就是如果使用了 hostPort, 是由 portmap 这个 cni 提供 portMapping 能力,同时,如果想使用这个能力,在配置文件中一定需要开启 portmap,这个在作者的集群中也开启了,这点对应上了

另外一个比较重要的结论是:

The CNI ‘portmap’ plugin, used to setup HostPorts for CNI, inserts rules at the front of the iptables nat chains; which take precedence over the KUBE- SERVICES chain. Because of this, the HostPort/portmap rule could match incoming traffic even if there were better fitting, more specific service definition rules like NodePorts later in the chain

参考: https://ubuntu.com/security/CVE-2019-9946

翻译过来就是使用 hostPort 后,会在 iptables 的 nat 链中插入相应的规则,而且这些规则是在 KUBE- SERVICES 规则之前插入的,也就是说会优先匹配 hostPort 的规则,我们常用的 NodePort 规则其实是在 KUBE- SERVICES 之中,也排在其后

从 portmap 的源码中果然是可以看到相应的代码

v2-a00777743d5e8894a2ff8adca0dfaaff_b.jpg

所以,最终是调用 portmap 写入的这些规则。

端口占用


进一步实验发现,hostport 可以通过 iptables 命令查看到, 但是无法在 ipvsadm 中查看到

使用 lsof/netstat 也查看不到这个端口,这是因为 hostport 是通过 iptables 对请求中的目的端口进行转发的,并不是在主机上通过端口监听

v2-d1aca0f37d7a8a70ada1c58bac23ca26_b.png

既然 lsof 跟 netstat 都查不到端口信息,那这个端口相当于没有处于 listen 状态?

如果这时再部署一个 hostport 提定相同端口的应用会怎么样呢?

结论是: 使用 hostPort 的应用在调度时无法调度在已经使用过相同 hostPort 的主机上,也就是说,在调度时会考虑 hostport

如果强行让其调度在同一台机器上,那么就会出现以下错误,如果不删除的话,这样的错误会越来越多,吓的作者赶紧删了.

v2-087c34860644b47d0f9054991988e113_b.jpg

如果这个时候创建一个 nodePort 类型的 svc, 端口也为 31123,结果会怎么样呢?

apiVersion: apps/v1

kind: Deployment

总结

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

**另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 **

下面有部分截图希望能对大家有所帮助。

在这里插入图片描述

找小编(vip1024c)领取
么样呢?

apiVersion: apps/v1

kind: Deployment

总结

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。

**另外本人还整理收藏了2021年多家公司面试知识点以及各种技术点整理 **

下面有部分截图希望能对大家有所帮助。

[外链图片转存中…(img-bA5v3Wdp-1721730432177)]

找小编(vip1024c)领取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值