【问题标题】:Is it possible to start a shell session in a running container (without ssh)是否可以在正在运行的容器中启动 shell 会话(没有 ssh)
【发布时间】:2013-07-28 00:05:06
【问题描述】:

我天真地期待这个命令在一个正在运行的容器中运行一个 bash shell:

docker run "id of running container" /bin/bash

这似乎是不可能的,我得到了错误:

2013/07/27 20:00:24 Internal server error: 404 trying to fetch remote history for 27d757283842

所以,如果我想在正在运行的容器中运行 bash shell(例如用于诊断目的)

我必须在其中运行 SSH 服务器并通过 ssh 登录吗?

【问题讨论】:

  • docker run CONTAINER 计划在 1.0 中
  • 从 docker 1.3 开始,你真的应该按照this answer中的描述去做
  • 只是docker attach container_name
  • 现在看来第二个答案比接受的答案要好得多 - 你能重新考虑改变接受的答案吗?
  • 我提出了一个单独的命令docker shellgithub.com/moby/moby/issues/41702

标签: docker


【解决方案1】:

在 docker 1.3 中,有一个新命令 docker exec。这允许您输入正在运行的 docker:

docker exec -it "id of running container" bash

【讨论】:

  • 这对我很有用。对 docker run 非常有用的补充。
  • 如果我在执行正在运行的容器时进行了更改并希望在线反映更改怎么办?最佳做法是什么?
  • 非常有用。谢谢你
  • 使用docker ps 获取正在运行的实例的ID
  • 注意:容器可能没有 bash(»exec: "bash": 找不到可执行文件«)。使用docker inspect <image> 查看可用的shell。例如。改为运行docker exec -it <container id> /bin/sh
【解决方案2】:

编辑:现在您可以使用docker exec -it "id of running container" bash (doc)

以前,这个问题的答案是:

如果你真的必须并且你在调试环境中,你可以这样做:sudo lxc-attach -n <ID> 请注意,id 必须是完整的 (docker ps -notrunc)。

但是,我强烈建议不要这样做。

注意:-notrunc 已弃用,很快将被--no-trunc 取代。

【讨论】:

  • 你为什么反对它?
  • 我建议不要这样做,因为 1)它需要一个非常新的内核,2)您在 docker 之外做事,因此您将无法跟踪它(日志、附加等)。此外,docker 可能现在使用 lxc,但不能保证它会永远这样做。
  • 尝试更新到 0.7.6。 Docker 现在仍在使用 lxc,lxc-attach 应该可以正常工作。我只是加倍检查,它对我有用。 (请注意,它不适用于 3.8 之前的内核)。
  • 从 0.9 开始,docker 默认不再与 LXC 一起运行。您必须使用 docker -d -e lxc 启动 docker 守护进程
  • Max L.,您的用例可以通过data volumes 解决。未测试示例: 1) 使用 nginx 日志运行容器,数据量为:docker run -v /var/log/nginx -name somename imagename command; 2)运行另一个容器查看数据卷内容:docker run -volumes-from somename -i -t busybox /bin/sh.
【解决方案3】:

做事

docker attach container_name

如 cmets 中所述,要在不停止容器的情况下从容器中分离,请键入 Ctrlp,然后键入 Ctrlq kbd>.

【讨论】:

  • 谢谢!!它有帮助。在实际问题的背景下,我想补充一点。使用docker attach container_name 调试我们的容器后,使用ctrl pctrl q 而不是exitexit 命令停止容器,而 ctrlpctrl q 只是分离该容器并使其保持运行
【解决方案4】:

由于情况正在发生变化,目前推荐的访问正在运行的容器的方法是使用nsenter

您可以在此github repository 上找到更多信息。但通常你可以像这样使用 nsenter:

PID=$(docker inspect --format {{.State.Pid}} <container_name_or_ID>)
nsenter --target $PID --mount --uts --ipc --net --pid

或者你可以使用包装器docker-enter:

docker-enter <container_name_or_ID>

可以在 Jérôme Petazzoni 的博客条目中找到关于该主题的一个很好的解释: Why you don't need to run sshd in your docker containers

【讨论】:

  • 不幸的是,使用这种方法会弄乱环境变量(如果您想检查由链接创建的变量)。我建议做source /proc/*/environ
【解决方案5】:

你不能运行的第一件事

docker run "existing container" command

因为这个命令需要一个 image 而不是 container 并且它无论如何都会导致一个新的容器被生成(所以不是你想要查看的那个)

我同意使用 docker 我们应该推动自己以不同的方式思考(所以你应该找到不需要登录到容器的方法),但我仍然觉得它很有用,这是我如何解决它。

我在 DEAMON 模式下通过主管运行我的命令。

然后我执行我所说的docker_loop.sh 内容差不多是这样的:

#!/bin/bash
/usr/bin/supervisord
/usr/bin/supervisorctl
while ( true )
    do
    echo "Detach with Ctrl-p Ctrl-q. Dropping to shell"
    sleep 1
    /bin/bash
done

它的作用是允许您“附加”到容器并显示supervisorctl 界面以停止/启动/重新启动和检查日志。 如果这还不够,您可以Ctrl+D,然后您将进入一个外壳,让您可以像普通系统一样四处查看。

还请注意,此系统不如没有外壳的容器安全,因此请采取所有必要步骤来保护您的容器。

【讨论】:

    【解决方案6】:

    密切关注这个拉取请求:https://github.com/docker/docker/pull/7409

    它实现了即将推出的docker exec &lt;container_id&gt; &lt;command&gt; 实用程序。当这可用时,它应该是可能的,例如在正在运行的容器中启动和停止 ssh 服务。

    还有nsinit 可以做到这一点:“nsinit 提供了一种方便的方式来访问正在运行的容器的命名空间内的 shell”,但它看起来很难运行。 https://gist.github.com/ubergarm/ed42ebbea293350c30a6

    【讨论】:

    • docker exec 登陆 Docker 1.3,因此现在可以在正在运行的容器中创建和加入新的 shell 会话
    【解决方案7】:

    你可以使用

    docker exec -it <container_name> bash
    

    【讨论】:

      【解决方案8】:

      这是我的解决方案

      在 Dockerfile 中:

      # ...
      RUN mkdir -p /opt
      ADD initd.sh /opt/
      RUN chmod +x /opt/initd.sh
      ENTRYPOINT ["/opt/initd.sh"]
      

      initd.sh 文件中

      #!/bin/bash
      ...
      /etc/init.d/gearman-job-server start
      /etc/init.d/supervisor start
      #very important!!!
      /bin/bash
      

      构建映像后,您有两个使用 execattach 的选项:

      1. 使用 exec(首选)并运行:

        docker run --name $CONTAINER_NAME -dt $IMAGE_NAME
        

        然后

        docker exec -it $CONTAINER_NAME /bin/bash
        

        并使用 CTRL + D 分离

      2. 使用附加并运行:

        docker run --name $CONTAINER_NAME -dit $IMAGE_NAME
        

        然后

        docker attach $CONTAINER_NAME
        

        并使用 CTRL + PCTRL + Q 分离

        注意:选项的区别在于参数-i

      【讨论】:

        【解决方案9】:

        实际上有一种方法可以在容器中放置一个外壳。

        假设您的 /root/run.sh 启动进程、进程管理器(主管)或其他任何东西。

        使用一些 gnu 屏幕技巧创建 /root/runme.sh

        # Spawn a screen with two tabs
        screen -AdmS 'main' /root/run.sh
        screen -S 'main' -X screen bash -l
        screen -r 'main'
        

        现在,您在选项卡 0 中拥有守护进程,在选项卡 1 中拥有交互式 shell。docker attach 随时查看容器内发生的情况。

        另一个建议是在生产映像之上创建一个“开发包”映像,其中包含所有必要的工具,包括这个屏幕技巧。

        【讨论】:

          【解决方案10】:

          有两种方法。

          带附件

          $ sudo docker attach 665b4a1e17b6 #by ID
          

          用执行器

          $ sudo docker exec - -t 665b4a1e17b6 #by ID
          

          【讨论】:

            【解决方案11】:

            如果目标是检查应用程序的日志,这篇文章显示了启动 tomcat 并将日志作为 CMD 的一部分。使用 'docker logs containerid' 在主机上可以使用 tomcat 日志。

            http://blog.trifork.com/2013/08/15/using-docker-to-efficiently-create-multiple-tomcat-instances/

            【讨论】:

              【解决方案12】:

              在运行容器时分配名称很有用。您不需要参考 container_id。

              docker run --name container_name yourimage docker exec -it container_name bash

              【讨论】:

                【解决方案13】:

                首先,通过

                获取所需容器的容器id
                docker ps
                

                你会得到这样的东西:

                CONTAINER ID        IMAGE                  COMMAND             CREATED             STATUS                          PORTS                    NAMES
                3ac548b6b315        frontend_react-web     "npm run start"     48 seconds ago      Up 47 seconds                   0.0.0.0:3000->3000/tcp   frontend_react-web_1
                
                

                现在复制此容器 ID 并运行以下命令:

                docker exec -it container_id sh
                
                docker exec -it 3ac548b6b315 sh
                
                

                【讨论】:

                  【解决方案14】:

                  也许您在开发容器时像我一样被误导了考虑虚拟机。我的建议:尽量不要。

                  容器就像任何其他进程一样。实际上,您可能希望“附加”到它们以进行调试(想想 /proc//env 或 strace -p ),但这是一个非常特殊的情况。

                  通常你只是“运行”这个过程,所以如果你想修改配置或读取日志,只需创建一个新容器并确保通过共享目录将日志写入它之外,写入标准输出(所以 docker日志工作)或类似的东西。

                  出于调试目的,您可能想要启动一个 shell,然后是您的代码,然后按 CTRL-p + CTRL-q 以保持 shell 不变。这样您就可以使用以下方法重新连接:

                  docker attach <container_id>
                  

                  如果您想调试容器,因为它正在做您没想到的事情,请尝试调试它:https://serverfault.com/questions/596994/how-can-i-debug-a-docker-container-initialization

                  【讨论】:

                  • 这是完全错误的。能够自省应用程序运行所在的 LXC 命名空间并不是“非常特殊的情况”,它是任何开发人员的常见/日常活动。
                  • @sleepycal "any developer" 听起来有点偏颇。无论如何,我确实使用了进程的自省,所以同样的事情也适用于容器。这就是调试背后的想法。您将调试器附加到进程(可能有一个 cli)。认为您“已”登录到容器听起来仍然对我产生误导。
                  【解决方案15】:

                  没有。这是不可能的。如果需要,请使用 supervisord 之类的东西来获取 ssh 服务器。不过,我肯定质疑这种需要。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2022-12-21
                    • 2011-10-25
                    • 2021-10-10
                    • 2014-10-18
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-09-18
                    相关资源
                    最近更新 更多