简体   繁体   English

如何使用不同的命令启动停止的 Docker 容器?

[英]How to start a stopped Docker container with a different command?

I would like to start a stopped Docker container with a different command, as the default command crashes - meaning I can't start the container and then use 'docker exec'.我想使用不同的命令启动一个停止的 Docker 容器,因为默认命令崩溃 - 这意味着我无法启动容器然后使用“docker exec”。

Basically I would like to start a shell so I can inspect the contents of the container.基本上我想启动一个 shell 以便我可以检查容器的内容。

Luckily I created the container with the -it option!幸运的是,我使用 -it 选项创建了容器!

Find your stopped container id找到您停止的容器 ID

docker ps -a

Commit the stopped container:提交已停止的容器:

This command saves modified container state into a new image user/test_image此命令将修改后的容器状态保存到新图像user/test_image

docker commit $CONTAINER_ID user/test_image

Start/run with a different entry point:使用不同的入口点启动/运行:

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

Entrypoint argument description: https://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime入口点参数说明: https ://docs.docker.com/engine/reference/run/#/entrypoint-default-command-to-execute-at-runtime

Note:笔记:

Steps above just start a stopped container with the same filesystem state.上面的步骤只是启动一个具有相同文件系统状态的停止容器。 That is great for a quick investigation.这非常适合快速调查。 But environment variables, network configuration, attached volumes and other staff is not inherited, you should specify all these arguments explicitly.但是环境变量、网络配置、附加卷和其他人员不会被继承,您应该明确指定所有这些参数。

Steps to start a stopped container have been borrowed from here: (last comment) https://github.com/docker/docker/issues/18078已从此处借用启动已停止容器的步骤:(最后评论) https://github.com/docker/docker/issues/18078

Edit this file (corresponding to your stopped container):编辑此文件(对应于您停止的容器):

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

Change the "Path" parameter to point at your new command, eg /bin/bash.更改“路径”参数以指向您的新命令,例如 /bin/bash。 You may also set the "Args" parameter to pass arguments to the command.您还可以设置“Args”参数以将参数传递给命令。

Restart the docker service (note this will stop all running containers):重新启动 docker 服务(注意这将停止所有正在运行的容器):

service docker restart

List your containers and make sure the command has changed:列出您的容器并确保命令已更改:

docker ps -a

Start the container and attach to it, you should now be in your shell!启动容器并附加到它,你现在应该在你的 shell 中!

docker start -ai mad_brattain

Worked on Fedora 22 using Docker 1.7.1.使用 Docker 1.7.1 在 Fedora 22 上工作。

NOTE: If your shell is not interactive (eg you did not create the original container with -it option), you can instead change the command to "/bin/sleep 600" or "/bin/tail -f /dev/null" to give you enough time to do "docker exec -it CONTID /bin/bash" as another way of getting a shell.注意:如果您的 shell 不是交互式的(例如,您没有使用 -it 选项创建原始容器),您可以改为将命令更改为“/bin/sleep 600”或“/bin/tail -f /dev/null”给您足够的时间来执行“docker exec -it CONTID /bin/bash”作为获取 shell 的另一种方式。

NOTE2: Newer versions of docker have config.v2.json, where you will need to change either Entrypoint or Cmd (thanks user60561).注意 2:较新版本的 docker 具有 config.v2.json,您需要在其中更改 Entrypoint 或 Cmd(感谢 user60561)。

Add a check to the top of your Entrypoint script在入口点脚本的顶部添加一个检查

Docker really needs to implement this as a new feature, but here's another workaround option for situations in which you have an Entrypoint that terminates after success or failure, which can make it difficult to debug. Docker 确实需要将此作为一项新功能来实现,但对于您的入口点在成功或失败后终止的情况,这是另一个解决方法选项,这可能会使调试变得困难。

If you don't already have an Entrypoint script, create one that runs whatever command(s) you need for your container.如果您还没有 Entrypoint 脚本,请创建一个运行容器所需的任何命令的脚本。 Then, at the top of this file, add these lines to entrypoint.sh :然后,在该文件的顶部,将这些行添加到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

To ensure that cat holds the connection, you may need to provide a TTY.为确保cat保持连接,您可能需要提供 TTY。 I'm running the container with my Entrypoint script like so:我正在使用我的 Entrypoint 脚本运行容器,如下所示:

docker run -t --entrypoint entrypoint.sh image_name

This will cause the script to run once, creating a file that indicates it has already run (in the container's virtual filesystem).这将导致脚本运行一次,创建一个表明它已经运行的文件(在容器的虚拟文件系统中)。 You can then restart the container to perform debugging:然后您可以重新启动容器以执行调试:

docker start container_name

When you restart the container, the already_ran file will be found, causing the Entrypoint script to stall with cat (which just waits forever for input that will never come, but keeps the container alive).当您重新启动容器时,将找到already_ran文件,导致 Entrypoint 脚本与cat一起停止(它只是永远等待永远不会出现的输入,但保持容器活动)。 You can then execute a debugging bash session:然后,您可以执行调试bash会话:

docker exec -i container_name bash

While the container is running, you can also remove already_ran and manually execute the entrypoint.sh script to rerun it, if you need to debug that way.在容器运行时,如果需要以这种方式进行调试,您还可以删除already_ran并手动执行entrypoint.sh脚本以重新运行它。

I took @Dmitriusan's answer and made it into an alias:我接受了@Dmitriusan 的回答并将其设为别名:

alias 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"'别名 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"'

Add this into your ~/.bashrc aliases file, and you'll have a nifty new docker-run-prev-container alias which'll drop you into a shell in the previous container.将此添加到您的~/.bashrc别名文件中,您将拥有一个漂亮的新docker-run-prev-container别名,它会将您放入前一个容器中的外壳中。

Helpful for debugging failed docker build s.有助于调试失败的docker build

This is not exactly what you're asking for, but you can use docker export on a stopped container if all you want is to inspect the files.这并不完全符合您的要求,但如果您只想检查文件,您可以在停止的容器上使用docker export

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

My Problem:我的问题:

  • I started a container with docker run <IMAGE_NAME>我用docker run <IMAGE_NAME>启动了一个容器
  • And then added some files to this container然后在这个容器中添加了一些文件
  • Then I closed the container and tried to start it again withe same command as above.然后我关闭了容器并尝试使用与上面相同的命令再次启动它。
  • But when I checked the new files, they were missing但是当我检查新文件时,它们不见了
  • when I run docker ps -a I could see two containers.当我运行docker ps -a时,我可以看到两个容器。
  • That means every time I was running docker run <IMAGE_NAME> command, new image was getting created这意味着每次我运行docker run <IMAGE_NAME>命令时,都会创建新图像

Solution: To work on the same container you created in the first place run follow these steps解决方案:要在您首先创建的同一个容器上运行,请按照以下步骤操作

  • docker ps to get container of your container docker ps获取容器的容器
  • docker container start <CONTAINER_ID> to start existing container docker container start <CONTAINER_ID>启动现有容器
  • Then you can continue from where you left.然后你可以从你离开的地方继续。 eg docker exec -it <CONTAINER_ID> /bin/bash例如docker exec -it <CONTAINER_ID> /bin/bash
  • You can then decide to create a new image out of it然后,您可以决定从中创建一个新图像

I have found a simple command我找到了一个简单的命令

docker start -a [container_name]

This will do the trick这会成功的

Or或者

docker start [container_name]

then然后

docker exec -it [container_name] bash

To me Docker always leaves the impression that it was created for a hobby system, it works well for that.对我来说,Docker 总是给人留下它是为一个爱好系统创建的印象,它很适合这个。
If something fails or doesn't work, don't expect to have a professional solution.如果某些事情失败或不起作用,不要指望有专业的解决方案。

That said: Docker does not only NOT support such basic administrative tasks, it tries to prevent them.也就是说:Docker 不仅不支持这些基本的管理任务,它还试图阻止它们。

Solution:解决方案:

  1.  cd /var/lib/docker/overlay2/
  2.  find | grep somechangedfile # You now can see the changed file from your container in a hexcoded folder/diff
  3.  cd hexcoded-folder/diff
  4. Create an entrypoint.sh (make sure to backup an existing one if it's there)创建一个entrypoint.sh (如果存在,请确保备份现有的)

     cat > entrypoint.sh #!/bin/bash while ((1)); do sleep 1; done;

    Ctrl + C Ctrl + C

     chmod +x entrypoint.sh
  5.  docker stop docker start

You now have your docker container running an endless loop instead of the originally entry, you can exec bash into it, or do whatever you need.你现在让你的 docker 容器运行一个无限循环而不是原来的条目,你可以 exec bash 进入它,或者做任何你需要的事情。 When finished stop the container, remove/rename your custom entrypoint.完成后停止容器,删除/重命名您的自定义入口点。

It seems docker can't change entry point after a container started.容器启动后,docker 似乎无法更改入口点。 But you can set a custom entry point and change the code of the entry point next time you restart it.但是您可以设置自定义入口点,并在下次重新启动时更改入口点的代码。

For example you run a container like this:例如,您运行这样的容器:

docker run --name c --entrypoint "/boot" -v "./boot":/boot $image

Here is the boot entry point:这是启动入口点:

#!/bin/bash
command_a

When you need restart c with a different command, you just change the boot script:当您需要使用不同的命令重新启动 c 时,您只需更改启动脚本:

#!/bin/bash
command_b

And restart:并重新启动:

docker restart c

docker-compose run --entrypoint /bin/bash cont_id_or_name docker-compose run --entrypoint /bin/bash cont_id_or_name

(for conven, put your env, vol mounts in the docker-compose.yml) (对于 conven,将您的 env、vol 挂载在 docker-compose.yml 中)

or use docker run and manually spec all args或使用 docker run 并手动指定所有参数

It wasn't specified whether the container is exiting, only that your code crashes and you need to see what's going on in the container. 没有指定容器是否正在退出,只是您的代码崩溃了,您需要查看容器中发生了什么。 If it isn't exiting, here is another potential solution. 如果它没有退出,这是另一个潜在的解决方案。

Get the container id with docker ps 使用docker ps获取容器ID

docker exec -it 665b4a1e17b6 /bin/sh

If entrypoint is set to something problematic, it can also be overridden as suggested in Dmitriusan's answer. 如果将入口点设置为有问题的东西,也可以按照Dmitriusan的回答中的建议覆盖它。 It should also be noted that you can attach to any running container with docker attach . 还应注意,您可以使用docker attach连接到任何正在运行的容器。 So many solutions different solutions. 这么多解决方案有不同的解 I just don't see the need to commit to the image. 我只是没有看到需要提交图像。 It seems unnecessary. 这似乎没必要。

Docs for Docker exec - https://docs.docker.com/engine/reference/commandline/exec/ Docker exec的文档 - https://docs.docker.com/engine/reference/commandline/exec/

Docs for Docker attach - https://docs.docker.com/engine/reference/commandline/attach/ Docker附件的文档 - https://docs.docker.com/engine/reference/commandline/attach/

To enter to a shell (bash / sh) of the container that can't be started (exited for some reason):进入无法启动(由于某种原因退出)的容器的外壳(bash / sh):

docker start [CONTAINER] && docker exec -it [CONTAINER] bash

This is possible because of && , which means that just before the container fails to start, we immediately run bash .这是可能的,因为&& ,这意味着就在容器无法启动之前,我们立即运行bash

I had a docker container where the MariaDB container was continuously crashing on startup because of corrupted InnoDB tables.我有一个 docker 容器,由于 InnoDB 表损坏,MariaDB 容器在启动时不断崩溃。

What I did to solve my problem was:我为解决我的问题所做的是:

  • copy out the docker-entrypoint.sh from the container to the local file system (docker cp)将容器中的 docker-entrypoint.sh 复制到本地文件系统(docker cp)
  • edit it to include the needed command line parameter (--innodb-force-recovery=1 in my case)编辑它以包含所需的命令行参数(在我的情况下为--innodb-force-recovery=1)
  • copy the edited file back into the docker container, overwriting the existing entrypoint script.将编辑后的文件复制回 docker 容器,覆盖现有的入口点脚本。

Lots of discussion surrounding this so I thought I would add one more which I did not immediately see listed above:围绕这个进行了很多讨论,所以我想我会再添加一个我没有立即在上面列出的内容:

If the full path to the entrypoint for the container is known (or discoverable via inspection) it can be copied in and out of the stopped container using 'docker cp'.如果容器入口点的完整路径已知(或可通过检查发现),则可以使用“docker cp”将其复制进出已停止的容器。 This means you can copy the original out of the container, edit a copy of it to start a bash shell (or a long sleep timer) instead of whatever it was doing, and then restart the container.这意味着您可以将原始文件复制出容器,编辑它的副本以启动 bash shell(或长睡眠计时器)而不是执行任何操作,然后重新启动容器。 The running container can now be further edited with the bash shell to correct any problems.现在可以使用 bash shell 进一步编辑正在运行的容器以纠正任何问题。 When finished editing another docker cp of the original entrypoint back into the container and a re-restart should do the trick.完成将原始入口点的另一个 docker cp 编辑回容器中后,重新启动应该可以解决问题。

I have used this once to correct a 'quick fix' that I butterfingered and was no longer able to run the container with the normal entrypoint until it was corrected.我曾经用它来更正一个“快速修复”,但我已经摸不着头脑,并且在更正之前无法使用正常的入口点运行容器。

I also agree there should be a better way to do this via docker: Maybe an option to 'docker restart' that allows an alternate entrypoint?我也同意应该有更好的方法通过 docker 来做到这一点:也许是一个允许备用入口点的“docker restart”选项? Hey, maybe that already works with '--entrypoint'?嘿,也许这已经适用于“--entrypoint”? Not sure, didn't try it, left as exercise for reader, let me know if it works.不确定,没试过,留给读者练习,让我知道它是否有效。 :) :)

It seems like most of the time people are running into this while modifying a config file, which is what I did.似乎大多数时候人们在修改配置文件时都会遇到这种情况,这就是我所做的。 I was trying to bypass CORS for a PHP/Apache server with a Vue SPA as my entry point.我试图绕过 CORS 以使用 Vue SPA 作为我的入口点的 PHP/Apache 服务器。 Anyway, if you know the file you horked, a simple solution that worked for me was无论如何,如果你知道你讨厌的文件,一个对我有用的简单解决方案是

  1. Copy the file you horked out of the image:复制您从图像中删除的文件:

    docker cp bt-php:/etc/apache2/apache2.conf. docker cp bt-php:/etc/apache2/apache2.conf。

  2. Fix it locally在本地修复它

  3. Copy it back in复制回来

    docker cp apache2.conf bt-php:/etc/apache2/apache2.conf docker cp apache2.conf bt-php:/etc/apache2/apache2.conf

  4. Start your container back up启动您的容器备份

  5. *Bonus points - Since this file is being modified, add it to your Compose or Build scripts so that when you do get it right it will be baked into the image! *奖励积分 - 由于此文件正在修改,请将其添加到您的 Compose 或 Build 脚本中,这样当您做对时,它将被烘焙到图像中!

docker container start <CONTAINER_ID>

I actually disagree with both of these answers. 我实际上不同意这两个答案。 If you just want to see what's in the container, then you can run this command to get a shell. 如果您只想查看容器中的内容,则可以运行此命令来获取shell。 No need to change the entrypoint at all or any configs. 无需更改入口点或任何配置。

docker run -it <image_name> bash

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM