概述
修改 ConfigMap 看起来无害,但它会改变每个读取该配置的进程行为。Deployment 的 Pod 不会自动重启:一方面 Kubernetes 无法判断新配置是否可以安全地逐步生效,另一方面环境变量只在容器启动时读取一次。结果就是集群中一部分 Pod 使用新值、一部分使用旧值,而发布历史里没有任何记录。应把配置当作发布产物来管理。
步骤
- 增加校验和注解,让配置变更触发新的 ReplicaSet:
spec:
template:
metadata:
annotations:
checksum/config: "{{ include (print $.Template.BasePath \"/configmap.yaml\") . | sha256sum }}"
- 设置滚动策略,保证容量不下降:
strategy:
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
- 观察滚动过程并确认旧 Pod 逐个退出:
kubectl rollout status deployment/payments -n prod --timeout=300s
kubectl get pods -n prod -l app=payments -o wide
- 在启动时校验配置,非法值直接让就绪探针失败:
const timeout = Number(process.env.REQUEST_TIMEOUT_MS ?? 3000);
if (!Number.isFinite(timeout) || timeout <= 0) {
throw new Error('invalid REQUEST_TIMEOUT_MS');
}
验证
滚动期间 kubectl get deployment 的可用副本数应始终不低于期望值,旧 Pod 只在新 Pod Ready 后才终止。修改配置后应产生新的 ReplicaSet,并可通过 kubectl rollout history 回滚。注入一个非法值后,新 Pod 应停留在未就绪状态,流量继续由旧 Pod 承载,而不是带着错误配置对外服务。
注意事项
maxUnavailable: 0时若有 Pod 一直 Pending,发布会无限期阻塞,需要先确认资源充足。- 环境变量只在容器启动时读取,只有挂载卷会原地更新,应用还需监听文件变化。
- 挂载卷的更新存在延迟,且多个 key 之间不是原子生效。
- 零停机的前提是新旧配置在过渡期内都合法。
- 日志中应记录生效配置(敏感值打码),便于事后判断 Pod 实际使用的值。