使用Docker Compose的交互式shell

594

使用Docker Compose是否有办法仅启动容器中的交互式shell?我在我的docker-compose.yml文件中尝试了以下内容:

myapp:
  image: alpine:latest
  entrypoint: /bin/sh

当我使用 docker-compose up 启动容器时,它会立即退出。是否有任何标志可以添加到entrypoint命令或作为myapp的附加选项,以启动交互式shell?

我知道有原生的docker命令选项可以实现此目的,只是好奇是否也可以仅使用Docker Compose实现。


1
这本应该不起作用。例如,如果您的compose文件中有多个带有/bin/sh入口点的图像,它应该做什么? - Xiongbing Jin
2
嗯,为什么不启动多个 shell 呢?例如,一个 shell 进入 mysql 容器以使用 mysql cli,另一个 shell 进入备份容器以运行备份命令? - drubb
6
docker-compose run myapp是什么意思? - ivoba
3
问题出在docker-compose run myapp无法暴露端口,因此您需要使用docker-compose run --service-ports myapp,但这仍然不太方便。 - The Fool
entrypoint: /bin/sh should be entrypoint: "/bin/sh" - codentary
2
@codentary 这只是YAML,所以在这种特定情况下引号是可选的。 - Gogowitsch
15个回答

766

您需要在docker-compose.yml文件中包含以下行:

version: "3"
services:
  app:
    image: app:1.2.3
    stdin_open: true # docker run -i
    tty: true        # docker run -t


第一个对应于docker run中的-i,第二个对应于-t

4
“stdin_open”是缺失的链接,只要我连接到已经运行shell的容器中,它就可以为我提供预期的行为。” - Charney Kaye
44
即使我也遇到了同样的问题。 最好运行 docker-compose run <service_name> - Aswath K
4
这是添加在哪里?在服务内部吗? - problemofficer - n.f. Monica
11
如果我使用 docker-compose up 和入口点 ["/bin/sh"],这仍然无法正常工作。虽然容器不会立即停止运行,但输入是否附加到入口点上呢? - doraemon
4
适用于使用docker attach <容器名称>的操作。 - Alexander
显示剩余6条评论

444

使用docker-compose获取交互式shell的规范方式是:

docker-compose run --rm myapp

(以您的示例中使用的服务名称 myapp 为例。更通用地说,它必须是Docker Compose文件中现有的服务名称,myapp 不仅仅是你选择的命令。例如:用 bash 而不是 myapp 将无法在此处工作。)

您可以设置 stdin_open: true, tty: true,但这实际上不会为您提供一个适当的 shell,因为所有容器的日志都被流式传输。

您还可以使用

docker exec -ti <container name> /bin/bash

获取正在运行容器的 shell。


31
请注意,如果您要公开任何端口(例如Web服务器),则需要添加“--service-ports”。 - epelc
13
我已经更新了我的答案,提供更多信息,并添加了 --rm 标志以便删除容器。@lynx0123 的回答是不正确的。如果运行 docker-compose up,您将无法获取交互式 shell。 - dnephin
2
要在Windows上使用Docker工作,我需要docker-compose v. 1.9.0(请参阅Github问题和PR)。截至2016年12月19日,这仅随Docker for Windows的beta版本一起发布。然后docker-compose run就可以工作了。您还需要将command: /bin/bash添加到docker-compose.yml中。 - Joseph238
9
这应该是最佳答案。这就是我来到这里寻找的东西。 - mkasberg
10
执行命令 "docker-compose up -d" 并在后台运行容器,然后使用命令 "docker attach <container_name>" 进入该容器。 - Aaron McMillin
显示剩余4条评论

142

官方的入门示例(https://docs.docker.com/compose/gettingstarted/)使用以下docker-compose.yml:

version: "3.9"
services:
  web:
    build: .
    ports:
      - "8000:5000"
  redis:
    image: "redis:alpine"

在使用docker-compose up启动后,你可以通过以下方式进入redis容器或web容器:

docker-compose exec redis sh

docker-compose exec web sh

docker-compose exec redis sh
docker-compose exec web sh 

为什么我不能像其他图片那样做到这一点,我只是在这里问了 https://dev59.com/ilEG5IYBdhLWcg3wZcdh - jcarlosweb

89

7
非常感谢。只是为了澄清,docker-compose run [在docker-compose.yml中定义的服务名称] [sh或bash]。 - theeranitp
1
我认为这是最直接的答案。我需要按照建议进行验证环境是否正确,通过运行 docker-compose run <service-name> sh 命令来检查服务。 - Nae
1
为了覆盖在 docker-compose.yml 中配置的 entrypoint,我必须使用以下命令:docker-compose run --entrypoint /bin/bash myapp - hfs
这真的很管用,在使用docker-compose时!! - Vincent
一个很好的替代命令是在容器内交互式地运行后,可以避免使用“docker-compose up ”。我使用“docker-compose -f other-compose-file.yml run myapp sh”来使用alpine镜像中特定版本的node。其中,“-f”指定yml文件,该文件声明了myapp服务。 - chisim

61

如果未来的任何人也到这里闲逛:

docker-compose exec service_name sh
或者
docker-compose exec service_name bash

或者你可以像这样运行单行代码:

docker-compose exec service_name php -v

那是在你已经启动和运行了容器之后。

service_name 在你的 docker-compose.yml 文件中被定义。


1
这是不正确的,应该是:docker-compose exec <service_name>,而不是 docker-compose exec <container_name> - loicgasser
为什么我不能像其他图片那样做到这一点,我只是在这里问了 https://dev59.com/ilEG5IYBdhLWcg3wZcdh - jcarlosweb

38

使用docker-compose,我发现最简单的方法是在启动容器后运行docker ps -a命令,获取我想要进入交互式Shell的容器的ID(我们称其为xyz123)。

然后执行以下命令就可以打开一个交互式Shell了:docker exec -ti xyz123 /bin/bash

这样,你就可以愉快地使用交互式Shell了。


2
不确定为什么这个被踩了 - 这是一个很好的调试方式,以防出现任何问题,我使用这种方法取得了成功,就像在阅读这个解决方案的一分钟内。 - ericmjl
6
因为这是一个两步骤过程,问题明确要求使用docker-compose的功能,并且已经在另一个答案中进行了说明。 - OneCricketeer

10

这个问题对我来说非常有趣,因为当我运行容器时,执行完毕后立即退出,我使用-it参数进行修复:

docker run -it -p 3000:3000 -v /app/node_modules -v $(pwd):/app <your_container_id>

当我需要使用Docker Compose自动化它时:

version: '3'
services:
    frontend:
        stdin_open: true
        tty: true
        build: 
            context: .
            dockerfile: Dockerfile.dev
        ports: 
            - "3000:3000"
        volumes: 
            - /app/node_modules
            - .:/app

这就是诀窍:stdin_open: true,tty: true

这是一个使用create-react-app生成的项目

Dockerfile.dev看起来像这样:

FROM node:alpine

WORKDIR '/app'

COPY package.json .
RUN npm install

COPY . . 

CMD ["npm", "run", "start"]

希望这个例子能帮助其他人将前端(以react为例)运行在docker容器中。

嘿@Carnaru,你能告诉我在卷部分使用“- /app/node_modules”命令的原因吗? - aashir khan
@aashirkhan 这与使用卷以及容器使用容器中的 node_modules 而不是本地文件有关。 - A.com

10
你可以使用以下命令在docker-compose中获得一个交互式shell(假设yml文件中指定了一个名为myservice的服务):
$ docker-compose exec myservice sh


在使用不同的yml文件名(例如docker-compose-mycompose.yml)时,为了获得交互式终端,需要指定yml,如下所示:
$ docker-compose -f docker-compose-mycompose.yml exec myservice sh


这需要容器已经在运行。这需要Dockerfile有一个CMD[...]行,不会立即退出,这似乎是问题的情况。 - undefined

9

我更倾向于

docker-compose exec my_container_name bash

5

对于这个旧问题的补充,上次我只有一个案例。sh和bash之间的区别,因此可能会发生一些情况,某些情况下bash无法工作,只有sh可以。

因此,您可以使用以下命令: docker-compose exec CONTAINER_NAME sh

在大多数情况下,您可以使用以下命令: docker-compose exec CONTAINER_NAME bash

如果您有时间,可以在这里详细了解sh和bash之间的区别: https://www.baeldung.com/linux/sh-vs-bash


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接