3、升级窗口定义:滚动更新策略、PodDisruptionBudget、优雅关闭与流量排空
Ingress 控制器的升级窗口是集群流量管理中最关键的时段。如果升级策略配置不当,轻则导致少量请求 502/503,重则引发整个集群入口瘫痪。本章从三个核心维度拆解升级窗口的防御体系:滚动更新策略控制 Pod 替换节奏,PodDisruptionBudget 保障最小可用副本数,优雅关闭与流量排空确保存量连接安全终止。
3.1 滚动更新策略:控制替换节奏
Kubernetes 默认的 RollingUpdate 策略会逐个替换 Pod,但对于 Ingress 控制器这类承载七层流量的组件,默认行为往往过于激进。你需要显式配置 maxSurge 和 maxUnavailable 来限制并发替换数。
| 参数 | 默认值 | 推荐值(Ingress 控制器) | 说明 |
|---|---|---|---|
maxSurge |
25% | 1 或 10% | 升级期间允许超出期望副本数的最大 Pod 数,避免同时启动过多新 Pod 造成后端过载 |
maxUnavailable |
25% | 0 | 升级期间允许不可用 Pod 的最大数量,设为 0 可保证至少保留全部副本数,但会延长升级时间 |
生产建议:对于 3 副本的 Ingress 控制器,推荐配置
maxSurge: 1 和 maxUnavailable: 0。这样每次只替换 1 个 Pod,且替换期间始终保持 3 个 Pod 处理流量,避免容量瞬间下降。
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: controller
image: registry.k8s.io/ingress-nginx/controller:v1.11.0
ports:
- containerPort: 80
- containerPort: 443
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 30"]
3.2 PodDisruptionBudget:保障最小可用副本
PodDisruptionBudget(PDB)是集群管理员对抗节点级故障和主动运维操作的防御层。即使节点被 drain 或集群触发自动缩容,PDB 也能阻止 Ingress 控制器的可用副本数低于阈值。
常见误区:PDB 只保护 自愿中断(如 kubectl drain、cluster autoscaler 缩容),不保护非自愿中断(如节点宕机、硬件故障)。非自愿中断需要依靠多副本 + 反亲和性来应对。
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: ingress-nginx-pdb
namespace: ingress-nginx
spec:
minAvailable: 2 # 至少保留 2 个副本
selector:
matchLabels:
app.kubernetes.io/component: controller
PDB 的两种配置模式对比:
| 模式 | 表达式 | 适用场景 |
|---|---|---|
| 最小可用数 | minAvailable: 2 |
固定副本数场景(如 3 副本集群),明确要求至少保留 2 个 |
| 最大不可用百分比 | maxUnavailable: 33% |
动态副本数场景(HPA 自动扩缩),按比例控制中断容忍度 |
3.3 优雅关闭与流量排空
Ingress 控制器的优雅关闭分为两个阶段:从负载均衡器摘除和存量连接排空。如果只依赖默认的 SIGTERM 处理,Kubelet 会在 terminationGracePeriodSeconds 到期后强制杀死进程,导致正在处理的请求被截断。
3.4 排空参数调优清单
以下参数需要根据业务请求的典型耗时进行联动调整:
| 参数 | 位置 | 推荐值 | 调优依据 |
|---|---|---|---|
terminationGracePeriodSeconds |
Deployment.spec.template.spec | 120s | 必须大于 PreStop + 排空超时之和 |
lifecycle.preStop.sleep |
Container 定义 | 30s | 负载均衡器健康检查间隔的 2~3 倍 |
--worker-shutdown-timeout |
Ingress 控制器启动参数 | 60s | Nginx worker 等待活跃请求完成的最大时间 |
--max-worker-connections |
ConfigMap / 启动参数 | 65536 | 根据并发量调整,过大可能导致排空变慢 |
排空验证命令:在升级窗口期间,持续观察 Ingress 控制器 Pod 的日志和指标,确认排空行为符合预期。
# 观察排空日志
kubectl logs -n ingress-nginx -l app.kubernetes.io/component=controller \
--tail=50 | grep -E "shutdown|drain|graceful|closing"
# 监控活跃连接数(Prometheus 指标)
nginx_ingress_controller_nginx_process_connections{state="active"}
# 检查 PDB 是否阻止了中断
kubectl get pdb -n ingress-nginx -o wide
3.5 升级窗口的完整防御链
将上述三个组件串联起来,形成 Ingress 控制器升级窗口的完整防御链:
- PDB 前置检查:升级操作发起前,Kubernetes 先检查 PDB 是否允许中断。如果当前可用副本数 ≤ minAvailable,操作被阻塞。
- 滚动更新节奏控制:maxUnavailable=0 确保每次只替换 1 个 Pod,且替换期间总副本数不下降。
- PreStop 延迟摘除:新 Pod 启动后,旧 Pod 进入 PreStop 阶段,sleep 30 秒等待负载均衡器完成摘除。
- SIGTERM 触发排空:PreStop 结束后,Ingress 控制器收到 SIGTERM,关闭新连接监听,启动内部排空计时器。
- 连接排空完成或超时:worker-shutdown-timeout 内等待活跃请求完成,超时后强制关闭。
- Kubelet 强制终止:terminationGracePeriodSeconds 到期后,Kubelet 发送 SIGKILL 清理残留进程。
排空失败典型场景:如果 terminationGracePeriodSeconds 设置过短(如 30s),而 PreStop sleep 已占用 30s,则排空阶段实际可用时间为 0s,所有存量连接都会被 SIGKILL 截断,导致 502 错误。务必保证 terminationGracePeriodSeconds ≥ PreStop sleep + worker-shutdown-timeout + 10s 缓冲。
3.6 升级窗口的可观测性检查点
在升级窗口期间,以下检查点可以帮助你快速定位排空问题:
| 检查点 | 观测对象 | 正常行为 | 异常信号 |
|---|---|---|---|
| PDB 状态 | kubectl describe pdb |
DisruptionsAllowed ≥ 1 | DisruptionsAllowed = 0,升级被阻塞 |
| Pod 事件 | kubectl describe pod |
PreStop 执行成功,无 FailedPreStopHook | PreStop 超时或执行失败 |
| Ingress 日志 | 控制器日志 | 输出 "Shutting down worker processes" 后正常退出 | 无排空日志,或出现 "worker process exited with fatal" |
| 上游 5xx 指标 | Prometheus / 负载均衡器 | 升级期间 5xx 无显著增加 | 502/503 突增,表明排空未生效 |