为保障ACK集群应用更新不中断服务,可通过配置Deployment的就绪探针、readinessGates、preStop钩子和SLB优雅中断等,实现流量的平滑迁移,保障业务持续高可用。
工作原理
为确保服务升级时的高可用性,可基于无状态(Deployment)应用的滚动更新(Rolling Update)策略,通过逐个替换Pod的方式确保应用始终存在能够接入流量的Pod。其核心流程可分为以下几个阶段:
启动阶段:首先,创建新版本(v2)的Pod。Kubernetes会等待新Pod通过就绪检查,确认其能够正常处理请求。在此之前,它不会接收任何来自Service的流量。
流量切换阶段:启用
readinessGates后,新Pod需先完成就绪检查,然后将其IP注册到Service关联的Endpoints中,并且同步到负载均衡器(SLB)的后端组才能开始接入流量。随后,系统向旧版本(v1)Pod发送终止信号,并将其IP从Endpoints中移除,使其不再接收新的业务请求。详细原理解释,请参考readinessGate工作原理。
优雅下线阶段:旧Pod在被彻底删除前,会先执行预定义的preStop钩子,并利用优雅终止宽限期(
terminationGracePeriodSeconds)处理完已建立的连接,与此同时SLB也会进行存量连接优雅中断。此过程确保了所有正在处理的请求都能正常完成,最终实现零中断滚动更新。
适用范围
集群版本为1.24及以上,请参见升级集群。
cloud-controller-manager组件为v2.10.0或更高版本,请参见Cloud Controller Manager。
部署示例应用
以下为一个Nginx无状态应用的部署示例。
控制台
在ACK集群列表页面,单击目标集群名称,在集群详情页左侧导航栏,选择。
在无状态页面,单击使用YAML创建资源,然后将以下内容复制到模板区域,单击创建。
在弹窗中找到目标无状态应用,单击查看,确认Pod状态为
Running。
kubectl
将以下YAML内容保存为nginx-demo.yaml文件。
apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment-demo spec: replicas: 1 # 生产环境建议配置2以上保证高可用,此处方便验证滚动部署设置为1 selector: matchLabels: app: nginx-demo # 滚动更新策略:保证更新期间服务不中断, # strategy: # type: RollingUpdate # Deployment工作负载默认为RollingUpdate策略 # rollingUpdate: # maxUnavailable: "25%" # 默认值,更新过程中最多允许25%的Pod副本处于不可用状态 # maxSurge: "25%" # 默认值,更新过程中允许创建的Pod总数最多可超出期望副本数的 25% template: metadata: labels: app: nginx-demo spec: # Pod级别的优雅下线总时限。必须大于 preStop 钩子执行时间与应用清理时间之和 terminationGracePeriodSeconds: 60 readinessGates: - conditionType: service.readiness.alibabacloud.com/nginx-demo-service # 设置nginx-demo-service服务的Readiness Gate containers: - name: nginx image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6 ports: - containerPort: 80 resources: requests: cpu: 500m memory: 1Gi limits: cpu: 500m # --- 健康检查探针 --- # 启动探针 (Startup Probe): 确保容器内应用已完成启动 startupProbe: httpGet: path: / # Nginx默认根路径可访问即代表启动成功 port: 80 # 给予应用足够长的启动时间。总超时 = failureThreshold * periodSeconds # 总超时时间为 failureThreshold * periodSeconds,即 30 * 10 = 300 秒 failureThreshold: 30 periodSeconds: 10 # 就绪探针 (Readiness Probe): 判断容器是否准备好接收流量 readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 # 容器启动后5秒开始探测 periodSeconds: 5 # 每5秒探测一次 timeoutSeconds: 2 # 探测超时时间 successThreshold: 1 # 1次成功即标记为就绪 failureThreshold: 3 # 连续3次失败即标记为不就绪 # --- 服务优雅下线配置 --- lifecycle: preStop: exec: # 建议根据业务自行设置钩子方法,等待存量连接处理完成然后关闭应用 # 若只使用sleep命令可能会导致优雅下线无法正常退出 command: ["sh", "-c", "sleep 30 && /usr/sbin/nginx -s quit"] --- apiVersion: v1 kind: Service metadata: name: nginx-demo-service annotations: # 设置连接优雅中断超时时间,此值应接近应用preStop中处理存量连接的时长,取值范围[10, 900] service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout: "30" # 开启连接优雅中断功能 service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain: "on" spec: type: LoadBalancer selector: app: nginx-demo ports: - protocol: TCP port: 80部署Nginx应用并创建服务(Service)。
kubectl apply -f nginx-demo.yaml确认目标应用Pod状态为
Running。kubectl get pod | grep nginx-deployment-demo
Pod就绪检查
startupProbe(启动探针):用于启动较慢的应用(如Java)检测是否完成启动。启动探测成功前,就绪探针和存活探针不会被执行,防止启动缓慢而被Kubelet误判为失败并重启。readinessProbe(就绪探针):用于判断容器是否准备好处理外部请求。就绪检查成功后,Pod的IP地址会加入其关联的所有 Service 的Endpoints中,表示可以接入流量。readinessGates:在readinessProbe的基础上等待readinessGates的状态也可用时,才视为Pod完全就绪,然后正式接入流量。
优雅下线
应用优雅下线
preStop:容器终止前执行的钩子命令,可设置应用优雅下线的命令,确保存量连接处理完成,保障服务无损下线。建议根据业务自行设置钩子方法,若只使用sleep命令可能会导致优雅下线无法正常退出。
terminationGracePeriodSeconds:Pod从被标记为终止到被强制杀死(SIGKILL信号)前的总时长,默认为30秒。该值必须充足,以覆盖preStop钩子的执行时间与容器自身清理时间之和。
SLB连接优雅中断
service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain注解:为SLB开启连接优雅中断功能。service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout注解:SLB存量连接优雅中断超时时长(单位:秒)。建议配置为接近preStop中处理存量连接请求的时长。
滚动更新策略
strategy:Deployment的默认更新策略为RollingUpdate,采用渐进式替换方式,逐步创建新版本Pod,并在新Pod就绪后删除对应的旧版本Pod,确保服务在更新过程中持续可用。maxUnavailable:滚动更新过程中最大不可用Pod副本数。默认值25%,可填写数字。maxSurge:滚动更新过程中,允许超出期望副本数的 Pod 数量上限。配置越大,更新速度越快,但占用资源更多。默认值25%,可填写数字。
验证零中断滚动部署
获取示例应用访问地址。
export NGINX_ENDPOINT=$(kubectl get service nginx-demo-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}{":"}{.spec.ports[0].port}') echo $NGINX_ENDPOINT安装压测工具hey。进行压力测试,以200的并发度执行50000次请求(按照示例的资源配置单副本运行通常在1分钟左右)。
hey -c 200 -n 50000 -disable-keepalive http://$NGINX_ENDPOINT同时立即开启一个新命令行窗口执行Deployment重启操作。
kubectl rollout restart deployment nginx-deployment-demo预期输出结果对照。
部署方案类型
预期输出
未配置零中断滚动部署
流量有损。
Status code distribution: [200] 49644 responses Error distribution: [320] Get "http://114.215.XXX.XXX": dial tcp 114.215.XXX.XXX:80: connect: connection refused [18] Get "http://114.215.XXX.XXX": dial tcp 114.215.XXX.XXX:80: connect: no route to host [18] Get "http://114.215.XXX.XXX": dial tcp 114.215.XXX.XXX:80: connect: operation timed out已配置零中断滚动部署
流量无损。
Status code distribution: [200] 50000 responses
常见问题
Pod启动时一直处于Running但未就绪状态(
)
原因说明:通常由于启动探测或就绪探测失败导致。
解决方案:
就绪检查配置:进入目标工作负载的编辑页,确认健康检查请求路径(如/healthz)和端口与实际应用提供的是否一致。如启动时间较长,可增加不健康阈值,避免过早判定为失败。
可临时关闭就绪检查,进入Pod终端或其所在宿主机,使用命令(如curl)验证健康检查方法是否能正确响应。
排查业务异常:结合Pod事件和日志(勾选显示上个容器退出时的日志)排查。