为什么配置更新了,Pod 却毫无反应?
🤔 开篇:凌晨2点的困惑
你更新了 ConfigMap,期待应用自动加载新配置。然而,Pod 纹丝不动。
真相:90% 的工程师对"Pod 重启"存在误解。
📊 四种"重启",天壤之别
| 类型 | UID 变化 | IP 变化 | 重启计数 | 本质 |
|---|---|---|---|---|
| 容器重启 | ❌ | ❌ | +1 | 同一 Pod 内进程重启 |
| Pod 重建 | ✅ | ✅ | 归零 | 滚动更新、驱逐 |
| CPU 原地扩容 | ❌ | ❌ | 0 | cgroup 配额更新 |
| 内存原地扩容 | ❌ | ❌ | +1 | 取决于策略 |
黄金法则:
kubectl get pod <pod> -o jsonpath='{.metadata.uid}'
# UID 变了 = Pod 重建
# UID 没变 = 容器重启
🧠 核心真相:kubelet 只监视 Pod Spec
# ❌ kubelet 不在乎:
- ConfigMap/Secret 内容变更
- Istio 路由规则
- NetworkPolicy
# ✅ 只有这些触发 kubelet:
- 容器镜像
- 环境变量
- 资源限制
决策矩阵:
- 必须重建:镜像、命令、探针、资源限制
- 应用决定:ConfigMap/Secret 卷挂载(文件自动更新,应用需热加载)
- 无需重启:CPU 原地扩容、Istio 路由(xDS 推送)、NetworkPolicy
- 手动触发:ConfigMap/Secret 环境变量注入
🎬 五大实战场景
场景 1:ConfigMap 的两种命运
环境变量模式(envFrom):
envFrom:
- configMapRef:
name: my-config
❌ 结果:配置更新后,Pod 纹丝不动
原因:环境变量在进程启动时复制,无法动态修改
卷挂载模式(Volume Mount):
volumeMounts:
- name: config
mountPath: /etc/config
volumes:
- name: config
configMap:
name: my-config
✅ 结果:文件自动同步(kubelet 通过原子 symlink 交换)
⚠️ 陷阱:应用需监控目录创建事件,而非文件修改
场景 2:镜像更新的三种结局
- 成功滚动更新:UID 变化,重启计数归零 = Pod 重建
- ImagePullBackOff:旧 Pod 保留,新 Pod 卡住
- CrashLoopBackOff:UID 不变,重启计数持续增加 = 崩溃循环
诊断法则:重启计数上升 + UID 不变 = 崩溃循环
场景 3:原地资源扩容(K8s 1.35+)
革命性特性:无需重建 Pod 即可调整资源!
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired # 无感知
- resourceName: memory
restartPolicy: RestartContainer # 容器重启
⚠️ 致命陷阱:不指定 resizePolicy,JVM 堆内存不会自动调整!
应用方法:
kubectl patch pod my-pod --subresource resize \
-p '{"spec":{"containers":[{"name":"app","resources":{
"requests":{"cpu":"250m","memory":"128Mi"}
}}]}}'
场景 4:Istio 路由 —— 零重启魔法
原理:Istiod 通过 xDS 协议推送,毫秒级生效
100% v1 → 80/20 金丝雀 → 50/50 → 100% v2
重启计数:[0,0,0,0] → [0,0,0,0]
⚠️ 陷阱:Envoy 可能静默拒绝推送,需监控 pilot_xds_push_errors
场景 5:Stakater Reloader 救星
问题:ConfigMap 以环境变量注入时,需手动重启
方案:
annotations:
reloader.stakater.com/auto: "true"
⚠️ 生产陷阱:默认只监视自身命名空间,需设置 watchGlobally=true
🛠️ 运维必备命令
# 判断重启类型
kubectl get pod <pod> -o custom-columns=\
"UID:.metadata.uid,RESTARTS:.status.containerStatuses[0].restartCount"
# 查看事件
kubectl describe pod <pod> | grep -A 20 "Events:"
# 检查原地扩容
kubectl get pod <pod> -o jsonpath='{.status.resize}'
📈 热重载 vs 容器重启
| 维度 | 容器重启 | 热重载 |
|---|---|---|
| 可用性 | 短暂中断 | 零中断 |
| 失败模式 | 立即报错 | 静默出错 |
| 调试难度 | 容易 | 困难 |
决策树:
- 环境变量/镜像/探针 → 容器重启 ✅
- 配置文件 + 应用支持 → 热重载 🔄
- Istio 路由 → xDS 推送 ⚡
🎓 三大原则
- 理解本质:UID 变化 = 重建;UID 不变 + 计数增加 = 容器重启
- kubelet 只关心 Pod Spec:ConfigMap 内容变化 ≠ Spec 变化
- 重启不是敌人,静默失败才是:选择应深思熟虑
💡 记住:目标不是更快重启,而是理解何时该重启,何时该静默。