通过配置Readiness Gate确保Pod平滑更新

在使用LoadBalancer类型的Service暴露后端Pod时,当Pod进行滚动更新,可能会由于Pod更新速度快于负载均衡器后端服务器组的挂载速度而导致访问中断。您可以通过配置Readiness Gate来确保Pod的平滑更新。本文将介绍如何使用Pod Readiness Gate机制实现Pod平滑更新。

前提条件

使用说明

当您的Service通过LoadBalancer方式暴露后端Pod时,Pod进行滚动更新可能会导致服务短暂中断。当使用 LoadBalancer 类型的 Service 暴露应用,并在进行滚动更新(Rolling Update)时,可能会遇到短暂的服务中断或连接失败。

  • 问题原因

    新 Pod 的启动速度通常快于负载均衡更新后端服务器列表的速度。在新 Pod 容器已就绪、但其 IP 尚未被添加到负载均衡后端时,滚动更新机制可能已经开始终止旧 Pod。这导致部分请求流量仍被导向正在终止或已从负载均衡移除的旧 Pod,从而引发访问失败。

  • 解决方案

    可在Pod YAML配置中Pod Readiness Gate机制,通过自定义条件控制Pod的就绪状态。Readiness Gate允许设置自定义条件(例如与LoadBalancer Service相关的service.readiness.alibabacloud.com/<Service Name>)。只有当这些条件满足时,Pod才会被标记为Ready,并开始正式接收流量。

  • 操作示例步骤

    image
  • 工作原理

    当 Pod 配置 readinessGates 后,其就绪流程如下:

    1. 容器探针就绪 kubelet运行容器的 readinessProbe。探针成功后,Pod 的 ContainersReady 状态变为 True。此时,Pod 整体仍为非就绪状态,等待其它Readiness Gate状态的确认。

    2. CCM添加后端 CCM 监测到容器就绪后,将该 Pod 的 IP 地址添加到指定负载均衡的后端服务器组中。添加成功后,CCM 会为Pod添加对应ServiceCondition(如service.readiness.alibabacloud.com/my-svc),并将其状态设置为True

    3. Pod 最终就绪 kubelet确认所有 Readiness Gate 条件均为 True 后,将 Pod 的最终 Ready 状态设置为 True。至此,Pod 才被正式视为就绪,同时滚动更新流程可以安全地终止旧 Pod。

  • 注意事项

    • Service 必须存在: 确保 readinessGates 中引用的 Service 名称正确无误,并且该 Service 真实存在于集群中。如果 Service 名称错误或在 Pod 启动期间被删除,CCM 无法完成添加后端的操作,Pod 将永远无法达到 Ready 状态,导致部署流程卡住。

    • 支持多个 Service: 一个 Pod 需要配置多个 readinessGates,对应挂载到多个不同的 LoadBalancer Service。此时,Pod 必须被成功添加到所有 Service 的后端后,才会最终变为就绪状态。

步骤一:创建负载均衡服务

  1. 参见以下示例YAML内容,创建名为my-svc.yaml文件,按需创建传统型负载均衡CLB或网络型负载均衡NLB实例。

    CLB

    apiVersion: v1
    kind: Service
    metadata:
      name: my-svc
    spec:
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: nginx
      type: LoadBalancer

    NLB

    apiVersion: v1
    kind: Service
    metadata:
      name: my-svc
      annotations:
        service.beta.kubernetes.io/alibaba-cloud-loadbalancer-zone-maps: "${zone-A}:${vsw-A},${zone-B}:${vsw-B}" # 例如cn-hangzhou-k:vsw-i123456,cn-hangzhou-j:vsw-j654321。
    spec:
      loadBalancerClass: alibabacloud.com/nlb # 指定负载均衡类型为NLB。
      ports:
      - port: 80
        targetPort: 80
        protocol: TCP
      selector:
        app: nginx
      type: LoadBalancer
  2. 执行以下命令,创建示例Service。

    kubectl apply -f my-svc.yaml
  3. 执行以下命令,查看当前Service状态。

    kubectl get service my-svc

    等待出现<IP地址域名>后,即可确认对应的负载均衡实例已创建完成。

    NAME     TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)        AGE
    my-svc   LoadBalancer   192.XX.XX.215   <IP地址域名>     80:30493/TCP   8s

步骤二:创建示例Deployment

  1. 使用以下示例PodYAML内容,创建一个名为my-nginx.yaml的文件,且Readiness GateconditionType设置为service.readiness.alibabacloud.com/my-svc

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-nginx    # 示例名称。
      labels:
        app: nginx
    spec:
      replicas: 2       # 设置副本数量。
      selector:
        matchLabels:
          app: nginx     # 对应服务中Selector的值需要与其一致,才可以通过服务公开。
      template:
        metadata:
          labels:
            app: nginx
        spec:
          readinessGates:
          - conditionType: service.readiness.alibabacloud.com/my-svc # 设置my-svc服务的Readiness Gate
          containers:
          - name: nginx
            image: anolis-registry.cn-zhangjiakou.cr.aliyuncs.com/openanolis/nginx:1.14.1-8.6
            ports:
            - containerPort: 80                                # 需要在服务中暴露该端口。
  2. 执行以下命令,部署示例Deployment。

    kubectl apply -f my-nginx.yaml
  3. 执行以下命令,查看Pod以及Readiness Gate状态。

    kubectl get pod -owide -l app=nginx

    预期输出:

    NAME                       READY   STATUS    RESTARTS   AGE   IP               NODE                         NOMINATED NODE   READINESS GATES
    my-nginx-d9f95dcf9-8dhwj   1/1     Running   0          14s   172.XX.XXX.188   cn-hangzhou.172.XX.XXX.174   <none>           0/1
    my-nginx-d9f95dcf9-z9hjm   1/1     Running   0          14s   172.XX.XXX.182   cn-hangzhou.172.XX.XXX.174   <none>           0/1

    多次执行该命令后,可以观察到PodReadiness Gate状态从0变为1,表明Pod已成功挂载到负载均衡服务器组中。

步骤三:滚动更新Deployment

  1. 执行以下命令,重新部署示例Deployment。

    kubectl rollout restart deployment my-nginx

    预期输出:

    deployment.apps/my-nginx restarted
  2. 执行以下命令,查看Pod以及Readiness Gate状态。

    kubectl get pod -owide -l app=nginx

    预期输出:

    NAME                       READY   STATUS    RESTARTS   AGE    IP               NODE                         NOMINATED NODE   READINESS GATES
    my-nginx-d9f95dcf9-8dhwj   1/1     Running   0          113s   172.XX.XXX.188   cn-hangzhou.172.XX.XXX.174   <none>           1/1
    my-nginx-df5c9cf7d-6p5jc   1/1     Running   0          6s     172.XX.XXX.182   cn-hangzhou.172.XX.XXX.174   <none>           0/1
    my-nginx-df5c9cf7d-7dh2v   1/1     Running   0          15s    172.XX.XXX.189   cn-hangzhou.172.XX.XXX.174   <none>           1/1

    多次执行该命令时,可以观察到在滚动更新过程中,Pod会等待就绪状态的Readiness Gate。只有当Readiness Gate就绪,表明Pod已成功挂载到负载均衡服务器组中,滚动更新才会继续进行。