讲解

容器不是虚拟机,「登录容器」其实是让 Docker 在容器的命名空间里再启动一个进程——这就是 docker exec。标准用法 docker exec -it 容器名 sh:-it 分配终端,sh 换成 bash(镜像里有的话)更顺手。exec 进去的 shell 退出不影响主进程,这是它和 attach 的本质区别:docker attach 是把终端接到容器的主进程上,退出时容易把主进程一起带走(Ctrl+C 发的是 SIGINT 给主进程),生产上几乎只用 exec。

exec 不仅能开 shell,也常用来在运行中的容器里执行单条命令做检查:docker exec 容器 env 看环境变量、docker exec 容器 cat /etc/os-release 确认发行版、docker exec nginx 容器 nginx -t 校验配置。配合 --user 可以指定执行身份,配合 -e 可以注入临时环境变量,配合 --workdir 指定工作目录。

有两个镜像现实要知道:一是极简镜像(alpine 系)只有 sh 没有 bash,exec bash 会报 not found;二是 distroless/scratch 镜像连 shell 都没有,exec 任何命令都会失败——这正是它们的安全卖点,调试要靠日志、debug 镜像或 ephemeral容器(docker debug,较新版本提供)。选基础镜像时就要想清楚「将来怎么进去排查」。

示例

起一个常驻容器,然后 exec 单条命令做检查(不用开 shell):

docker run -d --name ohmydocs-verify-box alpine:3.21 sleep 300
docker exec ohmydocs-verify-box cat /etc/os-release | head -2

exec 指定工作目录和环境变量执行命令:

docker exec --workdir /tmp -e WHO=教程读者 ohmydocs-verify-box sh -c 'pwd; echo "你好, $WHO"'

交互式 shell 是 exec -it 的天下。此处用一条管道命令模拟交互会话里最常做的事(真实操作时你直接敲 docker exec -it ... sh):

docker exec ohmydocs-verify-box sh -c 'echo "容器内进程列表:"; ps aux'

用完即清:

docker rm -f ohmydocs-verify-box

常见坑

  • exec bash 报 not found:alpine 系镜像只有 sh;先 docker exec 容器 ls /bin 看看有什么。
  • attach 把服务搞挂:attach 到主进程后按 Ctrl+C 等于给主进程发中断;排查用 exec,attach 留给确实需要接管主进程输出的场景。
  • 忘了 -it:exec sh 不带 -it 时命令一执行完就退出,看起来像「没反应」。
  • distroless 镜像进不去:不是故障,是设计;提前规划日志输出和可观测性,或用对应 :debug 标签的镜像。

小结

exec 在容器里开新进程(推荐),attach 接管主进程(慎用);-it 开交互 shell,单条命令做检查也很好用;极简镜像可能没有 bash 甚至没有 shell。下一章把容器的服务暴露出来:端口映射。