如何在已经存在的Docker容器上运行命令?


492

我创建了一个容器,-d因此它不是交互式的。

docker run -d shykes/pybuilder bin/bash

我看到容器已退出:

CONTAINER ID        IMAGE                     COMMAND             CREATED             STATUS                      PORTS               NAMES
d6c45e8cc5f0        shykes/pybuilder:latest   "bin/bash"          41 minutes ago      Exited (0) 2 seconds ago                        clever_bardeen

现在,我想在计算机上偶尔运行命令并退出。只是为了得到回应。

我试图启动机器。我尝试附加。我以为我可以run用一个容器打电话,但这似乎是不允许的。使用start似乎可以运行,然后迅速存在。

我想退出后回到互动模式。

我试过了:

docker attach d6c45e8cc5f0

但是我得到:

2014/10/01 22:33:34 You cannot attach to a stopped container, start it first

但是,如果我启动它,它仍然会退出。赶上22.我赢不了。


您怎么知道Docker容器已经退出?您运行了什么命令?
Thufir

docker container ls -a
布兰登·曼彻斯特

如果仅需要文件系统:如何使用其他命令启动已停止的Docker容器?(请注意,当容器停止时,环境变量和内存中的其他内容已经丢失。)
Franklin Yu

Answers:


548

在2014年10月,Docker团队引入了docker exec命令https : //docs.docker.com/engine/reference/commandline/exec/

因此,现在您可以在运行容器中运行任何命令,只需知道其ID(或名称)即可:

docker exec -it <container_id_or_name> echo "Hello from container!"

请注意,该exec命令仅适用于已经运行的容器。如果容器当前已停止,则需要首先使用以下命令运行它:

docker run -it -d shykes/pybuilder /bin/bash

这里最重要的是-d选项,它代表detached。这意味着您最初提供给容器(/bin/bash)的命令将在后台运行,并且容器不会立即停止


120
这不适用于已停止的容器,只能用于正在运行的容器。因此,如果您有一个立即停止运行的容器(如该问题所示),则实际上无法使其中的其他内容运行。
interfect

4
@interfect是正确的,CDR LDN有更全面的答案。
Jan-Philip Gehrcke博士2015年

6
@ Jan-PhilipGehrcke顺便说一句,此人的用户名已从CDR LDN更改cdrev为下面的答案(stackoverflow.com/a/26181666/149428)。
泰勒·埃德米斯顿,2016年

3
为什么要过去-it
尤利安·奥诺弗雷

4
天哪,为什么这么复杂?似乎是您需要做的最基本的事情。我们一定不能按照他们的意图使用它。
sudo

287

容器将退出,因为您给出的命令将结束。使用以下选项可以使其保持活动状态:

  • -i 即使未连接STDIN,也请保持打开状态。
  • -t 分配伪TTY。

因此,您的新run命令是:

docker run -it -d shykes/pybuilder bin/bash

如果要附加到已经运行的容器:

docker exec -it CONTAINER_ID /bin/bash

在这些示例中,/bin/bash将其用作命令。


2
尝试docker exec -it CONTAINER_ID /bin/bash -c "export VAR=1 && echo $VAR"并打印了空变量(预期为1)。我想念什么?
Yellow01

运行'docker exec -it CONTAINER_ID / bin / bash'后,它会正确地进入bash,但无法与其交互。
蓝云'18

1
但是,如果我使用docker-compose,-it则不可用。
adnanmuttaleb

120

因此,我认为答案比上面的许多误导性答案更简单。

启动已停止的现有容器

docker start <container-name/ID>

停止正在运行的容器

docker stop <container-name/ID>

然后登录到容器的交互式外壳

docker exec -it <container-name/ID> bash

启动现有容器并将其附加到一个命令中

docker start -ai <container-name/ID>

当心,这将停止出口的容器。但是通常,您需要启动容器,完成后附加并停止它。


正在运行的docker attach <容器名称/ ID>
谢坤明

9
@Peter T.实际上,我发现您的回答比其他人提供的更为简洁。我不明白为什么人们喜欢使一个非常简单的问题复杂化。感谢彼得这个答案。
Helen Neely

1
这要求你这么做的时候搬运工创建,你-它做到了 stackoverflow.com/questions/45216612/... 否则将无法启动..所以你会做码头工人开始<容器的id>,然后泊坞窗PS -l并且您会发现开始后它没有启动。然后连接将失败。所以也必须使用-it创建。
barlop

1
@Peter最相关的答案
Nilanjan Sarkar,

1
这是最准确的答案!
nagendra547

91

为了扩展katrmr的答案,如果容器由于错误而停止并且无法启动,则需要将commit其转换为图像。然后,您可以在新映像中启动bash:

docker commit [CONTAINER_ID] temporary_image
docker run --entrypoint=bash -it temporary_image

1
仅供参考,我做了这么多事情,以至于我组合了一个dshell在各种情况下自动执行的命令-github.com/avirshup/docker-cli-sugar
Aaron V

41

此处的某些答案具有误导性,因为它们与正在运行而不是停止的容器有关。

Sven Dowideit在Docker论坛上解释说,容器已绑定到其进程(而Docker似乎无法更改已停止容器的进程,这至少是由于其内部结构所致:https//github.com/docker/docker/issues / 1437)。因此,基本上唯一的选择是commit将容器包含到图像中,run并使用不同的命令。

请参阅https://forums.docker.com/t/run-command-in-stopped-container/343
(我相信“ ENTRYPOINT带有参数”方法也不起作用,因为您仍然无法更改停止容器的参数。)


2
注意:bin/bash不运行-it将不会更改容器中的任何内容,因此确实没有必要进行提交,而CDR LDN可以为OP的特定情况提供正确的答案。仍然commit是如何更改容器过程的技术问题的答案。
katrmr 2015年

Candlerb在“容器停止运行命令”中的注释建议使用一次性映像,其中包含非活动容器中的卷对我有用:docker run --rm --volumes-from CONTAINER -i busybox tar cO / var /目录| gzip -c>〜/ mydir_backup.tgz
eel ghEEz

这是对所提问题的实际答案。容器已绑定到其进程,因此无法更改命令。
cjsimon

21

我必须使用bash -c来运行命令: docker exec -it CONTAINER_ID bash -c "mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql"


1
-c为我工作。难怪为什么单单的bash不工作(没有得到提示)
安德烈Werlang

18

创建一个容器并向其发送命令:

docker create --name=my_new_container -it ubuntu
docker start my_new_container
// ps -a says 'Up X seconds'
docker exec my_new_container /path/to/my/command
// ps -a still says 'Up X+Y seconds'
docker exec my_new_container /path/to/another/command

这是对这个问题的好答案。如果要在创建后启动容器并能够在其中执行“ docker exec”命令,则必须在docker create命令中使用“ -it”标志进行创建。
joanlofe

8

这是我使用上面的CDR LDN答案和在这里找到的答案组合而成的答案。

以下示例从映像启动Arch Linux容器,然后git使用该pacman工具将其安装在该容器上:

sudo docker run -it -d archlinux /bin/bash
sudo docker ps -l
sudo docker exec -it [container_ID] script /dev/null -c "pacman -S git --noconfirm"

就这些。


5

如果您尝试运行shell脚本,则需要将其作为bash运行。

docker exec -it containerid bash -c /path/to/your/script.sh

4

将命令通过管道发送到stdin

必须删除-t才能使其正常工作:

echo 'touch myfile' | sudo docker exec -i CONTAINER_NAME bash

与有时使用CLI选项相比,这可能更方便。

经过测试:

sudo docker run --name ub16 -it ubuntu:16.04 bash

然后在另一个外壳上:

echo 'touch myfile' | sudo docker exec -i ub16 bash

然后在第一个外壳上:

ls -l myfile

在Docker 1.13.1,Ubuntu 16.04主机上进行了测试。



3

不幸的是ENTRYPOINTdocker run --entrypoint要实现这个目标,不可能用参数来覆盖。

注意:您可以使用--entrypoint覆盖ENTRYPOINT设置,但这只能将二进制文件设置为exec(将不使用sh -c)。


3

我想指出,最佳答案有点误导。

执行的问题docker run是每次都会创建一个新容器。但是,在某些情况下,我们想重新使用旧容器或不占用新容器的空间。

(给出的clever_bardeen是创建的容器的名称...)

如果是OP,请执行以下命令,以确保首先运行docker映像:

docker start clever_bardeen

然后,使用以下命令执行docker容器:

docker exec -it clever_bardeen /bin/bash

2

对于Mac:

$ docker exec -it <container-name> sh

如果要以root用户身份连接:

$ docker exec -u 0 -it <container-name> sh

1

简单的答案:同时启动并附加。在这种情况下,您将完全按照要求进行操作。

docker start <CONTAINER_ID/CONTAINER_NAME> && docker attach <CONTAINER_ID/CONTAINER_NAME> 

确保改变 <CONTAINER_ID/CONTAINER_NAME>



1

我正在运行Windows容器,我需要在docker容器中查找创建和复制的文件和文件夹。

为了做到这一点,我使用了以下docker entrypoint命令来使命令提示符在容器内运行或附加到容器。

ENTRYPOINT ["C:\\Windows\\System32\\cmd.exe", "-D", "FOREGROUND"]

这帮助我将命令提示符附加到容器,并使容器保持活动状态。:)


0

恢复和访问最近退出的容器的快速方法:

docker start -a -i `docker ps -q -l`

0

我通常使用这个:

    docker exec -it my-container-name bash

与正在运行的容器进行持续交互。

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.