当你值班时,有三种寻呼机通知会让你紧张到出汗:DNS解析出错、证书即将过期和网络故障。
我在Adevinta内部的平台团队工作,该团队负责SCHIP,这是我们的内部运行时平台,帮助开发人员部署和运维他们的应用程序。我所在的团队维护着集群和众多支持服务,从可观测性到安全性,再到网络。
一天晚上,我们收到了一个页面,显示有些DaemonSets失败了。登录到服务器并检查Pod状态后,我们发现错误消息,最担心的事情果然发生了:name="aws-cni" 失败 (添加): 添加命令失败,无法为容器分配IP地址
当SCHIP(你可以在这里了解更多详情)开始时,我们决定让它成为一个多租户集群。作为多租户集群,运行在集群中的pod可能需要与部署在其他AWS账户中的AWS VPC资源(如RDS数据库或ElastiCache)进行通信。这意味着我们需要某种‘连接’来连接集群与内部客户使用的VPC。
当使用如 AWS 所推荐的 EKS 集群,并采用 VPC-CNI 插件 (容器网络接口插件) 时,随着集群规模的扩大,VPC 中使用的 IP 数量将会急剧上升。
这是因为 VPC-CNI 为每个 pod 分配一个 IP 地址。如果你的 EKS 集群开始增长到,比如说,10000 个 pod,它将会使用 10000 个 IP 地址,这将需要一大块 IPv4 地址空间。
VPC 内的 vpc-cni 网络布局,图片来自这篇_AWS博客文章
如果你有好的预测和容量规划,你可以应对这个需求。然而,你的集群可能会出现pod的高峰,比如一个失控的任务或配置错误导致启动了多个失败的任务,这些任务保留分配的IP直到被回收。
几年前,我们在Adevinta开始了EKS的旅程。没过多久,我们发现IP地址资源可能会成为一个问题,于是我们开始监控IP地址的使用情况。
快进到这篇帖子开头提到的那个决定性的寻呼机信息的那天。我们的一些集群由于失败的 pod 出现了问题。网络驱动程序(CNI)的错误非常吓人,明确显示了“没有可用的 IP 地址”。
幸运的是,这次问题只影响了一个相对较小且闲置的集群。不过既然我们已经发现了这个问题,时间在紧迫,我们很快就会面临一次更严重的全集群故障。
在EKS中使用VPC-CNI时出现的IP地址耗尽问题是已知且公开的问题,你可以采取几种解决方案,其中包括AWS给出的建议(https://aws.amazon.com/blogs/containers/addressing-ipv4-address-exhaustion-in-amazon-eks-clusters-using-private-nat-gateways/)。最全面的解决方案描述可以在[这篇文章中找到,列出了所有选项](https://www.tibobeijen.nl/2022/02/09/eks-ips-secondary-cidr-private-natgw/#:~:text=EKS%20和它的IP地址渴望&text=在大多数Kubernetes实现中,都会用到,VPC%20CNI插件的Kubernetes。)。
不过,如果你搜索“VPC CNI IP 耗尽”,你将找到很多相关的博客文章解释这个问题、解决方案以及如何实施(包括这篇文章,希望如此!)
如果你负责集群维护,在使用 AWS 提供的 EKS 创建集群时,需要做出几个网络配置方面的决定。
VPC的布局,包括以下内容:
只要所需都在集群内搞定,就没啥额外网络麻烦了。
但也许在某个时候,你在集群中托管的工作负载需要与其他私有网络的其他部分连接。当这种情况发生时,你需要找到如何从集群私密地连接到外部的VPC,因为网络地址冲突会使连接变得更困难。
结果是你需要维护内部的IPAM以及不同VPC之间的连接方式。最开始,我们只是使用VPC对等连接。但随着这些连接越来越多,我们开始使用TGW来管理更多集群VPC与其他组织VPC之间的连接。这很重要,因为它帮我们解决了IP中断的问题。
我们租户的VPC和SCHIP VPC之间的网络拓扑图,展示出了我们之前通过对等连接,后来我们切换到了传输网关。
六月,我们收到了一条寻呼机消息,在大规模迁移至基于EKS的集群期间。我们的SCHIP分布基于Kube-aws,而运行时团队正在将工作负载迁移到新集群。
关于IP不足的消息虽然让人担忧,但因此影响有限。但我们开始思考如何才能在接下来的迁移中或者在处理更大集群时避免这种情况。我们意识到必须马上采取行动——否则下一次的宕机将会非常严重且不可避免。
在Adevinta的CPR团队里,我们专门留出了时间用于实验。每个双周五,我们都会安排时间来探索任何工程师感兴趣的科技或项目。多年来,我们发现这种“看似无用”的时间实际上给我们带来了巨大的好处,其中一个例子我们在之前的博客文章中写过(为4000名工程师透明地提供ARM节点)。
幸运的是,我们在收到那令人担忧的传呼机消息之前很久就已经花了一些时间来开发解决IP资源耗尽问题的方案。我们已经花了一些时间来开发解决IP资源耗尽问题的方案,一些工程师利用他们的实验时间来测试:
在我们的环境中,使用 Secondary CIDR(次要CIDR)实现自定义网络配置更为简单。因此,虽然这可能不是最优雅的技术选择,但使用Secondary CIDR使我们能够按时完成迁移。
切换到另一个类似的 CNI,比如 Cilium,本可以解决问题,但这也带来了新的挑战和未知因素,需要解决这些问题。
如果将 VPC-CNI 配置为使用 IPv6,我们可以减少一些未知数和挑战,但仍会有一些地方需要时间和资源来解决。
在八月下旬,我们在较小的集群中开始了自定义网络的逐步推出,并取得了令人鼓舞的结果。九月份,由于IP数量不足,我们暂停了迁移。
展示可用IP数量下降趋势以及开始回升的转折点的仪表板。
由于受控推出成功后,我们继续在其他船只上部署自定义网络。
实施我们解决方案后的IP地址空间恢复情况的仪表盘
这使我们能够顺利完成迁移到EKS(亚马逊弹性容器服务),并避免了一场严重影响我们大多数客户和[市场平台]的大规模服务中断。
几个月之后,我们开始了向 Karpenter 的迁移。正如迈克尔·恩德所说,“但那是另一个故事,将在另一个时间讲述”[1],但那个迁移项目, 让我们想起了有限的IP地址问题。
[1] https://adevinta.com/techblog/the-karpenter-effect-redefining-our-kubernetes-operations/
Karpenter 可能会,也可能将提供较小的实例。这是因为(弹性网络接口 ENI 和 IP 地址)的数量取决于实例的大小。这意味着我们再次收到了有关 IP 地址不足的警报消息。
主要问题在于Karpenter并没有意识到我们在使用Secondary CIDR和自定义网络配置。在部署Karpenter时,我们注意到需要添加一个 –reserved-enis 参数。这个设置允许Karpenter计算在考虑到第一个ENI将被用于自定义网络的情况下,一个节点上能容纳多少Pod。
一个拉取请求的内容,使 Karpenter 支持自定义网络的配置,一行之别决定正常与故障。
如果你是一个平台团队或集群维护者,除非你投入时间进行容量规划,否则vpc-cni还没有准备好进行扩展并在生产环境中应用,每个选项都有利有弊。当你开始部署大型集群时,可以考虑使用IPv6,它更经济且更具前瞻性。无论如何,不要认为它在小集群中运行良好就能在扩展后正常运行。