记一次 kubernetes HostPort 引发的服务故障排错指南
最近排查了一个 kubernetes 中使用了 hostport 后遇到比较坑的问题,奇怪的知识又增加了。 问题背景 集群环境为 K8s v1.15.9,cni 指定了 flannel-vxlan 跟 portmap, kube-proxy 使用 mode 为 ipvs,集群 3 台 master,同时也是 node,这里以 node-1,node-2,node-3 来表示。集群中有 2 个 mysql, 部署在两个 ns 下,mysql 本身不是问题重点,这里就不细说,这里以 mysql-A,mysql-B 来表示。mysql-A 落在 node-1 上,mysql-B 落在 node-2 上, 两个数据库 svc 名跟用户、密码完全不相同出现诡异的现象这里以一张图来说明会比较清楚一些: 其中绿线的表示访问没有问题,红线表示连接 Mysql-A 提示用户名密码错误特别诡异的是,当在 Node-2 上通过 svc 访问 Mysql-A 时,输入 Mysql-A 的用户名跟密码提示密码错误,密码确认无疑,但当输入 Mysql-B 的用户名跟密码,居然能够连接上,看了下数据,连上的是 Mysql-B 的数据库,给人的感觉就是请求转到了 Mysql-A, 最后又转到了 Mysql-B,当时让人大跌眼镜碰到诡异的问题那就排查吧,排查的过程倒是不费什么事,最主要的是要通过这次踩坑机会挖掘一些奇怪的知识出来。 排查过程 既然在 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 后,使用正确的用户名密码自然可以登录成功原因是找到了,但是又引出来了更多的问题? 这几条规则是谁入到 iptables 中的? 怎么解决呢,是不是删掉就可以?问题复现同样是 Mysql,为何 Mysql-A 没有呢? 那么比对一下这两个 Mysql 的部署差异 比对发现, 除了用户名密码,ns 不一样外,Mysql-B 部署时使用了 hostPort=3306, 其它的并无异常 难道是因为 hostPort? 作者日常会使用 NodePort,倒却是没怎么在意 hostPort,也就停留在 hostPort 跟 NodePort 的差别在于 NodePort 是所有 Node 上都会开启端口,而 hostPort 只会在运行机器上开启端口,由于 hostPort 使用的也少,也就没太多关注