如何使用其他命令启动已停止的Docker容器?


250

我想用其他命令启动一个停止的Docker容器,因为默认命令崩溃了-这意味着我无法启动该容器,然后使用'docker exec'。

基本上,我想启动一个外壳,以便可以检查容器的内容。

幸运的是,我使用-it选项创建了容器!

Answers:


380

查找您停止的容器ID

docker ps -a

提交停止的容器:

此命令将修改后的容器状态保存到新映像中 user/test_image

docker commit $CONTAINER_ID user/test_image

从另一个入口点开始/运行:

docker run -ti --entrypoint=sh user/test_image

入口点参数描述:https ://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime

注意:

上面的步骤只是启动具有相同文件系统状态的已停止容器。这对于快速调查非常有用。但是环境变量,网络配置,附加卷和其他人员不会被继承,您应该显式指定所有这些参数。

从此处借用了启动已停止容器的步骤:(最新评论)https://github.com/docker/docker/issues/18078


1
不,图像是只读的。它将修改后的容器状态保存到新映像中test_image
Dmitriusan

4
这几乎错过了所有有关环境,卷,UID的配置,…与停止的容器的共同点是文件系统(这也许对某些用户来说足够了)
Florian Klein

4
如果能以某种方式获得相同的环境,网络配置和附加的卷,那将是很棒的。是否可以将inspect输出转换为用于后续运行的配置?
Otheus

2
@Webman,是的,但是对于在停止容器之前已安装的卷而言并非如此。下次启动容器时,您将必须显式附加相同的卷
Dmitriusan

1
@EmreTapcı,我认为这样做与Docker意识形态背道而驰。与虚拟机相比,容器旨在成为一次性使用的即弃即用实体。您可以尝试遵循aaa90210的答案,但这将是一个hack。
德米特里桑

126

编辑此文件(与您停止的容器相对应):

vi /var/lib/docker/containers/923...4f6/config.json

更改“路径”参数以指向您的新命令,例如/ bin / bash。您也可以设置“ Args”参数,以将参数传递给命令。

重新启动docker服务(注意,这将停止所有正在运行的容器):

service docker restart

列出您的容器,并确保命令已更改:

docker ps -a

启动容器并连接到它,现在应该在外壳中了!

docker start -ai mad_brattain

使用Docker 1.7.1在Fedora 22上工作。

注意:如果您的外壳不是交互式的(例如,您没有使用-it选项创建原始容器),则可以改为将命令更改为“ / bin / sleep 600”或“ / bin / tail -f / dev / null”给您足够的时间来执行“ docker exec -it CONTID / bin / bash”作为获取shell的另一种方法。

注意2:较新版本的docker具有config.v2.json,您需要在其中更改Entrypoint或Cmd(感谢user60561)。


44
我的眼睛。我的眼睛。我希望这是某个功能请求,可以在Docker中正确处理。
gertvdijk

2
@AlexeyStrakh,您可以尝试运行“ / usr / bin / sleep 600”,然后执行“ docker exec -it / bin / bash”以获取外壳程序。虽然我不确定如何在该Path变量上放置参数。否则,尝试找到另一个可以存活足够长的命令来执行一个exec,或者查看Dmitriusan的回答。
aaa90210 '16

3
那是对该问题的唯一真正准确的答案:所有其他命题都运行“几乎相同”的容器,但他们忘记了体积,env,UID等……
Florian Klein

3
在我的情况下,/ usr / bin / sleep无法使用。我在..."Path":"tail","Args":["-f","/dev/null"]...
nevrome上

4
较新版本的docker具有config.v2.json,您需要在其中更改EntrypointCmd
user60561

20

在Entrypoint脚本的顶部添加一个检查

Docker确实需要将其实现为一项新功能,但是这是另一个解决方法,适用于您的入口点在成功或失败后终止的情况,这可能使调试变得困难。

如果您还没有一个Entrypoint脚本,请创建一个可以运行容器所需命令的脚本。然后,在此文件的顶部,将这些行添加到entrypoint.sh

# Run once, hold otherwise
if [ -f "already_ran" ]; then
    echo "Already ran the Entrypoint once. Holding indefinitely for debugging."
    cat
fi
touch already_ran

# Do your main things down here

为了确保cat保持连接,您可能需要提供一个TTY。我正在使用我的Entrypoint脚本运行容器,如下所示:

docker run -t --entrypoint entrypoint.sh image_name

这将导致脚本运行一次,并创建一个指示其已经运行的文件(在容器的虚拟文件系统中)。然后,您可以重新启动容器以执行调试:

docker start container_name

当您重新启动容器时,already_ran将找到该文件,从而导致Entrypoint脚本停顿cat(它将永远等待永远不会出现的输入,但会使容器保持活动状态)。然后,您可以执行调试bash会话:

docker exec -i container_name bash

在容器运行时,如果需要调试,也可以删除already_ran并手动执行entrypoint.sh脚本以重新运行它。


3
另外,您可以使入口点运行/bin/sh而不是cat-然后始终可以在重新启动时进入。您的解决方案动摇了!
丹尼·杜莱

4

我的问题:

  • 我开始用一个容器 docker run <IMAGE_NAME>
  • 然后向该容器中添加一些文件
  • 然后我关闭了容器,并尝试使用与上述相同的命令再次启动它。
  • 但是当我检查新文件时,它们不见了
  • 当我跑步时,docker ps -a我可以看到两个容器。
  • 这意味着每次我运行docker run <IMAGE_NAME>命令时,都会创建新映像

解决方案: 要在您首先创建的同一容器上运行,请遵循以下步骤

  • docker ps 得到你的容器的容器
  • docker container start <CONTAINER_ID> 启动现有容器
  • 然后,您可以从离开的地方继续。例如docker exec -it <CONTAINER_ID> /bin/bash
  • 然后,您可以决定从中创建新图像

这不能回答问题。OP希望知道如何重新启动容器,但是所用参数与docker run <containerID>
CodeBlooded

2

我接受了@Dmitriusan的回答,并将其作为别名:

别名docker-run-prev-container ='prev_container_id =“ $(docker ps -aq | head -n1)” && docker commit“ $ prev_container_id”“ prev_container / $ prev_container_id” && docker run -it --entrypoint = bash“ prev_container / $ prev_container_id“'

将其添加到您的~/.bashrc别名文件中,您将获得一个漂亮的新docker-run-prev-container别名,该别名会将您放入先前容器中的外壳中。

对调试失败有用docker build


2

这并不是您所要的,但是docker export如果您要检查文件,则可以在已停止的容器上使用。

mkdir $TARGET_DIR
docker export $CONTAINER_ID | tar -x -C $TARGET_DIR

1

没有指定容器是否正在退出,只是您的代码崩溃了,您需要查看容器中正在发生什么。如果没有退出,这是另一个潜在的解决方案。

使用获取容器ID docker ps

docker exec -it 665b4a1e17b6 /bin/sh

如果将入口点设置为有问题的东西,则也可以按照Dmitriusan的答案中的建议将其覆盖。还应注意,您可以使用附加到任何正在运行的容器docker attach。这么多解决方案不同的解决方案。我只是看不到需要提交图像。似乎没有必要。

对于泊坞窗EXEC文件- https://docs.docker.com/engine/reference/commandline/exec/

对于泊坞窗文件附上- https://docs.docker.com/engine/reference/commandline/attach/


-12

我实际上不同意这两个答案。如果您只想查看容器中的内容,则可以运行此命令以获取外壳。无需更改所有或任何配置的入口点。

docker run -it <image_name> bash

12
这不起作用,因为操作人员正在询问容器而不是图像。
彼得·弗拉贝尔

我想您的权利,但是没有理由这样做。您可以将日志通过管道发送到stdout,docker logs <container_id> --follow并为您提供所需的内容。另一种选择是使用上面的命令,然后在dockerfile中使用相同的命令在该映像上启动崩溃服务,然后从那里调试。
deadbabykitten

4
run命令从映像创建一个新容器。它不会启动已停止的容器。
Waleed Abdulla

2
嗯,..这不是docker的意义在于每个图像都可以以完全相同的方式旋转吗?这否定了你的观点。他不需要启动已停止的容器。任何容器都完全相同,因此启动或停止哪个容器都没有关系。他只是在检查内容。最简单的方法是执行命令并将命令或命令的输出管道传输到日志。你们有时会针对最简单的问题提出最复杂的解决方案。
deadbabykitten

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.