- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章记一次 K8S 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 上发现有以下的规则在其它节点上没有.
其中 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 使用的也少,也就没太多关注,网上短暂搜了一番,描述的也不是很多,看起来大家也用的不多.
那到底是不是因为 hostPort 呢?
Talk is cheap, show me the code 。
通过实验来验证,这里简单使用了三个 nginx 来说明问题, 其中两个使用了 hostPort,这里特意指定了不同的端口,其它的都完全一样,发布到集群中,yaml 文件如下:
Finally,问题复现:
可以肯定,这些规则就是因为使用了 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:
也就是如果使用了 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 的源码中果然是可以看到相应的代码:
所以,最终是调用 portmap 写入的这些规则.
进一步实验发现,hostport 可以通过 iptables 命令查看到, 但是无法在 ipvsadm 中查看到.
使用 lsof/netstat 也查看不到这个端口,这是因为 hostport 是通过 iptables 对请求中的目的端口进行转发的,并不是在主机上通过端口监听.
既然 lsof 跟 netstat 都查不到端口信息,那这个端口相当于没有处于 listen 状态?
如果这时再部署一个 hostport 提定相同端口的应用会怎么样呢?
结论是: 使用 hostPort 的应用在调度时无法调度在已经使用过相同 hostPort 的主机上,也就是说,在调度时会考虑 hostport 。
如果强行让其调度在同一台机器上,那么就会出现以下错误,如果不删除的话,这样的错误会越来越多,吓的作者赶紧删了.
如果这个时候创建一个 nodePort 类型的 svc, 端口也为 31123,结果会怎么样呢?
可以发现,NodePort 是可以成功创建的,同时监听的端口也出现了.
从这也可以说明使用 hostposrt 指定的端口并没有 listen 主机的端口,要不然这里就会提示端口重复之类.
那么问题又来了,同一台机器上同时存在有 hostPort 跟 nodePort 的端口,这个时候如果 curl 31123 时, 访问的是哪一个呢?
经多次使用 curl 请求后,均是使用了 hostport 那个 nginx pod 收到请求.
原因还是因为 KUBE-NODE-PORT 规则在 KUBE-SERVICE 的链中是处于最后位置,而 hostPort 通过 portmap 写入的规则排在其之前.
因此会先匹配到 hostport 的规则,自然请求就被转到 hostport 所在的 pod 中,这两者的顺序是没办法改变的,因此无论是 hostport 的应用发布在前还是在后都无法影响请求转发.
另外再提一下,hostport 的规则在 ipvsadm 中是查询不到的,而 nodePort 的规则则是可以使用 ipvsadm 查询得到.
要想把这些规则删除,可以直接将 hostport 去掉,那么规则就会随着删除,比如下图中去掉了一个 nginx 的 hostport.
另外使用较多的 port-forward 也是可以进行端口转发的,它又是个什么情况呢? 它其实使用的是 socat 及 netenter 工具,网上看到一篇文章,原理写的挺好的,感兴趣的可以看一看.
参考: https://vflong.github.io/sre/k8s/2020/03/15/how-the-kubectl-port-forward-command-works.html 。
一句话,生产环境除非是必要且无他法,不然一定不要使用 hostport,除了会影响调度结果之外,还会出现上述问题,可能造成的后果是非常严重的.
原文链接:https://mp.weixin.qq.com/s?__biz=MzA4Nzg5Nzc5OA==&mid=2651702450&idx=1&sn=3c4c5c10126a9ee92159fc1b3478fe13&chksm=8bcb071bbcbc8e0dc1eacb2ec2e94b9c3769330d9649d798e0fe6e6dcc100f00aeb5e2df470c&mpshare=1& 。
最后此篇关于记一次 K8S HostPort 引发的服务故障排错指南的文章就讲到这里了,如果你想了解更多关于记一次 K8S HostPort 引发的服务故障排错指南的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我想让我的 NSIS 代码更具可读性。 我需要一些关于明智地编写代码部分的指南(比如 C# 中有 #region #endregion)或任何可以使编写 NSIS 代码变得有趣和容易的信息. 请帮帮我
我正在尝试找出Gherkin中所有可用的语法/格式,例如关于多行参数以及我不知道的所有其他内容。 在挖掘Google搜索结果之后,似乎综合指南位于here中: 我以为那很好,并且it链接到一个页面,该
关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。 想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。 5年前关闭。 Improve thi
当我将 guides 添加到 valueAxesSettings 中时,即使我选择 valueAxesSettings 到 valueAxes 中,它也不起作用。此外,valueAxesSetting
我正在寻找有关如何管理 .NET 程序集的三个不同程序集版本号的指针、建议,甚至是口述。 Product 版本是最简单的,因为这似乎通常由业务决定。然后,文件版本似乎用于部署之间的版本控制,其中实际的
昨晚我脑子里冒出一件事。我想知道为什么我们在项目之间仍然有不同的编码风格。由于风格是个人的东西,我认为最好这样对待它。我们为什么不呢?这有什么技术限制吗? 我举几个例子: // Code sample
我有一个应用程序,用户可以在其中从主 Activity 登录,然后可以使用 ListView 浏览实体的层次结构。因此,Activity 堆栈看起来像这样: A -> B -> B -> B -> .
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 9 年前。 Improve
大家好,上个月我开始学习 CSS。我做的第一件事是阅读我能在 www.w3school.com 上找到的所有内容,之后我开始阅读 CSS Mastery 2nd版本。我已经建立了几个自己的网站并取得了
我希望用户能够上传个人资料图片。 关于如何最好地处理这个问题,是否有任何指导方针?例如 - 在哪里保存图像?和要使用的文件夹结构。- 让用户难以浏览每个人的个人资料照片? 谢谢。 最佳答案 如果你自己
我有兴趣了解有关条件重启系统及其工作原理的更多信息。我不知道从哪里开始。我一直在查看源代码,但想知道是否有更高级别的指南可用。 最佳答案 Kent Pitman:条件系统 http://www.nhp
我想将小型、精简且平均的基于 C 的解析器合并到我的 Android 项目中。我过去做过 JNI 编程,但没有在 Android 上进行任何类型的 native (C) 开发。我的计划是将 C lib
免责声明:我试图搜索类似的问题,但是它返回了关于每个 C++ 问题的信息...此外,我将感谢任何可以提出更好标题的人。 C++ 中有两个著名的循环结构:while 和for。 我故意忽略了 do ..
我一直在尝试批量删除 Wordpress 帖子中的垃圾链接,如下所示: . 它们位于 post_content 列下的 wp_posts 表中。我试图通过在 href 标记中添加 % 的通配符来做到这
关闭。这个问题是opinion-based .它目前不接受答案。 想要改进这个问题? 更新问题,以便 editing this post 可以用事实和引用来回答它. 关闭 6 年前。 Improve
我们正在讨论为实体类定义方法的最佳方式 - 作为扩展方法或使用分部类。我们讨论的这类方法不会修改实体的状态,它们是纯粹的“辅助”方法,可以查询状态并返回值。 这两种方法的主要好处是保持实体类干净,同时
您将如何在 Flutter 中在实际屏幕上实现引导层。像这样: 最佳答案 这不是微不足道的。以下是必需的组件: 首先,你必须open a transparent full screen dialog
我们需要通过在 C/C++ 中实现特定算法来解决的大多数科学计算问题都需要远低于 double 的精度。例如,1e-6、1e-7 精度涵盖了 ODE 求解器或数值积分的 99% 情况。即使在我们确实需
我正在研究对专有 UI 框架(用于桌面应用程序)的 RTL 支持,我想知道:是否有关于如何更改小部件渲染的指南? 我正在寻找以下内容的列表: 复选框标签位于复选框左侧,右对齐 工具栏按钮从右到左排列
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我是一名优秀的程序员,十分优秀!