找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

478

积分

0

好友

62

主题
发表于 3 天前 | 查看: 8| 回复: 0

本文将深入剖析其背后的实现机制。Kubernetes 设计的优雅退出机制,旨在保证服务实例上下线时,尽可能避免服务中断。

这一目标的核心实现,依赖于 Kubernetes 的调度策略与 Pod 容器内部关闭逻辑的紧密配合:

  1. 调度策略:当 Pod 被删除或缩容时,Kubernetes 会向容器进程发送 SIGTERM 信号,通知容器开始优雅退出,同时将该 Pod 状态标记为 Terminating。同步地,Kubernetes 会根据副本控制器(如 ReplicaSet/Deployment)的配置创建新的 Pod,并且 Service 会立即将新流量路由到新 Pod,而非处于 Terminating 状态的旧 Pod。
  2. Pod 容器的内部关闭逻辑:对于处于 Terminating 状态的 Pod,Kubernetes 会提供一个宽限期(默认为 30 秒)让其完成清理工作,例如关闭文件描述符、释放资源等。如果容器进程在宽限期内未能自行退出,Kubernetes 将发送 SIGKILL 信号强制终止进程。因此,业务服务在开发时,需要监听 SIGTERM 信号,在收到信号后,先处理完当前正在执行的请求,再正常退出,从而实现最大程度的优雅下线。

详解

Kubernetes 的优雅退出是由 kubeletEndpoints 控制器、ReplicaSet/Deployment、探针(Probe)与生命周期钩子(Lifecycle)等多个组件协同实现的。

通常有两种触发路径:

  • kubectl delete pod(用户强制删除):旧 Pod 会立即进入 Terminating 状态,随后副本控制器检测到副本数不足,会启动新的 Pod 进行补充。
  • Deployment 滚动更新(RollingUpdate):通常的策略是“先启动新 Pod”(maxSurge),待新 Pod 进入 Ready 状态后,再终止旧 Pod(maxUnavailable)。

核心逻辑

  • 当 Pod 进入 Terminating 状态后,它会被从 Service 的 Endpoints 后端列表中移除,新的流量请求不会再被路由到该 Pod。
  • kubelet 会首先向 Pod 内的容器发送 SIGTERM 信号。如果容器在 terminationGracePeriodSeconds 设定的宽限期内没有退出,kubelet 最终会发送 SIGKILL 信号强制终止进程。
  • kubectl delete pod 命令不会“先拉新后删旧”;只有滚动更新(RollingUpdate)才有“先启动新实例,再终止旧实例”的保障流程。
  • 应用程序自身需要实现“停止接收新连接、等待现有请求处理完成、超时后强制关闭”等逻辑。为了更可靠,建议配合使用 preStop 生命周期钩子与 readinessProbe 就绪探针。

触发路径对比(时序图)

A. 用户执行 kubectl delete pod

6403.jpeg

B. Deployment 滚动更新(RollingUpdate)

默认策略:maxUnavailable=1maxSurge=1 64026.png

流程拆解

  1. 终止信号分发
    • kubelet 在 Pod 被删除或缩容时,会向容器内的主进程发送 SIGTERM 信号。
    • 收到信号的 Pod 随即进入 Terminating 状态,优雅退出的宽限期开始计时。
  2. 与流量切断协同
    • Endpoints 控制器会实时监听 Pod 状态,一旦 Pod 进入 Terminating,便将其从关联的 Service 后端池中移除。
    • 新的服务请求将不会再被路由到该 Pod;对于该 Pod 上仍在处理的连接和请求,则由应用程序自身的逻辑决定何时释放。
  3. 宽限期与强制终止
    • 宽限期的时长由 Pod 规约中的 spec.terminationGracePeriodSeconds 字段控制,默认值为 30 秒。
    • 如果容器进程在宽限期结束后仍未退出,kubelet 将发送 SIGKILL 信号强制终止该进程。
  4. 新 Pod 的补充与创建
    • kubectl delete pod场景:旧 Pod 直接变为 Terminating;随后,ReplicaSet 控制器观察到期望的副本数减少,便会触发创建新 Pod 的流程。
    • 滚动更新场景:通常策略是先创建新 Pod(将总副本数临时提升至 replicas + maxSurge),待新 Pod 状态变为 Ready 后,再按顺序终止旧 Pod(将总副本数最终降至 replicas - maxUnavailable)。

关键参数与配置

Pod 级别

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1       # 允许超出期望副本数的最大Pod数
      maxUnavailable: 1 # 更新过程中不可用Pod的最大数量
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      terminationGracePeriodSeconds: 60  # 优雅退出宽限期,单位秒
      containers:
        - name: server
          image: ghcr.io/example/web:1.2.3
          ports:
            - containerPort: 8080
          readinessProbe:                # 就绪探针
            httpGet:
              path: /healthz
              port: 8080
            periodSeconds: 2
            failureThreshold: 2
          lifecycle:                     # 生命周期钩子
            preStop:                     # 终止前钩子
              httpGet:
                path: /drain             # 应用实现的“停止接收新连接”端点
                port: 8080

配置说明:

  • terminationGracePeriodSeconds:设置合理的宽限期,既能保证在途请求处理完毕,又能避免因超时被 SIGKILL 强制杀死。
  • readinessProbe:确保只有通过健康检查的 Pod 才会被加入 Service 的流量后端。应用在准备退出时,可以主动使就绪探针失败,促使自身更快地从后端移除。
  • preStop:用于在 SIGTERM 信号发送之前或同时,执行自定义的清理逻辑(例如调用应用内预先实现的“排水”(Drain)接口,通知服务停止接收新请求)。

Service 与 Endpoints

  • Service 与 Endpoints 无需特殊配置即可配合优雅退出。Endpoints 控制器会自动在 Pod 变为 Terminating 时将其从后端列表中剔除。
  • 如果使用了外部负载均衡器(如 Ingress 或云厂商的 LoadBalancer 类型 Service),需要确保负载均衡器的健康检查机制与 Kubernetes 内部的 readinessProbe 状态保持一致,避免流量切换延迟或双写。

验证与排查

  • 观察 Pod 事件:执行 kubectl describe pod <pod-name>,查看事件中关于 TerminatingpreStop 钩子执行以及探针检查的记录。
  • 观察 Endpoints 变化:执行 kubectl get endpoints <service-name> -w 进行实时观察,确认 Pod 进入 Terminating 状态后是否被及时移除。
  • 滚动更新演练:执行 kubectl rollout restart deployment/<deployment-name> 触发滚动更新,观察新旧 Pod 的 ReadyTerminating 状态变化的先后顺序是否符合预期。
  • 压测验证:在 Pod 删除或滚动更新过程中持续发送业务流量,监控服务是否出现明显的 5xx 错误率突增或连接拒绝现象。

最佳实践

  1. 避免宽限期过短:如果应用关闭逻辑较复杂,需要适当调大 terminationGracePeriodSeconds,并优化应用自身的关闭路径,确保能在宽限期内完成。
  2. 处理长连接:应用在收到 SIGTERM 后,应立即停止接受新的连接,并为现有连接设置合理的超时时间,必要时主动关闭空闲或超时的长连接。
  3. 合理使用 preStoppreStop 钩子执行时间计入宽限期,应确保其逻辑快速且幂等。复杂的关闭逻辑建议在应用内部处理。
  4. 主动标记非就绪状态:应用可以在收到 SIGTERM 信号或进入 preStop 阶段时,主动将自身的健康检查状态置为失败,促使负载均衡器更快地切断流量。
  5. 与外部组件对齐:确保外部负载均衡器(LB)或 API 网关的健康检查端点、超时时间与 Kubernetes 内的 readinessProbe 配置保持一致,避免因状态不一致导致流量错误路由。

常见误解澄清

  1. 删除 Pod 会等待新 Pod Ready 后才让旧 Pod Terminating 吗? 答:不会。kubectl delete pod 命令会立刻让目标 Pod 进入 Terminating 状态;新 Pod 是由副本控制器(如 ReplicaSet)在检测到副本数不足后随后创建补足的,两者没有等待关系。
  2. Pod 处于 Terminating 状态下还会接收流量吗? 答:不会。Endpoints 控制器会将其从关联的 Service 后端列表中移除,新的服务请求不会再被路由到它。
  3. 优雅退出只靠配置 Kubernetes 资源就足够了吗? 答:不够。Kubernetes 提供了机制和框架,但应用必须自行实现优雅关闭的业务逻辑(停止接单、等待在途请求完成、超时强制关闭等)。

总结

Kubernetes 的优雅退出是一套由“信号分发、后端移除、宽限期控制、副本管理”等多个环节协同工作的机制。它不仅是Docker等容器运行时技术的上层抽象,更是构建稳定微服务架构的关键保障。

要实现真正的无损发布或下线,除了正确配置 terminationGracePeriodSecondsreadinessProbepreStop 等参数外,更关键的是在应用程序内部实现完善的优雅关闭流程。

无论是滚动更新还是手动删除,Kubernetes 都会确保进入 Terminating 状态的 Pod 不再承接新流量,从而为业务平滑过渡提供了基础保障。




上一篇:GESP-C++一级备考刷题:计算机常识与历史真题解析
下一篇:MySQL分区键实战解析:使用默认时间戳时能否为NULL?
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区(YunPan.Plus) ( 苏ICP备2022046150号-2 )

GMT+8, 2025-12-7 00:24 , Processed in 0.106059 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 CloudStack.

快速回复 返回顶部 返回列表