使用Kubernetes三年,我们从中学到了什么?( 二 )


不仅需要维护代码 , 还需要策略来维护Kubernetes部署文件、Docker文件、Docker镜像和Helm图表 , 并设计一种将它们链接起来的方法 。
在几次迭代后我们有了如下设计:放置应用程序代码及其Helm图表于单独的git存储库中 , 这使我们可以分别对它们进行版本控制 。 (语义版本号)
然后 , 我们将图表版本的地图与应用程序版本一起保存 , 并使用它来跟踪发布 。 例如 , 将app-1.2.0与charts-1.1.0一起部署 。 如果仅更改Helm值文件 , 则仅更改图表的补丁程序版本(例如 , 从1.1.0到1.1.1) 。 所有这些版本均由每个存储库RELEASE.txt发行说明 。
Apache Kafka或Redis的代码之类的系统应用程序的工作方式有所不同 , 我们未构建或修改其代码 。 也就是说 , 由于Docker标签只是Helm chart版本控制的一部分 , 我们没有两个git存储库 。 如果我们曾经更改了docker标签进行升级 , 我们将在图表标签中增加主要版本 。
4.存活和就绪探针(双刃剑)
Kubernetes的存活和就绪探针是能自动解决系统问题的出色功能点 。 可以在发生故障时重新启动容器 , 并将流量从异常事故中转移 。 但在某些故障情况下 , 探针可能是双刃剑 , 并影响应用程序的启动和恢复 , 尤其是有状态应用程序 , 例如消息平台或数据库 。
Kafka系统就是受害者 。 我们运行了一个有replicationFactor of 3 和minInSyncReplica of 2的 3 Broker 3 Zookeeper状态集 , 当系统意外故障或崩溃导致Kafka启动时会发生此问题 。 这导致它在启动期间运行其他脚本来修复损坏的索引 , 根据严重程度不同 , 该过程可能需要10到30分钟 。
由于时间耗费增加 , 存活探针将不断失败 , 从而向Kafka发出终止信号以重新启动 , 这一并阻止了Kafka系统修改索引和完全启动 。
唯一的解决方案是在存活探针设置中设置 initialDelaySeconds , 从而在容器启动后延迟探针评估 。 但是问题在于当然很难给出具体时间 , 有些恢复甚至需要一个小时 , 因此我们需要留足空间来计算时间 。 但是initialDelaySeconds增加的时间越多 , 速度就越慢 , 因为启动失败时Kubernetes需要更长的时间来重新启动容器 。
最新的几个版本中 , Kubernetes引入了第三种探针“启动探针”来解决这个问题 。 在alpha from 1.16 和 beta from 1.18 中都可用 。 启动探针可以使存活和就绪探针在容器启动前停止运行 , 保证应用程序的启动不受干扰 。
5.公开外部IP
使用Kubernetes三年,我们从中学到了什么?文章插图
图源:unsplash
我们了解到 , 使用静态外部IP公开服务会极大损害内核的连接跟踪机制 。 除非详细计划 , 否则它只会大规模崩溃 。
集群在Calico for CNI和BGP运行 , 作为Kubernetes内部路由协议 , 并与边缘路由器搭配 。 而Kubeproxy , 我们使用IP Tables模式 。 我们在Kubernetes有着庞大的服务 , 该服务通过外部IP公开 , 每天处理数百万个连接 。
所有的源网络地址转换(NAT)和伪装来自软件定义网络 , Kubernetes需要一个机制来跟踪所有逻辑流 。 为此 , 它使用内核的Conntrack and netfilter工具来管理与静态IP的外部连接 , 接着将其转换为内部服务IP , 再转为pod IP 。 这些都通过conntrack表和IP表完成 。
但这个conntrack表有限制 。 当达到极限时 , Kubernetes集群(下有OS内核)将不能接受新连接 。 在RHEL上 , 可以通过这种方式进行检查:
$sysctlnet.netfilter.nf_conntrack_countnet.netfilter.nf_conntrack_maxnet.netfilter.nf_conntrack_count = 167012net.netfilter.nf_conntrack_max = 262144解决该问题的方法是匹配带有边缘路由器的多个节点 , 使你的静态IP的传入连接遍及整个群集 。 因此 , 如果集群中有大量虚拟机 , 累积起来就可以拥有一个大的conntrack表来处理大量的传入连接 。