435

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'.

Basically I would like to start a shell so I can inspect the contents of the container.

Luckily I created the container with the -it option!

aaa90210
  • 11,295
  • 13
  • 51
  • 88

13 Answers13

603

Find your stopped container id

docker ps -a

Commit the stopped container:

This command saves modified container state into a new image named 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

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 stuff 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

Bernardo Ramos
  • 4,048
  • 30
  • 28
Dmitriusan
  • 11,525
  • 3
  • 38
  • 38
  • Does this imply modifying the image? – ichigolas Apr 24 '17 at 16:55
  • 2
    no, images are read-only. It saves modified container state into a new image test_image – Dmitriusan Apr 26 '17 at 05:02
  • I have tried to do that with the [Docker image](https://github.com/SonarSource/docker-sonarqube/blob/master/6.3.1/Dockerfile) `sonarqube:6.3.1` and unfortunatly it lead to an **error** : `docker: Error parsing reference: "entrypoint=sh" is not a valid repository/tag: invalid reference format.` – Dimitri Kopriwa Apr 29 '17 at 23:22
  • I've updated an answer, please try commands again. Also, what docker version are you using? – Dmitriusan May 03 '17 at 09:17
  • 25
    this misses almost all the config about env, volumes, UID, … All it has in common with the stopped container is the filesystem (which is maybe enough for some) – Florian Klein Aug 31 '17 at 07:59
  • 5
    It would be great if I could somehow get the same environment, network config, attached volumes. Is it possible to convert the ``inspect`` output into a configuration that is used with the subsequent run? – Otheus Feb 07 '18 at 17:42
  • > Error response from daemon: Conflict. The container name "/xyz" is already in use by container "502f...". You have to remove (or rename) that container to be able to reuse that name – Joe Phillips Jul 15 '18 at 04:04
  • @JoePhillips, looks like the container you are trying to start is already running. – Dmitriusan Jul 16 '18 at 09:32
  • so when we summon docker run... and make some change on it, once the container has stopped its file system structure is permanent if I understand well – Webwoman Sep 13 '18 at 14:19
  • 2
    @Webman, yes, but that is not true for volumes that were mounted before stopping a container. You will have to attach the same volumes explicitly when you start the container next time – Dmitriusan Sep 14 '18 at 08:02
  • 1
    `docker run -ti --entrypoint=sh user/test_image` creates a new container. How can I run an existing container with a custom command, without creating a new container? – Emre Tapcı Nov 29 '18 at 08:22
  • 2
    @EmreTapcı, I think doing that is against the Docker ideology. Containers are intended to be a sing-use run-and-throw-away entity, in contrast to virtual machines. You may try to follow the *aaa90210* answer, but it would be a hack. – Dmitriusan Nov 30 '18 at 09:15
  • This doesn't allow to modify the failing container to fix it! – cdalxndr Jan 29 '21 at 23:27
  • Just out of curiosity, I had to achieve something similar but the container was part of Kubernetes environment. Can something similar be done with a container running in Kubernetes? – Parag Meshram Aug 16 '21 at 19:19
  • It would be useful also to add the param `--rm` to run command `docker run -ti --rm --entrypoint=sh user/test_image`, so container will be removed once you exit it. – c3R1cGFy May 04 '23 at 10:56
184

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, e.g. /bin/bash. You may also set the "Args" parameter to pass arguments to the command.

Restart the docker service (note this will stop all running containers unless you first enable live-restore):

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!

docker start -ai mad_brattain

Worked on Fedora 22 using Docker 1.7.1.

NOTE: If your shell is not interactive (e.g. 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.

NOTE2: Newer versions of docker have config.v2.json, where you will need to change either Entrypoint or Cmd (thanks user60561).

Community
  • 1
  • 1
aaa90210
  • 11,295
  • 13
  • 51
  • 88
  • my bash is not interactive, it starts and exits at once (exit 0) – Mando Nov 26 '16 at 23:51
  • 2
    @AlexeyStrakh you could try running "/usr/bin/sleep 600" and then do "docker exec -it /bin/bash" to get a shell. Although I am not sure how to put parameters on that Path variable. Otherwise try and find another command that will stay alive long enough for you to do an exec, or see answer from Dmitriusan. – aaa90210 Nov 27 '16 at 04:48
  • 2
    there is another attribute called "Arguments" to pass parameters. Though I found another solutions for me is `docker cp` to copy required file from the stopped container, update config and put it back. – Mando Nov 27 '16 at 07:01
  • 9
    that's the only really accurate answer to the question: all the others propositions run an "almost same" container, but they forget the volumes, env, UIDs, … – Florian Klein Aug 31 '17 at 07:58
  • 6
    In my case /usr/bin/sleep was not available. I had success with `..."Path":"tail","Args":["-f","/dev/null"]...` – nevrome Oct 23 '17 at 19:57
  • @nevrome yep good idea, anything that keeps the container alive long enough to do a "docker exec" will work. – aaa90210 Oct 23 '17 at 21:51
  • 10
    Newer versions of docker have `config.v2.json`, where you will need to change either `Entrypoint` or `Cmd`. – flaviut Dec 19 '18 at 17:52
  • 5
    After restarting container config file always get back to previous version. – Mr Jedi Sep 10 '20 at 09:47
  • 1
    @MrJedi did you restart Docker itself or just the container? Bear in mind this will stop ALL running containers. – aaa90210 Sep 10 '20 at 10:03
  • Only container. Ok, I got this. So there is no option to stop only one container and change entrypoint? I don't wan't to stop all of them. – Mr Jedi Sep 10 '20 at 10:15
  • @MrJedi there is using the accepted answer, but that has limitations as described. If you want to use this solution (config file change), Docker itself must be restarted. – aaa90210 Sep 10 '20 at 20:18
  • 1
    Docker is not really well suited for a productive system. I wish I had time to create a proper lightweight container tool. – John Mar 19 '21 at 17:54
  • 5
    For Docker Desktop on Windows, you can find the `config.v2.json` files at: `\\wsl$\docker-desktop-data\version-pack-data\community\docker\containers\CONTAINER_ID\config.v2.json` – Venryx Aug 29 '21 at 15:19
  • Using `/bin/bash`, `/bin/sh` or only "sh" and "bin" didn't worked to me (not found). Anything else I should try? Thanks :) – no-stale-reads Oct 11 '22 at 08:17
  • @no-stale-reads you should set it to the command you want to run - /bin/bash was just and example. What image are you running that does not have /bin/sh? – aaa90210 Oct 11 '22 at 10:49
  • @aaa90210 mongo latest image. it should have bash too – no-stale-reads Oct 11 '22 at 12:15
  • On version 24.0.5 (on Arch Linux), `Path` seems to be the right field to edit again in `config.v2.json`. Changing `Cmd` doesn't help. Tested on an `alpine` based container that was started with `/bin/sh` but I wanted it changed to `/bin/bash` after I installed it. – Devansh Sharma Aug 12 '23 at 15:33
31

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.

If you don't already have an Entrypoint script, create one that runs whatever command(s) you need for your container. Then, at the top of this file, add these lines to 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. I'm running the container with my Entrypoint script like so:

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). You can then execute a debugging bash session:

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.

Ethan T
  • 1,390
  • 12
  • 28
  • 8
    Additionally, you could make the entrypoint run `/bin/sh` instead of `cat` -- then you can always get in just be restarting. Your solution rocks! – Danny Dulai May 11 '17 at 23:02
  • `cat` and `/bin/sh` didn't halt execution for me, I ended up looping / sleeping indefinitely. `while : do sleep 3600 done` – Jeff Ward Sep 12 '21 at 04:32
7

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

(for conven, put your env, vol mounts in the docker-compose.yml)

or use docker run and manually spec all args

BrendenCom
  • 71
  • 1
  • 1
6

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.

mkdir $TARGET_DIR
docker export $CONTAINER_ID | tar -x -C $TARGET_DIR
Lars Christian Jensen
  • 1,407
  • 1
  • 13
  • 14
5

I took @Dmitriusan's answer and made it into an alias:

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"'

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.

Helpful for debugging failed docker builds.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Dean Rather
  • 31,756
  • 15
  • 66
  • 72
4

It seems docker can't change entry point after a container started. 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:

#!/bin/bash
command_b

And restart:

docker restart c
Summer
  • 91
  • 1
  • 5
3

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
Saurabh Kumar
  • 2,088
  • 14
  • 17
  • 18
    Unfortunately this does nor work if the container crashes immediately when you start it. – aaa90210 Mar 09 '21 at 18:56
  • 1
    it can work if run like this: docker start [container_name] && docker exec -it [container_name] bash – nggit Nov 02 '21 at 00:20
  • 1
    @nggit that still doesn't work if the container errors out immediately and exits. The `docker exec` won't keep the container alive. – dboshardy Nov 08 '21 at 18:38
  • @dboshardy it works for me, as long as "bash" or "sh" is present. so we can **debug** why the original CMD / ENTRYPOINT exits immediately, by running that said original CMD / ENTRYPOINT inside shell --- "bash" or "sh" can be replaced by another program as long as it exists in the container and can be executed. as per the question "run a different command" i.e. bash, sh, etc. – nggit Nov 08 '21 at 22:19
  • @nggit I'm not sure what you're doing, but that's not how `exec` works. [The command started using docker exec only runs while the container’s primary process (PID 1) is running, and it is not restarted if the container is restarted.](https://docs.docker.com/engine/reference/commandline/exec/) In this case, if the original process in the container, the one used to start it (here, `PID 1`) exits immediately, this will kill both `PID 1` and the additional `PID` you've invoked via `exec`. – dboshardy Nov 09 '21 at 23:23
  • @dboshardy you're right, now i can't reproduce it – nggit Nov 10 '21 at 03:29
  • 1
    i just thought, just before "exits immediately" there's a little time to override PID 1 by using "&&" – nggit Nov 10 '21 at 03:50
2

My Problem:

  • I started a container with 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.
  • That means every time I was running docker run <IMAGE_NAME> command, new image was getting created

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 container start <CONTAINER_ID> to start existing container
  • Then you can continue from where you left. e.g. docker exec -it <CONTAINER_ID> /bin/bash
  • You can then decide to create a new image out of it
Amit Dudhbade
  • 61
  • 1
  • 1
  • 5
    This doesn't answer the question. The OP wants to know how to restart the container but with different arguments than those used in `docker run ` – CodeBlooded Jun 03 '19 at 09:12
2

I had a docker container where the MariaDB container was continuously crashing on startup because of corrupted InnoDB tables.

What I did to solve my problem was:

  • copy out the docker-entrypoint.sh from the container to the local file system (docker cp)
  • edit it to include the needed command line parameter (--innodb-force-recovery=1 in my case)
  • copy the edited file back into the docker container, overwriting the existing entrypoint script.
  • Note that `docker cp` copies files with [permissions preserved if possible](https://docs.docker.com/engine/reference/commandline/cp/#:~:text=permissions%20preserved%20if%20possible). You may need to chmod the file copied from the host to make it executable before copying it into the container. – dlauzon Dec 01 '22 at 16:15
2

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. 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 .

  2. Fix it locally

  3. Copy it back in

    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!

Bryce Rakop
  • 146
  • 7
1

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'. 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. The running container can now be further edited with the bash shell to correct any problems. When finished editing another docker cp of the original entrypoint back into the container and a re-restart should do the trick.

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? Hey, maybe that already works with '--entrypoint'? Not sure, didn't try it, left as exercise for reader, let me know if it works. :)

Travis
  • 552
  • 1
  • 8
  • 14
0

To me Docker always leaves the impression that it was created for a hobby system, it works well for that.
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.

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)

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

    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. When finished stop the container, remove/rename your custom entrypoint.

Syscall
  • 19,327
  • 10
  • 37
  • 52
John
  • 7,507
  • 3
  • 52
  • 52