容器服务 Service 优雅停机

基于接入层直连 Pod 的场景,当后端进行滚动更新或后端 Pod 被删除时,如果直接将 Pod 从 LB 的后端摘除,则无法处理 Pod 已接收但还未处理的请求。

相关产品
容器服务 产品页,含版本规格、价格与购买入口。

一、简介

对于长连接场景,例如会议业务,如果直接更新或删除工作负载的 Pod,会导致会议直接中断。

二、应用场景

·更新工作负载时,Pod 的优雅退出,使客户端不会感受到更新时产生的抖动和错误。

·当 Pod 需要被删除时,Pod 能够处理完已接收到的请求,此时入流量关闭,但出流量仍能走通。直到处理完所有已有请求和 Pod 真正删除时,出入流量才进行关闭。

注意:1. 仅针对 直连场景 生效,请检查你的集群是否支持直连模式。

注意:2. 如果是多 Service 复用相同的 CLB,且同时更新多个 Service 对应的后端服务,可能导致优雅停机功能受影响,详情见 多 Service 复用 CLB 中的说明事项。

三、步骤1:使用 Annotation 标明使用优雅停机

控制台使用说明YAML使用说明

1. 登录容器服务控制台,选择左侧导航中的 集群。

2. 在集群列表中,选择目标集群 ID,进入该集群的基本信息页面。

3. 在服务与路由页面的 Service 页签,找到目标 Service,单击其右侧的编辑 Annotations。

4. 在编辑 Annotations 页面,增加两项注解。

·第一项令键为service.cloud.tencent.com/enable-grace-shutdown,值为true。

·第二项令键为service.cloud.tencent.com/direct-access,值为true。

5. 单击设置 Annotations。

以下为使用 Annotation 标明使用优雅停机示例,完整 Service Annotation 说明可参见 Service Annotation 说明。kind: ServiceapiVersion: v1metadata: annotations: service.cloud.tencent.com/direct-access: "true" ## 开启直连 Pod 模式 service.cloud.tencent.com/enable-grace-shutdown: "true" # 表示使用优雅停机 name: my-servicespec: ports: – name: example port: 80 targetPort: 80 selector: app: anyserver type: LoadBalancer

四、步骤2:使用 preStop 和 terminationGracePeriodSeconds

步骤2为在需要优雅停机的工作负载里配合使用 preStop 和 terminationGracePeriodSeconds。

五、容器终止流程

以下为容器在 Kubernetes 环境中的终止流程:

1. Pod 被删除,此时 Pod 里有 DeletionTimestamp,且状态置为 Terminating。此时调整 CLB 到该 Pod 的权重为 0。

2. kube-proxy 更新转发规则,将 Pod 从 service 的 endpoint 列表中摘除掉,新的流量不再转发到该 Pod。

3. 如果 Pod 配置了 preStop Hook ,将会执行。

4. kubelet 将对 Pod 中各个 container 发送 SIGTERM 信号,以通知容器进程开始优雅停止。

5. 等待容器进程完全停止,如果在 terminationGracePeriodSeconds 内 (默认30s) 还未完全停止,将发送 SIGKILL 信号强制停止进程。

6. 所有容器进程终止,清理 Pod 资源。

六、具体操作步骤

1. 使用 preStop

要实现优雅终止,务必在业务代码里处理 SIGTERM 信号。主要逻辑是不接受新的流量进入,继续处理存量流量,所有连接全部断开才退出,了解更多可参见 示例。
若你的业务代码中未处理 SIGTERM 信号,或者你无法控制使用的第三方库或系统来增加优雅终止的逻辑,也可以尝试为 Pod 配置 preStop,在其实现优雅终止的逻辑,示例如下:

apiVersion: v1kind: Podmetadata: name: lifecycle-demospec: containers: – name: lifecycle-demo-container image: nginx lifecycle: preStop: exec: command: – /clean.sh…

更多关于 preStop 的配置请参见 Kubernetes API 文档。

在某些极端情况下,Pod 被删除的一小段时间内,仍然可能有新连接被转发过来,因为 kubelet 与 kube-proxy 同时 watch 到 Pod 被删除,kubelet 有可能在 kube-proxy 同步完规则前就已经停止容器,这时可能导致一些新的连接被转发到正在删除的 Pod,而通常情况下,当应用受到 SIGTERM 后都不再接受新连接,只保持存量连接继续处理,因此可能导致 Pod 删除的瞬间部分请求失败。

针对上述情况,可以利用 preStop 先 sleep 短暂时间,等待 kube-proxy 完成规则同步再开始停止容器内进程。示例如下:

apiVersion: v1kind: Podmetadata: name: lifecycle-demospec: containers: – name: lifecycle-demo-container image: nginx lifecycle: preStop: exec: command: – sleep – 5s 

2. 使用 terminationGracePeriodSeconds 调整优雅时长
如果需要优雅终止时间较长 (preStop + 业务进程停止可能超过30s),可根据实际情况自定义 terminationGracePeriodSeconds,避免过早的被 SIGKILL 停止,示例如下:

apiVersion: v1kind: Podmetadata: name: grace-demospec: terminationGracePeriodSeconds: 60 # 优雅停机默认30s,你可以设置更长的时间 containers: – name: lifecycle-demo-container image: nginx lifecycle: preStop: exec: command: – sleep – 5s…

七、相关能力

优雅停机只是在 Pod 删除时,才把 CLB 后端的权重置为 0。若 Pod 在运行的过程中,出现了不健康的情况,此时将该后端的权重置为 0,可以减少服务不可用的风险。
你可以使用 Annotation:service.cloud.tencent.com/enable-grace-shutdown-tkex: "true" 实现这样优雅退出的能力。
该 Annotation 会根据 Endpoint 对象中 endpoints 是否 not-ready,将 not-ready 的 CLB 后端权重置为 0。

八、相关文档

故障处理:Nginx Ingress Controller 后端解绑不优雅的问题

赞 (0)
上一篇 4天前
下一篇 4天前