Administrator
Administrator
发布于 2026-10-28 / 0 阅读
0
0

Kubernetes 故障排查(15):Pod 显示 Evicted:别把节点驱逐当作普通容器重启

面向初级运维,使用 Linux 节点和稳定 Kubernetes API。命令按 Bash 编写。本文为教学故障场景,日志及结果为示意,不冒充生产实测;执行前确认 context、命名空间和权限。

一、遭遇情况:原 Pod 变成 Evicted,新 Pod 又不断出现

值班时发现同一应用留下多个 Evicted Pod,Deployment 又创建了新副本。清理旧对象后没多久,新副本也开始异常,问题并没有消失。

本篇场景是某节点临时存储持续增长,kubelet 因压力驱逐 Pod。删掉失败对象只是清理列表,不会自动释放增长源,也不证明节点恢复了足够空间。

二、原因分析:容器重启与 Pod 驱逐是不同层

容器因 OOM 或应用退出后,可能在同一 Pod 内重启;节点压力驱逐则会使整个 Pod 失败,常见 reason 为 Evicted。Deployment 等控制器可能创建替代 Pod,裸 Pod 则不自动拥有相同恢复机制。

Pod 驱逐与节点资源压力的定位顺序

节点磁盘满、inode 用完、内存不足,都可能进入相应压力判断。节点压力驱逐不是普通 API 自愿驱逐流程,不能指望 PDB 阻止所有这类中断。

三、排查思路:先保留驱逐消息,再看节点

kubectl get pod 失败Pod -n 目标命名空间 -o jsonpath='{.status.phase}{"\n"}{.status.reason}{"\n"}{.status.message}{"\n"}'
kubectl describe pod 失败Pod -n 目标命名空间
kubectl describe node 相关节点
kubectl get pods -A -o wide --field-selector spec.nodeName=相关节点

替换对象名称。消息若指向 ephemeral-storage,应核对写入路径、容器日志和节点文件系统;若指向内存,则看相关用量与历史峰值。不能只因服务曾经 OOM,就把之后的所有 Evicted 都归为同一原因。

在获准访问的 Linux 节点,读取:

df -h
df -i
sudo journalctl -u kubelet --since '30 minutes ago' --no-pager

确认哪块文件系统或 inode 紧张。kubectl top 主要提供 CPU/内存视图,不应拿它没有显示磁盘异常作为临时存储健康的证据。

四、分析来源:应用写在哪一层

容器可写层、容器日志和磁盘型 emptyDir 都可能消耗节点临时存储。数据库挂了 PVC,不代表它的日志、临时目录和缓存也全部位于持久卷上。

内存型 emptyDir 则使用内存,不能简单按普通磁盘临时目录的方式理解。不同节点文件系统布局与运行时配置,也会影响 kubelet 的统计与回收范围。

不要在生产节点上用写满磁盘的方式复现。本篇实践采用有界的临时写入配置,练习识别存储位置与限制,不主动制造真实节点压力。

五、实践:给实验临时目录和资源设置边界

保存 kt15-ephemeral.yaml,在有余量的测试集群应用。数值仅为演示,不是生产容量建议:

apiVersion: v1
kind: Namespace
metadata:
  name: kt15
---
apiVersion: v1
kind: Pod
metadata:
  name: bounded-writer
  namespace: kt15
spec:
  containers:
    - name: writer
      image: busybox:1.37
      command: ["sh", "-c"]
      args:
        - "dd if=/dev/zero of=/scratch/test.bin bs=1024 count=1024; ls -lh /scratch/test.bin; exec sleep 3600"
      resources:
        requests:
          cpu: 25m
          memory: 16Mi
          ephemeral-storage: 64Mi
        limits:
          cpu: 250m
          memory: 64Mi
          ephemeral-storage: 256Mi
      volumeMounts:
        - name: scratch
          mountPath: /scratch
  volumes:
    - name: scratch
      emptyDir:
        sizeLimit: 64Mi
kubectl apply -f kt15-ephemeral.yaml
kubectl wait --for=condition=Ready pod/bounded-writer -n kt15 --timeout=120s
kubectl logs bounded-writer -n kt15 --tail=20
kubectl describe pod bounded-writer -n kt15

预期只写入约 1 MiB 测试数据,而不是触发驱逐。观察资源声明与 emptyDir 的位置,理解“临时目录大小边界”和“容器临时存储限额”不是两个互不相关的额外容量。

这些限额依赖 kubelet 对节点存储的支持和统计,部分情形以观察后驱逐的方式执行,不等于所有文件系统都被同步硬配额锁死。因此不能在极小节点上靠限额放心运行无限写入程序。

六、修复实践:停止增长源,再恢复资源余量

若真实故障来自异常日志,修复刷屏与日志保留/采集配置;Kubernetes 常用 CRI 日志和 kubelet 轮转规则,不要直接照搬 Docker json-file 配置期待解决所有节点日志。

若来自无上限缓存或批处理临时文件,给应用明确生命周期与清理策略。若业务容量合理,则评估扩容、迁移或使用适合的存储,而不是把所有写入改到一个未规划的 hostPath。

镜像与容器回收由运行时和 kubelet 配合管理,不要手工删除 /var/lib/kubelet 或 containerd 数据目录。已删除文件仍被进程持有时,目录大小与文件系统可用空间也可能不同,应继续确认打开文件与相关进程。

七、验证与总结

验证节点压力条件稳定恢复、磁盘/inode 有余量、替代 Pod Ready,且相同业务量下空间不再持续耗尽。旧 Evicted 对象可以在保留必要证据后按管理规则清理,但它不是根因修复。

QoS、requests 和优先级会影响资源管理,但没有一个“永不被驱逐”的简单开关。应结合节点压力、业务重要性和容量规划整体判断。

这类故障的闭环是:保留驱逐原因 → 定位节点资源 → 确认写入层和增长源 → 受控恢复 → 观察替代副本与持续趋势。让列表变干净,只是收尾的一部分。

官方参考


上一篇 · 系列目录 · 下一篇


评论