【问题标题】:How do I run a command on an already existing Docker container?如何在已经存在的 Docker 容器上运行命令?
【发布时间】:2014-11-27 00:30:06
【问题描述】:

我用-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


【解决方案1】:

假设图像使用默认入口点/bin/sh -c,运行/bin/bash 将立即退出守护程序模式(-d)。如果您希望此容器运行交互式 shell,请使用 -it 而不是 -d。如果您想在通常执行另一个进程的容器中执行任意命令,您可能想尝试nsenternsinit。详情请查看https://blog.codecentric.de/en/2014/07/enter-docker-container/

【讨论】:

    【解决方案2】:

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

    • -i 保持 STDIN 打开,即使未连接。
    • -t 分配一个伪 TTY。

    所以你的新run 命令是:

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

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

    docker exec -it CONTAINER_ID /bin/bash
    

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

    【讨论】:

    • 尝试了docker exec -it CONTAINER_ID /bin/bash -c "export VAR=1 && echo $VAR" 并打印了空变量(预期为1)。我错过了什么?
    • 在运行 'docker exec -it CONTAINER_ID /bin/bash' 后,它会正确进入 bash,但无法与之交互。
    • 但如果我使用 docker-compose,-it 不可用。
    【解决方案3】:

    2014 年 10 月Docker team introduced docker exec command: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) 将在后台运行,并且容器不会立即停止

    【讨论】:

    • 这不适用于已停止的容器,仅适用于正在运行的容器。因此,如果您有一个立即停止自身的容器,如问题所示,这实际上无法让其他东西在其中运行。
    • @interfect 是对的,CDR LDN 有更全面的答案。
    • @Jan-PhilipGehrcke 顺便说一句,此人的用户名已从 CDR LDN 更改为 cdrev 以获取以下答案 (stackoverflow.com/a/26181666/149428)。
    • 为什么要传递-it
    • 天哪,为什么这么复杂?似乎是您需要做的最基本的事情。我们不能按照他们的意图使用它。
    【解决方案4】:

    这里的一些答案具有误导性,因为它们涉及正在运行而不是停止的容器。

    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 with arguments”方法也行不通,因为您仍然无法将参数更改为已停止的容器。)

    【讨论】:

    • 注意:在没有 -it 的情况下运行 bin/bash 不会更改容器中的任何内容,因此实际上没有必要提交它,CDR LDN 为 OP 的特定情况提供了正确的答案。尽管如此,commit 还是解决了如何更改容器进程的技术问题。
    • candlerb 在 run-command-in-stopped-container 的评论建议使用一次性图像和非活动容器中的卷对我有用:docker run --rm --volumes-from CONTAINER -i busybox tar co /var/DIR | gzip -c > ~/mydir_backup.tgz
    • 这是对所提问题的实际答案。容器绑定到它们的进程,所以命令不能改变。
    【解决方案5】:

    要扩展 katrmr 的答案,如果容器因错误而停止并且无法启动,您需要将其 commit 发送到图像。然后你可以在新镜像中启动 bash:

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

    【讨论】:

    【解决方案6】:

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

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

    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"
    

    仅此而已。

    【讨论】:

      【解决方案7】:

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

      【讨论】:

      • -c 为我工作。想知道为什么单独 bash 不起作用(没有得到提示)
      【解决方案8】:

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

      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”标志来创建它。
      【解决方案9】:

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

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

      【讨论】:

        【解决方案10】:

        简单的答案:同时启动和附加。在这种情况下,您所做的正是您所要求的。

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

        确保更改&lt;CONTAINER_ID/CONTAINER_NAME&gt;

        【讨论】:

          【解决方案11】:

          所以我认为答案比上面许多误导性的答案要简单。

          启动已停止的现有容器

          docker start <container-name/ID>
          

          停止正在运行的容器

          docker stop <container-name/ID>
          

          然后登录到容器的交互式shell

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

          在一个命令中启动现有容器并附加到它

          docker start -ai <container-name/ID>
          

          请注意,这将在退出时停止容器。但一般情况下,你需要在完成后启动容器、附加并停止它。

          【讨论】:

          • @Peter T. 实际上,我发现您的答案比其他人提供的要简洁得多。我不明白为什么人们喜欢把一个非常简单的问题复杂化。谢谢彼得这个答案。
          • 这要求当你做 docker create 时,你用 -it stackoverflow.com/questions/45216612/… 做它,否则它不会启动.. 所以你会做 docker start 然后 docker ps -l 你会看到它在开始后没有启动。然后附加将失败。所以也必须用 -it 创建。
          • @Peter 最相关的答案
          • 这是最准确的答案!
          • 我执行 docker start -ai &lt;ID&gt; 并立即停止。所以我不能进入 insede 容器。应该如何创建容器以便允许进入?
          【解决方案12】:

          将命令传送到docker exec bashstdin

          必须删除 -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 主机上测试。

          【讨论】:

            【解决方案13】:

            对于 Mac:

            $ docker exec -it <container-name> sh
            

            如果您想以 root 用户身份连接:

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

            【讨论】:

              【解决方案14】:

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

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

              【讨论】:

                【解决方案15】:
                # docker exec -d container_id command 
                

                例如:

                # docker exec -d xcdefrdtt service jira stop 
                

                【讨论】:

                  【解决方案16】:

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

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

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

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

                  【讨论】:

                    【解决方案17】:

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

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

                    【讨论】:

                      【解决方案18】:

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

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

                      (鉴于clever_bardeen 是创建的容器的名称...)

                      在 OP 的情况下,通过执行以下命令确保 docker 映像首先运行:

                      docker start clever_bardeen
                      

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

                      docker exec -it clever_bardeen /bin/bash
                      

                      【讨论】:

                        【解决方案19】:

                        我通常用这个:

                            docker exec -it my-container-name bash
                        

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

                        【讨论】:

                        • 重点是,您不能在退出的容器上运行此命令。它显示以下错误:来自守护程序的错误响应:容器 31ed0... 未运行
                        • @AshishPratap 多么奇怪的错误!我刚刚运行了“docker exec -it e47e2ece292a bash”,它工作正常。也许您需要更新 Docker?
                        • 您确定在运行此命令时您的容器尚未处于运行状态吗?
                        • @AshishPratap 哦,你是对的,我的错。此命令无法在已停止的容器中执行
                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2020-05-21
                        • 1970-01-01
                        • 2020-07-28
                        • 2021-07-10
                        • 1970-01-01
                        相关资源
                        最近更新 更多