亚马逊AWS官方博客
使用 Readiness Gate 解决 EKS Pod 滚动升级产生的服务中断
背景介绍
AWS LoadBalancer Controller 是帮助一个管理 Kubernetes 集群的ELB的控制器。它可以通过 Kuberentes Server / Ingress 来控制 AWS NLB / ALB.
Amazon VPC CNI Plugin 是一个 AWS 原生 kubernetes 网络插件。它使用 AWS 上的弹性网络接口(ENI)在 Kubernetes 中用于 pod 网络,实现了 Pod IP 通过 ENI 落在 VPC CIDR 内。
在 EKS 中使用 AWS LoadBalancer Controller时,可以通过适当的 Annotations 启用 IP 模式。在这种模式下,AWS NLB / ALB 将流量直接转发到后端 Kubernetes Pods, 尔无须通过 NodePort 等进行额外跳转。
但这带了一个新的问题。
在 Kuberentes Server / Ingress 中启用 Instance 模式而非 IP 模式时,ELB targets 是 Kuberenetes Nodes 的 NodePort, 通过 iptables / IPVS 的方式转发到 Pod IP. 这种情况下升级 Pod 时,在 Kubernetes 内部通过滚动更新就可以完成切换,ELB 无感知。
但使用 IP 模式时,ELB Listener 是 Pod IP,及时 Kubernetes 进行了滚动更新,ELB 的初始化仍会带来服务中断。
测试
单副本模式
让我们进行一个简单的测试,部署一个示例 nginx 应用并更新它。在更新过程中按每秒一次的频率请求 Endpoint 查看状态码:
可以看到从 16:11:43 到 16:13:51,中断了128秒:
这是因为新 Pod Running 之后,就会终止旧的 Pod. 此时在 ELB 中,新的 Pod 还在 initial,旧的 Pod 已经 draining, 此时 ELB 没有 healthy targets 提供服务。
多副本模式
一般情况下,用户都会选择多副本模式提高服务可用性,那么多副本模式会不会改善这个问题?
首先将 Deployment replicas 设置成2:
再进行更新:
可以看到,从 16:32:32 到 16:34:39 中断了 127 秒。多副本对这个问题并无改善。两个新 Pod 都在 initial 状态中,而旧 Pod 都在 draining。
使用 Readiness Gate
Kubernetes 提供了 Pod 就绪态(Readiness),保证 Pod 内业务就绪后才提供服务,减少了服务中断。在 Kubernetes 1.14 中,GA 了 Readiness Gate。通过Pod Readiness Gates,用户可以在 Pod 上设置自定义的ReadinessProbe探测方式,辅助kubernetes判断Pod是否真正到达服务可用状态Ready。
在使用 AWS LoadBalancer Controller 时,可以启用 Readiness Gate,使 EKS 持续监控 ELB Target 状态,直到状态为 healthy 才认为 Pod 已经启动,而非只通过 Pod 状态变为 Running. 这个功能仅适用于 IP 模式,而非 instance 模式,因为 instance 模式下,ELB 无法知道 pod/podReadiness 状态。
部署
想要启用 Readiness Gate 功能很简单,几乎无须额外配置,只需要在 namespace 中添加一个 label:
添加了 label 之后,新启动的 Pod 会自动注入 Readiness Gate 相关配置。对于已存在 pod 可以通过重启的方式自动注入配置。可以通过以下命令检查配置生效:
测试
此时进行同样的更新测试:
可以看到,新 Pod initial 时,旧 Pod 仍在提供服务
因为新 Pod readiness gate 没有就绪,Kubernetes 判断新 Pod 为非就绪状态,旧 Pod 不可以终止
在新 Pod 作为 ELB Target 已经 healthy 后,才会终止对应旧 Pod:
更新好多副本中的一个 Pod 后,再以同样的方式更新下一个 Pod:
最终每个新 Pod 都就绪后,才会完成所有的旧 Pod的删除:
检查一下更新过程中请求的状态码,可以看到状态码均为200,更新过程没有任何中断:
单副本模式测试
如果是单副本模式,readiness gate 仍会提供同样的性能:
我们先将 Deployment replicas 设置为 1,再进行更新。
我们可以看到同样的过程,在新 Pod 在 ELB 中作为 target 状态为 initial 时,会同时运行新旧两个 Pod:
在更新结束后,检查更新过程中的状态吗,均为200,更新过程没有任何中断:
结论
使用 readiness gate 可以在保证 EKS Server/Ingress 的性能的同时,有效提升服务的稳定性,减少服务中断的发生,而又无须复杂配置。建议在条件允许的情况下,使用 IP 模式 AWS LoadBalancer Controller 的用户都启用这个功能。
参考链接:
Pod Readiness Gate – AWS LoadBalancer Controller (kubernetes-sigs.github.io)