应用零中断部署:滚动更新与优雅下线配置实践

为保障ACK集群应用更新不中断服务,可通过配置Deployment的就绪探针、readinessGates、preStop钩子和SLB优雅中断等,实现流量的平滑迁移,保障业务持续高可用。

工作原理

为确保服务升级时的高可用性,可基于无状态(Deployment)应用的滚动更新(Rolling Update)策略,通过逐个替换Pod的方式确保应用始终存在能够接入流量的Pod。其核心流程可分为以下几个阶段:

  1. 启动阶段:首先,创建新版本(v2)的Pod。Kubernetes会等待新Pod通过就绪检查,确认其能够正常处理请求。在此之前,它不会接收任何来自Service的流量。

  2. 流量切换阶段:启用 readinessGates 后,新Pod需先完成就绪检查,然后将其IP注册到Service关联的Endpoints中,并且同步到负载均衡器(SLB)的后端组才能开始接入流量。随后,系统向旧版本(v1)Pod发送终止信号,并将其IPEndpoints中移除,使其不再接收新的业务请求。

    详细原理解释,请参考readinessGate工作原理
  3. 优雅下线阶段:旧Pod在被彻底删除前,会先执行预定义的preStop钩子,并利用优雅终止宽限期(terminationGracePeriodSeconds)处理完已建立的连接,与此同时SLB也会进行存量连接优雅中断。此过程确保了所有正在处理的请求都能正常完成,最终实现零中断滚动更新。

image

适用范围

部署示例应用

以下为一个Nginx无状态应用的部署示例。

控制台

  1. ACK集群列表页面,单击目标集群名称,在集群详情页左侧导航栏,选择工作负载 > 无状态

  2. 无状态页面,单击使用YAML创建资源,然后将以下内容复制到模板区域,单击创建

    示例应用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
  3. 在弹窗中找到目标无状态应用,单击查看,确认Pod状态为Running。 

kubectl

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 将以下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
  3. 部署Nginx应用并创建服务(Service)。

    kubectl apply -f nginx-demo.yaml
  4. 确认目标应用Pod状态为Running

    kubectl get pod | grep nginx-deployment-demo
  • Pod就绪检查

    • startupProbe (启动探针):用于启动较慢的应用(如Java)检测是否完成启动。启动探测成功前,就绪探针和存活探针不会被执行,防止启动缓慢而被Kubelet误判为失败并重启。

    • readinessProbe (就绪探针):用于判断容器是否准备好处理外部请求。就绪检查成功后,PodIP地址会加入其关联的所有 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%,可填写数字。

验证零中断滚动部署

  1. 获取集群KubeConfig并通过kubectl工具连接集群

  2. 获取示例应用访问地址。

    export NGINX_ENDPOINT=$(kubectl get service nginx-demo-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}{":"}{.spec.ports[0].port}')
    echo $NGINX_ENDPOINT
  3. 安装压测工具hey。进行压力测试,以200的并发度执行50000次请求(按照示例的资源配置单副本运行通常在1分钟左右)。

    hey -c 200 -n 50000  -disable-keepalive http://$NGINX_ENDPOINT

    同时立即开启一个新命令行窗口执行Deployment重启操作。

    kubectl rollout restart deployment nginx-deployment-demo
  4. 预期输出结果对照。

    部署方案类型

    预期输出

    未配置零中断滚动部署

    未配置零中断的YAML示例

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment-demo
    spec:
      replicas: 1                 # 生产环境建议配置2以上保证高可用,此处方便验证滚动部署设置为1
      selector:
        matchLabels:
          app: nginx-demo
      template:
        metadata:
          labels:
            app: nginx-demo 
        spec:
          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
    ---           
    apiVersion: v1
    kind: Service
    metadata:
      name: nginx-demo-service
    spec:
      type: LoadBalancer
      selector:
        app: nginx-demo 
      ports:
        - protocol: TCP
          port: 80

    流量有损。

    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但未就绪状态(Snipaste_2025-11-05_13-57-58

原因说明:通常由于启动探测或就绪探测失败导致。

解决方案

  • 就绪检查配置:进入目标工作负载编辑页,确认健康检查请求路径(如/healthz)和端口与实际应用提供的是否一致。如启动时间较长,可增加不健康阈值,避免过早判定为失败。

    可临时关闭就绪检查,进入Pod终端或其所在宿主机,使用命令(如curl)验证健康检查方法是否能正确响应。
  • 排查业务异常:结合Pod事件日志(勾选显示上个容器退出时的日志)排查。

相关文档