如何用 docker-compose 启动交互式 Shell?
一次性调试用 docker compose run;运行中的服务用 docker compose exec 服务名 sh。若以 shell 为主进程,可配 tty/stdin_open,up -d 后再 attach;up 本身不等于进入交互 shell。
两种路径:①容器还没跑——yml 里给服务配 tty: true、stdin_open: true、command: sh,用 up -d 启动后再 attach 连接主进程;一次性调试更适合 compose run --rm;②服务已在跑——docker compose exec 服务名 sh 直接在运行容器里开 shell(更常用)。
方式一:启动即进入 shell
services:
myservice:
image: python:3.12
tty: true # 分配伪终端(等价 docker run -t)
stdin_open: true # 保持标准输入(等价 docker run -i)
command: sh
docker compose run --rm --no-deps --entrypoint sh myservice
# 或先后台启动,再接入服务主进程
docker compose up -d && docker compose attach myservice
up 主要负责启动与聚合输出,不等于自动连接交互 shell。command 仍受镜像 ENTRYPOINT 影响,必要时像上例显式覆盖。
适合:一次性调试环境、工具容器(装好了 CLI 的镜像,进去敲命令)。
方式二:exec 进运行中的服务(日常首选)
docker compose exec web sh # 有 bash 用 bash 体验更好
docker compose exec web python manage.py shell # 直接执行特定命令
服务是长驻进程(Web 服务等)时用这个——不打断主进程,exit 只退你的 shell。
两者对比
| up + tty/stdin_open | exec | |
|---|---|---|
| 适用 | 专门的工具/调试容器 | 运行中的服务容器 |
| 主进程 | shell 就是主进程 | 不受影响 |
| 退出后 | 容器停止 | 容器继续跑 |
常见报错
the input device is not a TTY:在非交互环境可对 compose exec/run 使用 -T;多副本 exec 还应以 --index 指定目标- 服务起不来立刻退出:command 是 sh 但忘了配
tty: true+stdin_open: true,sh 没输入源立即退出
常见问题(FAQ)
Q:docker compose run 和 exec 有什么区别?
A:run 新起一个容器,默认不发布服务端口、可能启动依赖,可用 --service-ports/--no-deps 控制;它仍可能共享配置中的卷和外部状态。适合一次性命令(如 docker compose run web python manage.py migrate);exec 进已运行的容器。
Q:attach 和 exec 进 shell 选哪个?
A:exec。attach 接主进程,Ctrl+C 可能将信号传给主进程并停止服务。
Q:容器里没有 sh?
A:distroless 类镜像没 shell,换 debug 变体镜像或拷文件排查。