坏消息是,你可以安装更新的Kubernetes,但无法与工作节点联网。好消息是,Mirantis的一位工程师发现了一些修复方法,并正在分享。
没有什么比建立一个全新的Kubernetes集群、部署它更重要的了,但如果工作节点失去网络连接,你不能用ssh连接它们,不能ping它们——它们“消失了”。
发现问题
当然,它们实际上并没有消失;你就是找不到它们。9月中旬这一问题被发现,大家开始找解决的办法。
事实证明,问题是iptables(默认的Linux防火墙程序)与安装的iptables kube路由器1.25版本存在冲突。
问题的核心是iptables 1.8.8在某些规则上打破了与旧版本的兼容性。当使用iptables 1.8.8创建新的“-m标记”规则时,旧版本的iptables无法正确读取该规则:这实际上是预期结果。根本原因是,较新的iptables nft使用本地nftables表达式来匹配数据包标记,而较旧的iptablesnft使用内核中的xtables扩展。netfilter开发人员不希望用户运行两个不同版本的iptable。当然,对于容器,这种情况经常发生。
正如Mirantis软件工程师Jussi Nummelin解释的那样,“如果主机使用iptables 1.8.8,当kube-router CNI等组件开始使用旧版本的iptables编写自己的网络策略和规则时(kube路由器附带iptables 1.8.7),一切都很顺利!因为kubelet通过主机提供的iptable 1.8.8写道:
-一个KUBE-FIREWALL-m comment–comment“kubernetes FIREWALL for DROP marked packets”-m mark–mark 0x8000/0x8000-j DROP
然后,kube路由器使用kube代理提供的早期版本的iptables,执行正常的iptable保存;修改/添加规则;iptables恢复,但使用旧版本执行此操作会导致读取并重新插入规则:
-A KUBE-FIREWALL-m comment–comment“kubernetes FIREWALL for droping marked packets”-j DROP
明白了吗?作为一名网络管理员,笔者会解释发生了什么。因为该规则“已损坏”,它会阻止主机上的所有网络流量。或者,正如Nummelin所说,“当你甚至不能ping本地主机时,你就知道有麻烦了。”
此外,Nummelin解释道,“虽然在这个特定情况下,我们使用的是kube路由器,但所有这一切实际上都可能发生在任何其他在pods/容器中使用iptables的网络组件上。
是的,Kubernetes的网络非常脆弱。
修复方法是“确保每个网络组件实际上使用与主机相同版本的iptables,并且所有这些组件也使用相同的后端(传统版与nftables)。”
那么为什么我们需要相同的版本呢?难道Kubernetes就不能补偿吗?不,不,它不能。这是因为,Nummelin说,“netfilter团队对版本兼容性真的没有任何保证。”(尤其是iptables团队,特别不能保证向后兼容性,因为它是一个容器时代之前的工具,它是基于一个假设,即主机上永远不会有多个版本的iptables。)
这很公平。毕竟,Netfilter和IPTable可以追溯到1999年。而且,如果你认为它们很糟糕,你永远不用使用它们的前身ipchains。
解决之道
那么你能做什么呢?
在Mirantis的Kubernetes发行版k0s中,他们通过以下方式缓解了这个问题:
——使用iptables wrappers脚本检测iptables模式:这为我们提供了最大的可能性,让一切以相同的模式工作。
——将iptables二进制文件与k0s一起发布:这样一来,操作系统升级就不会破坏一切,因为k0s从不依赖操作系统提供的版本。
——用k0s发布iptables 1.8.7:通过这种方式,与其他组件保持同步,并实际测试组合。
如果你不使用k0s,有一些其他选项:
——将主机上的iptables降级到1.8.7以消除不兼容性。
——使用–feature gates=IPTablesOwnershipCleanup=true运行kubelet,这将导致它不会创建有问题的“-j DROP”规则。正如Dan Winship在Github上指出的那样,“当然,这是一个alpha特性,你可能会遇到假设kubelet仍然创建这些规则的组件的问题,但如果你创建了这些规则,那么你可以报告问题并帮助KEP前进。”
笔者阅读了GitHub对Kubernetes和IPTables的评论。似乎没有任何一个能让Kubernetes用户满意的修复方案。所以,就目前而言,笔者认为将主机iptables降级到1.8.7是最好的做法。