
Kubernetes的滚动更新机制在生产环境中是保障系统持续可用与平滑升级的关键能力,在香港节点集群更新过程中,我们遇到了滚动更新失败的问题。这个问题表面上是应用层的更新中断,实际深入分析后发现与底层节点状态漂移、Pod调度异常密切相关。本文将完整复现该问题的排查过程,并详解修复方案,以期为读者提供一套可借鉴的实战经验。
我们的业务系统部署在多个区域的 Kubernetes 集群中,香港区域的集群承担了部分核心业务请求的转发与处理。这个区域集群由 6 个物理节点组成,运行在基于 Ubuntu 20.04 的香港裸金属服务器上,配套使用了 containerd 作为容器运行时,CNI 网络插件为 Calico,Kubernetes 版本为 v1.26.3。
在一次例行的版本更新中,我们采用如下更新策略:
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
maxSurge: 1
预期目标为每次仅下线一个 Pod 并启动一个新版本副本,最大限度保障服务可用。然而,更新操作执行后却发现 Deployment 卡在中间状态,更新无法继续推进,Pods 处于长时间的 Pending 状态。
初步排查:Pod 调度失败
我们首先查看了 Deployment 状态:
kubectl describe deployment core-service
输出中显示已有若干 Pod 成功更新,但后续 Pods 一直处于 Pending 状态。
进一步查看具体 Pod 的调度详情:
kubectl describe pod core-service-xxx
发现以下调度失败信息:
Warning FailedScheduling default-scheduler 0/6 nodes are available: 3 node(s) had taint {node.kubernetes.io/unreachable: }, that the pod didn't tolerate, 2 node(s) had insufficient memory, 1 node(s) not ready.
深入分析:节点状态异常
上述信息提示我们存在多个问题节点。接下来验证节点状态:
kubectl get nodes
输出显示:
NAME STATUS ROLES AGE VERSION
node-hk-1 Ready <none> 92d v1.26.3
node-hk-2 Ready,SchedulingDisabled <none> 91d v1.26.3
node-hk-3 NotReady <none> 89d v1.26.3
node-hk-4 Ready <none> 91d v1.26.3
node-hk-5 Ready <none> 91d v1.26.3
node-hk-6 Ready <none> 91d v1.26.3
node-hk-3 处于 NotReady 状态,而 node-hk-2 已被标记为 SchedulingDisabled。这意味着当前仅有 4 个节点可用于调度,而实际中其中 2 个节点存在内存资源不足的问题,导致调度资源紧张。
我们进一步登录 node-hk-3 进行检查:
journalctl -u kubelet
日志中显示:
NodeController detected that the node is not responding. Marking it as NotReady.
结合节点的 system log,我们发现该节点与 kube-apiserver 的网络通信间歇性中断。
问题根因定位
通过持续的网络连通性测试(ping 与 curl kube-apiserver IP),最终确认问题根因如下:
- Kubernetes 节点状态漂移: 某些节点与控制平面之间出现间歇性网络丢包,导致 kubelet 无法及时上报心跳,节点被标记为 NotReady。
- Pod 调度资源不足: 由于多个节点调度受限,集群无法满足新 Pod 的调度请求。
- 容器滚动更新机制未考虑节点状态变化,造成更新停滞。
这个问题的一个关键点在于:Kubernetes 的滚动更新机制在调度受限场景下不会自动回退,而是持续等待可用资源,造成更新“卡死”。
修复方案
1. 网络层修复
首先针对 node-hk-3 进行网络排查,发现是物理服务器网卡的 RX 阈值未调优,导致在高并发流量下出现中断丢失。
解决方案:
ethtool -C eth0 rx-usecs 64
systemctl restart kubelet
此操作后节点成功恢复 Ready 状态。
2. 节点预检与健康监控补强
为了防止后续更新再被卡住,我们增加了以下机制:
在 CI/CD 中引入更新前的节点健康检测脚本,自动过滤出不健康节点。
在 Prometheus 中增加节点状态告警阈值,若某区域 Ready 节点少于设定值,自动暂停更新。
示例健康检测脚本如下:
#!/bin/bash
for node in $(kubectl get nodes --no-headers | awk '{print $1}'); do
status=$(kubectl get node $node -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}')
if [[ "$status" != "True" ]]; then
echo "Node $node is not Ready, aborting update."
exit 1
fi
done
3. 调整Pod调度策略
针对资源不足问题,我们为关键组件设置资源请求上限,避免因内存膨胀占用调度资源。同时启用了 PodPriority 与 PreemptionPolicy,确保关键服务优先调度。
示例配置:
priorityClassName: system-critical
resources:
requests:
cpu: "500m"
memory: "1Gi"
limits:
cpu: "1"
memory: "2Gi"
此次滚动更新失败表面是调度受限,实质是节点状态漂移引发的连锁反应。整个排查过程暴露了多个潜在隐患:
- 节点状态与滚动更新策略耦合紧密,需在更新前充分校验节点状态。
- Kubernetes 默认调度器在资源紧张场景下的行为易导致更新中断,应结合实际设置合理的 Pod 优先级与资源限制。
- 节点层的网络与系统参数调优需提前介入,防止底层问题影响上层部署。
给您得建议:
- 在 CI/CD 中增加“节点健康预检查”环节。
- 部署更新时启用 PodDisruptionBudget 与 priorityClass,更好控制调度行为。
- 对边缘节点(如跨境香港区域)配置更稳定的网络策略与 QoS。
通过此次问题复盘,我们不仅解决了容器滚动更新失败的表面问题,更优化了整套系统的稳定性与更新机制,为日后的可持续交付提供了坚实的保障。











