背景
Kubernetes 节点磁盘快满了(90%+),
第一反应非常自然:清理无用容器和镜像。
节点使用的是 containerd,于是直接执行:
js
nerdctl prune -a
磁盘立刻释放,看起来一切正常。
几分钟后,Pod 开始起不来了。
问题现象
kubelet 持续报错,所有新 Pod 卡在 ContainerCreating:
js
Warning FailedCreatePodSandBox
Failed to create pod sandbox:
failed to get sandbox image "localhost/kubernetes/pause"
failed to pull image "localhost/kubernetes/pause:latest"
dial tcp 127.0.0.1:443: connect: connection refused
表现:
- 节点 NotReady
- Pod 无法创建
- 老 Pod 不受影响,新 Pod 全挂
紧急恢复操作
执行以下操作后集群恢复:
js
sudo sed -i 's|sandbox_image = .*|sandbox_image = "registry.k8s.io/pause:3.9"|' \
/etc/containerd/config.toml
sudo systemctl restart containerd
sudo systemctl restart kubelet
Pod 能正常创建,但问题本身并没有真正解释清楚。
根因分析
Kubernetes 强依赖 pause 镜像
在 containerd + kubelet 架构中:
- 每个 Pod 都需要一个 sandbox
- sandbox 本质是一个 pause 容器
- 镜像由 containerd 的 CRI 插件管理
containerd 默认配置:
js
sandbox_image = "registry.k8s.io/pause:3.9"
nerdctl prune -a 干了什么?
js
nerdctl prune -a
实际含义是:
删除所有未被"当前运行容器"使用的资源*
而问题在于:
- pause 镜像 不是运行容器
- 但 kubelet 随时需要
结果就是:
Kubernetes 的基础镜像被当成"无用资源"删掉了
为什么会拉 localhost/kubernetes/pause ?
当 sandbox 镜像不存在时:
- containerd 会尝试 fallback 地址
- 节点没有本地 registry
- 最终请求 https://localhost/v2/... 直接失败
这个错误非常迷惑,但根因还是 pause 镜像被删
生产环境安全清理建议
只清理停止容器(推荐)
js
nerdctl container prune
只清理悬空镜像
js
nerdctl image prune
带时间窗口清理镜像
js
nerdctl image prune --all --filter until=240h
磁盘满的"真正大头":日志
这一步经常能直接释放大量空间
js
find /var/log/containers -type f -name "*.log" -size +100M -exec truncate -s 0 {} \;
find /var/log/pods -type f -name "*.log" -size +100M -exec truncate -s 0 {} \;