这个坑值得记一笔。阿里云 2 核 4G 的 Ubuntu 22.04,Docker 24.0.7,容器基于 distroless 镜像构建,进去排查时报 OCI runtime exec failed: exec failed: unable to start container process: exec: "bash": executable file not found in $PATH,换成 /bin/sh 也是同样的报错,重启容器没有变化。

刚开始盯着「容器的 PATH 被 ENTRYPOINT 脚本改过,shell 其实在 /busybox 下面」,折腾了半个多小时,排掉了。

真正麻烦的地方在于,几个原因的现象几乎一样。镜像基于 distroless 构建,里面根本没有 bash 这个可执行文件;Dockerfile 用 scratch 做最终阶段,只拷了一个静态编译的二进制;镜像层被裁剪工具删过,/bin/sh 的软链指向了不存在的文件。

动手时先列出镜像里实际存在的可执行文件

docker run --rm --entrypoint ls app:v2 /bin /usr/bin

从宿主机进入容器的命名空间排查

docker inspect -f '{{.State.Pid}}' web && nsenter -t $PID -m -u -i -p -n sh

起一个带工具的临时容器共享它的网络

docker run --rm -it --network container:web nicolaka/netshoot

剩下的就是确认问题后重建带 shell 的调试镜像

docker commit web web:debug

别只看报错消失,验证要多做一步。nsenter 进入后能看到 /bin/sh,docker exec -it web sh 正常返回提示符,业务进程全程没有重启。

给生产镜像补 shell 会扩大攻击面,调试完应该回退到原镜像,日常排查用 nsenter 或临时容器更稳妥。报错文案容易误导,真正的原因往往在相邻那一层的日志里。

作者 9823189