容器排障这件事,表面上看是技术问题,实际上更像是一场耐心的较量。尤其是刚接触 Kubernetes 运维那阵子,常常被 Pod 状态折腾到怀疑人生——服务容器启动后几秒就退出,Kubernetes 反复重启,Pod 不断卡在 CrashLoopBackOff。想看一眼镜像里的配置文件、启动脚本、日志目录?根本进不去。这种“明明有错却无从下手”的无力感,相信不少人都深有体会。

一、问题现场:CrashLoopBackOff 的真实困境
典型现象一目了然:
kubectl get pod
NAME READY STATUS RESTARTS
nignx-xxx 0/1 CrashLoopBackOff 17
常见的痛点在于——
- 容器启动即退出,日志无法获取
kubectl exec无法进入容器kubectl logs只输出不完整信息- 不清楚镜像内究竟有哪些配置
面对这种困境,多数人的第一反应是反复查看日志、修改代码、重新构建,但往往耗时费力却不奏效。其实有更直接的解决思路。
二、核心思路:让容器“别死”
一句话总结:只要能让容器先运行起来,就一定能进去排障。下面是在生产环境中最常用、也最稳妥的 3 种方法。
1. 方式一:直接用 docker run 查看镜像内容(最快)
使用场景
- 仅需确认镜像内文件是否存在
- 不依赖 Kubernetes 环境
- 本地或节点上能够拉取到镜像
示例:查看镜像内目录及文件权限
# 查看容器内某个目录的文件或权限
docker run --rm -ti --entrypoint ls -l /opt reg.nginx.test:5000/dev/nginx:master_amd64
# 通过替换 entrypoint 覆盖镜像启动命令,直接进入镜像
docker run -ti --rm --entrypoint=/bin/sh reg.nginx.test:5000/dev/nginx:master_amd64
这个命令的核心作用:绕过镜像预设的启动指令,用一个明确的 shell 或命令替代,直接进入容器内部查看文件系统。无需纠结 Pod 的状态。
2. 方式二:其他方式让容器不退出
# 方式一
docker run -d --name nginx-test reg.nginx.test:5000/dev/nginx:master_amd64 tail -f /dev/null
# 方式二
docker run -d \
--name init-job-test \
--entrypoint sh \
nginx-test reg.nginx.test:5000/dev/nginx:master_amd64 \
-c "while true; do sleep 3600; done"
这两种方式非常适合快速验证——配置文件是否存在、路径是否写错、镜像构建是否完整。几分钟就能得出答案,无需走完完整的 CI/CD 流程。
三、K8s 场景下,让 Pod 先“活着”
1. 场景说明
容器一启动就退出,Pod 持续处于 CrashLoopBackOff 状态,导致无法 exec、日志输出不全。此时需要在 Pod 层面让它“保持运行”。
2. 方法一:临时修改 Deployment 中的 TTY
spec:
containers:
- name: app
image: xxx
tty: true
原理很简单:保持标准输入打开,防止容器因没有前台进程而立即退出。适用于启动脚本是 shell、程序较简单的场景。
2. 方法二(更稳):让容器 sleep infinity
containers:
- name: app
image: xxx
command: ["sleep", "infinity"]
这是最推荐的方式。为什么?容器不会退出,Pod 状态直接变为 Running,可以随意 kubectl exec 进去查看。没有比这更省心的调试入口了。
四、方式三:docker-compose / 镜像启动脚本排障
使用场景
- 本地 docker-compose 启动即退出
- 怀疑镜像中的 ENTRYPOINT / CMD 存在异常
- 启动脚本内置于镜像中
解决方法:覆盖启动命令。
services:
app:
image: xxx
command: sleep infinity
然后执行:
docker-compose up -d
docker exec -it app bash
这种方式特别适合分析 ENTRYPOINT 执行顺序、启动脚本报错、环境变量缺失等问题。将容器“定格”在启动后的瞬间,可以尽情翻查。
五、关于 restartPolicy 的重要说明(K8s 必看)
调试 Pod 时,别忘了给 restartPolicy 加上 Never:
restartPolicy: Never
为什么要加?防止容器不断重启,避免被 kubelet 反复拉起、杀死。适用于一次性排障的场景,尤其适合临时调试 Pod,省去等待重启的烦躁。
