进不去容器的常见原因
docker exec 报 not found、OCI runtime error 或直接失败,通常归为四类:精简镜像里根本没有 shell、容器已停止或暂停、镜像缺少想用的命令、以及进程空间受限(根文件系统只读或能力被裁剪)。排查思路不是硬进容器,而是换通道:从宿主机进入目标容器的命名空间、另起一个共享命名空间的调试容器,或用 Kubernetes 提供的调试容器能力。
基本信息
| 没有 shell | distroless 与 scratch 镜像不提供 sh,部分镜像连 ls 都没有 |
|---|---|
| 容器已停 | exec 只对运行中的容器有效,先确认状态再看日志与退出码 |
| nsenter 方案 | 在宿主机取容器 PID,进入其 mount、net、pid 等命名空间 |
| 临时容器 | 共享目标容器的 network 与 pid 命名空间,工具齐全且不影响原容器 |
| K8s 侧 | 用 kubectl debug 注入临时容器,无需改动原镜像 |
| 只读根文件系统 | 能进去也写不了文件,抓包结果要输出到宿主机挂载路径 |
典型使用场景
- distroless 服务出现网络异常,需要临时用完整工具排查
- 容器 OOM 重启前需要保留现场:一旦重启就进不去,必须先看日志与状态
- 抓包需要 tcpdump,但抓的是故障容器的网卡,靠共享网络命名空间解决
- 宿主机有 root 但容器内没有任何工具,只能从宿主侧进入命名空间
- 确认进程真实状态:用共享 pid 命名空间配宿主 ps,比容器内视角更全
替代进入方式
替代进入方式
docker inspect -f '{{.State.Status}}' myapp # 先确认容器状态
PID=$(docker inspect -f '{{.State.Pid}}' myapp)
sudo nsenter -t $PID -m -u -i -n -p sh # 进入容器的各命名空间
docker run --rm -it --network container:myapp \
--pid container:myapp nicolaka/netshoot # 共享命名空间的调试容器
docker exec -it myapp ls / # 镜像无该命令时同样报 not found报错与处理
| 报错或现象 | 常见原因 | 处理方式 |
|---|---|---|
| executable file not found | 镜像里没有该命令或没有 shell | 改用 nsenter 或共享命名空间的调试容器 |
| Container is not running | 容器已停止或处于暂停状态 | 先看退出码与日志,再决定是否重启 |
| OCI runtime exec failed | 运行时异常或根文件系统只读 | 换用调试容器,避免改动原容器 |
| 命令找不到但能进容器 | 极简镜像缺少工具 | 临时安装工具或直接换调试镜像 |
| 权限被拒 | 能力或安全策略受限 | 从宿主机侧用 nsenter 排查并留记录 |
nsenter 需要宿主机 root 权限:这是特权操作,生产环境要保留操作记录并限制可使用账号,否则它会成为绕过审计直接操作容器的通道。
判断顺序建议固定下来:先确认容器状态,再看镜像里有什么(镜像构建历史与 Entrypoint),最后才决定用哪种方式进入。这个顺序能省掉大量无效尝试,也能避免为了「进去看看」而重启容器破坏现场。