现象或背景
我们一条 24 节点(16C64G,Kubernetes 1.28.9 + containerd 1.7.13,cgroup v2)的核心交易集群,Java 17 + Spring Boot 3.1,Pod 副本数 12,QPS 约 3200。
事故发生在一次普通的 kubectl rollout restart 后,凌晨 03:12,集群里一台 8C16G、100GB 系统盘的 worker 节点(Kubernetes 1.28.9,containerd 1.7.13)突然开始批量驱逐 Pod:03:12 起 40 分钟内,kubectl get pods 显示 19 个 Pod 被驱逐,kubectl describe pod 显示 Evicted 状态,kubectl logs 无法获取日志,kubectl describe node 显示 DiskPressure。
监控数据显示,Pod 在崩溃前 CPU 使用率长期处于 95% 以上,内存使用率接近阈值。通过日志分析发现,崩溃前存在大量 OOM Killer 日志,且系统日志显示频繁的 killed 信号。
原理或根因分析
Pod 崩溃的根本原因是 节点磁盘打满,触发了 kubelet 的 DiskPressure 机制,导致 Pod 被连环驱逐。具体机制如下:
- 磁盘水位监控:kubelet 默认每 20 秒检查一次节点磁盘使用率,当系统盘使用率超过 90% 时,触发
DiskPressure状态。 - Pod 驱逐策略:当节点处于
DiskPressure时,kubelet 会按优先级驱逐 Pod,优先驱逐 低优先级 的 Pod(如 initContainer、非关键业务 Pod)。 - 日志清理机制:容器日志默认存储在
/var/lib/docker/containers/下,未配置日志轮转时,日志文件会持续增长,最终占满磁盘。
具体做法
3.1 确认磁盘使用情况
# 查看节点磁盘使用
df -h
# 查看 kubelet 日志
journalctl -u kubelet --since "2026-10-13 03:00:00" --until "2026-10-13 04:00:00"
# 查看系统日志
journalctl -b -1 | grep 'killed' | grep 'oom-killer'
3.2 检查 Pod 驱逐原因
# 查看节点状态
kubectl describe node <node-name>
# 查看 Pod 驱逐详情
kubectl describe pod <pod-name>
# 查看 kubelet 日志中的驱逐事件
kubectl logs <kubelet-pod-name> --previous
3.3 修复与预防
临时修复:
# 清理容器日志(需谨慎,可能丢失日志)
find /var/lib/docker/containers/ -name 'json.log' -type f -exec truncate -s 0 {} \;
# 重启 kubelet 服务
systemctl restart kubelet
长期预防:
- 配置日志轮转:在
containerd配置文件中添加日志轮转策略,限制单个日志文件大小和保留天数。 - 监控磁盘使用:使用 Prometheus + Grafana 监控节点磁盘使用率,设置阈值告警。
- 调整 Pod 资源限制:为关键业务 Pod 设置合理的
resources.requests和resources.limits,避免资源争抢。
踩过的坑或反直觉之处
- 忽略日志轮转配置:未配置日志轮转时,日志文件会持续增长,最终占满磁盘,导致 Pod 被驱逐。
- 误判驱逐原因:初次排查时误以为是 CPU/内存问题,实际是磁盘水位触发的驱逐。
- 清理日志的风险:直接清理日志可能导致重要错误信息丢失,需在清理前备份。
结论与可复用清单
| 问题 | 解决方案 | 防范措施 | |------|----------|----------| | 磁盘打满 | 清理日志、重启 kubelet | 配置日志轮转、监控磁盘使用 | | Pod 被驱逐 | 检查 kubelet 日志、查看驱逐原因 | 设置资源请求与限制 | | 日志丢失 | 备份日志、使用日志管理系统 | 集成 ELK 或 Loki 日志收集系统 |
关键命令汇总:
# 日志轮转配置示例(containerd)
[plugins."io.containerd.grpc.v1.cri".docker]
log_path = "/var/log/containers/"
max_log_size = 10485760 # 10MB
max_log_keep = 3
工具推荐:
- Prometheus + Grafana:监控节点资源使用
- ELK Stack / Loki:日志集中管理
- kube-state-metrics:实时监控 Pod 状态
引用依据:
- [postId:657](CPUQuota 是带宽不是水位)
- [postId:1739](CPU limit 隐性性能税讨论)
一句话:Pod 崩溃的根因是磁盘打满触发的驱逐,修复需从日志清理、资源限制、监控告警三方面入手,避免重复踩坑。