CCI 2.0应用进行优雅滚动升级
应用场景
用户在云容器实例 CCI 2.0中部署工作负载时,应用发布为LoadBalancer类型的Service且对接的独享型ELB,经过ELB的访问流量支持直通到容器中,应用进行滚动升级或者弹性扩缩容时,可以配置容器探针、最短就绪时间等实现优雅升级和优雅弹性扩缩容,避免升级或扩缩容过程中出现5xx的错误响应。
场景 |
措施 |
---|---|
Deployment升级 |
滚动升级+存活/就绪探针+优雅终止 |
Deployment缩容 |
存活/就绪探针+优雅终止 |
- 滚动升级
Deployment可以采用滚动升级的升级方式,会对各个实例逐步进行更新,并非同时对所有实例进行全部更新,可以控制Pod的更新速度和并发数,从而确保了升级过程中业务不中断。例如,可以设置maxSurge和maxUnavailable参数,控制同时创建的新Pod数量和同时删除的旧Pod数量。确保升级过程中始终有工作负载能够提供服务。
示例:配置最大浪涌(maxSurge)为25%,最大无效实例数(maxUnavailable)为25%,假设Deployment的副本数为2,那实际升级过程中,maxSurge允许最多3个Pod存在(向上取整,2*1.25=2.5,取整为3),而maxUnavailable则不允许有Pod Unavailable(向下取整,2*0.25=0.5,取整为0),也就是说在升级过程中,不允许有Pod处于非运行状态,每次新建一个Pod,待新的Pod创建成功后再删掉一个旧的Pod,直至Pod全部为新Pod。
- 设置存活/就绪探针
存活探针可以用来确定什么时候需要重启容器,如果容器的存活检查的结果为失败,云容器实例会对该容器执行重启操作,有利于提高应用的可用性。
就绪探针可以知道容器何时准备好接口请求流量,若Pod尚未就绪,将会被从负载均衡器后端服务器组中剔除。
- 优雅终止
负载升级或缩容过程中,负载均衡器会将正在终止的pod从后端服务器组中移除,但会保持还在处理的请求的连接。如果后端服务Pod在收到结束信号后立即退出,可能会导致正在处理的请求失败或部分流量仍被转发到已经退出的Pod中,导致流量损失和服务中断。为了避免这种情况,建议在后端服务的Pod中配置优雅删除时间(terminationGracePeriodSeconds)和preStop Hook。
优雅删除时间(terminationGracePeriodSeconds):默认为30秒,删除Pod时发送SIGTERM终止信号,然后等待容器中的应用程序终止执行。如果在terminationGracePeriodSeconds时间内未能终止,则发送SIGKILL的系统信号强行终止。
如果用户的业务代码中没有处理SIGTERM信号,也可以尝试为Pod配置preStop Hook,在Pod被移除后继续工作一段时间,以解决流量中断的问题。
建议用户在业务代码中对SIGTERM信号进行处理,实现优雅终止,同时也可以利用preStop先sleep一会,等待 kube-proxy 完成规则同步再开始停止容器内进程。用户可根据实际情况自定义优雅删除时间(preStop + 业务进程停止可能超过30s),避免过早被SIGKILL信号强行终止。
操作步骤
以部署nginx无状态工作负载为例,在云容器实例 CCI 2.0中进行优雅滚动升级或者弹性扩缩容。
- 在云容器实例 CCI2.0控制台,单击左侧导航栏中的“负载管理 > 无状态负载”,单击左上角“YAML创建”。
- 参考以下yaml示例创建负载:
kind: Deployment apiVersion: cci/v2 metadata: name: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:latest ports: - containerPort: 80 resources: limits: cpu: 500m memory: 1Gi requests: cpu: 500m memory: 1Gi livenessProbe: # 存活探针 httpGet: # 以HTTP请求检查为例 path: / # HTTP检查路径为/ port: 80 # 检查端口为80 initailDelySeconds: 5 periodSeconds: 5 readinessProbe: # 就绪探针,该配置是检查用户业务是否就绪,不就绪则不转发流量到当前实例。 httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 5 lifecycle: preStop: # 停止前处理,该配置是保证业务容器在退出过程中能够对外提供服务。 exec: command: - /bin/bash - '-c' - sleep 30 dnsPolicy: Default imagePullSecrets: - name: imagepull-secret strategy: type: RollingUpdate rollingUpdate: maxUnavailable: 0 # 滚动升级期间最多容忍的不可用的pod数量 maxSurge: 100% # 滚动升级期间可冗余的pod比例 minReadySeconds: 10 # 最小就绪时间,用于指定新创建的Pod在没有任意容器崩溃情况下的最小就绪时间,只有超出这个时间Pod才被视为可用。
- 推荐的配置minReadySeconds时长,为业务容器的启动预期时间加上ELB服务下发member到生效的时间。
- minReadySeconds的时长需要小于sleep时长,保证旧的容器停止并退出之前,新的容器已经准备就绪。
- 配置完成后,对应用进行升级和弹性扩缩容的测试。
准备一台集群外的客户端节点,预置检测脚本detection_script.sh,内容如下,其中100.85.125.90:80为service的公网访问地址:
#! /bin/bash for (( ; ; )) do curl -I 100.85.125.90:80 | grep "200 OK" if [ $? -ne 0 ]; then echo "response error!" exit 1 fi done
- 运行检测脚本:bash detection_script.sh,并在云容器实例 CCI2.0控制台,单击左侧导航栏中的“负载管理 > 无状态负载”,选择相关工作负载,单击“YAML编辑”,来触发应用的滚动升级。
滚动升级的过程中,应用的访问并未中断,并且返回的请求都是“200 OK”,说明升级过程是优雅升级,无中断。