一、postStart 和 preStop 分别解决什么问题

Kubernetes 为容器提供了两个非常实用的生命周期钩子:

  • postStart:容器启动后立刻触发
  • preStop:容器终止前触发

常见用途包括:

  • 启动后写入标记文件、注册状态、预热资源
  • 终止前先摘流量、通知服务下线、等待连接处理完成

示例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: lifecycle-demo-container
    image: registry.cn-hangzhou.aliyuncs.com/zq-demo/nginx:1.14.2
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
      preStop:
        exec:
          command: ["/bin/sh","-c","nginx -s quit; while killall -0 nginx; do sleep 1; done"]

二、postStart 有什么容易误解的地方

postStart 虽然名字像“启动后再执行”,但它并不意味着一定严格晚于主进程所有启动动作完成。尤其当容器本身也有启动命令时,两者更接近并行触发,而不是绝对先后顺序。

所以,如果你的需求是“必须在主容器真正启动前先完成某一步准备工作”,更合适的做法通常不是 postStart,而是 initContainer

三、如何验证 postStart 生效了

创建 Pod 后:

kubectl create -f nginx.yml
kubectl get po nginx

进入容器查看:

kubectl exec -it nginx -- cat /usr/share/message

如果输出:

Hello from the postStart handler

就说明钩子已经按预期执行。

四、preStop 在 Kubernetes 1.30 前后有什么变化

在较早版本里,常见写法是:

preStop:
  exec:
    command: ["sleep", "60"]

而在较新版本中,preStop 增加了更直接的 sleep 写法:

preStop:
  sleep:
    seconds: 60

这类变化的本质,是让优雅终止配置更直观,也更容易表达“给服务留出缓冲时间”这件事。

五、零宕机发布最关键的不是滚动更新本身,而是配套细节

很多人以为只要用了 RollingUpdate 就天然零宕机,其实不够。

一个更稳妥的基础配置通常是:

spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%

但这只是第一步。真正决定能不能平滑切流的,还包括探针和优雅终止。

六、探针要怎么配,才更适合生产发布

一个比较实用的思路是:

1. 就绪探针必须有

readinessProbe:
  httpGet:
    path: /health/ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

它直接决定了新 Pod 什么时候能接流量,也是旧 Pod 下线前流量能否及时摘除的关键。

2. 存活探针按需配

livenessProbe:
  httpGet:
    path: /health/live
    port: 8080
  initialDelaySeconds: 15

它更偏向故障恢复,而不是流量切换。

3. 慢启动应用加 startupProbe

startupProbe:
  httpGet:
    path: /health/started
    port: 8080
  failureThreshold: 30
  periodSeconds: 5

它能避免应用初始化还没结束,就被过早判定失败。

七、优雅终止为什么经常决定零宕机是否成立

如果 Pod 收到终止信号后直接退出,往往会出现这些问题:

  • 长连接被硬切断
  • 注册中心里还没摘除实例
  • 请求已经进来但还没处理完

因此常见做法是,在 preStop 里先执行下线逻辑,例如:

lifecycle:
  preStop:
    exec:
      command:
      - /bin/sh
      - -c
      - "pkill java; sleep 30"

对像 Nacos 这类注册中心或需要优雅下线的服务,这种做法尤其重要。

八、gRPC 服务怎么做健康检查

从 Kubernetes 1.24 起,gRPC 探针逐渐进入更常见的使用场景。

如果你的服务本身就是 gRPC,可以直接使用:

apiVersion: v1
kind: Pod
metadata:
  name: etcd
spec:
  containers:
  - image: registry.cn-hangzhou.aliyuncs.com/google_containers/etcd:3.5.1-0
    name: etcd
    command:
    - /usr/local/bin/etcd
    - --data-dir
    - /var/lib/etcd
    - --listen-client-urls
    - http://0.0.0.0:2379
    - --advertise-client-urls
    - http://127.0.0.1:2379
    - --log-level
    - debug
    ports:
    - containerPort: 2379
    livenessProbe:
      grpc:
        port: 2379
      initialDelaySeconds: 10

创建后查看:

kubectl create -f grpc.yml
kubectl get po etcd

这类探针的前提,是应用实现了标准的 gRPC 健康检查接口。

九、这一篇最值得记住的发布思路

如果把优雅终止和零宕机发布压缩成一套简单方法论,可以记成:

  1. 用滚动更新控制替换节奏
  2. readinessProbe 控制何时接流量
  3. startupProbe 保护慢启动阶段
  4. preStop 给下线留缓冲
  5. 对 gRPC 服务使用原生 gRPC 探针

真正稳定的发布,从来不是“换 Pod 很快”,而是“新实例准备好之后再接流量,旧实例摘流量后再退出”。