docker exec. What if there is no shell process? - docker

docker exec <container> <command>.
In the documentation it is written:
Run a command in a running container
But what does it mean exactly? What does it mean to execute a command in container. I can't imagine a situation that exec command is executed by a shell run in the container. But we cannot assume that every container has run shell or shell at whole.

The docker exec <container> <command> will run given command in the namespaces of the specified container. The docker exec creates new process and sets its namespaces to container's namespaces and after that executes command.
More on Linux namespaces can be found here:
Namespaces in operation
Namespaces of a process can be found using the following command:
sudo ls -l /proc/<PID>/ns

A container is an isolated environment for your process, with its own network environment, mounted filesystems, namespaced process list, etc. When you perform a docker run you create this namespace by running a command as pid 1. When you perform a docker exec you can run any command inside this same namespace. E.g.:
$ docker run --name test-exec -d busybox tail -f /dev/null
5e77cec13293e7146dac6858ed11be1e6a706ba973c419435303f4ec8c346e2d
$ docker exec test-exec ps -ef
PID USER TIME COMMAND
1 root 0:00 tail -f /dev/null
6 root 0:00 ps -ef
Note that in neither of the above commands did I even run a shell.

Related

Batch file not executing a command

I am trying to create a .bat file that will back-up the database inside the container. After the first command (that is used to enter the container) the next one is ignored.
docker exec -it CONTAINER_NAME /bin/bash
cd /var/opt/mssql/data
Any ideas why? If I'm trying to manually write cd /var/opt/mssql/data in the opened cmd it works.
When running docker exec -it CONTAINER_NAME /bin/bash, you are opening a bash-shell INSIDE the docker container.
The next command, i.e. cd /var/opt/mssql/data, is only executed, if the previous command, docker exec -it CONTAINER_NAME /bin/bash has exited successfully, which means that the shell on the docker container has been closed/exited.
This means that cd /var/opt/mssql/data is then executed on the local machine and not inside the docker container.
To run a command inside the docker container, use the following command
docker exec -it CONTAINER_NAME /bin/bash -c "<command>"
Although it may be better to create a script inside the container during the build process or mount a script inside the docker container while starting the container and then simply call this script with the above mentioned command.

Life-cycle difference between docker run and docker start

I have a fundamental question about container life cycle.
For example I run the following command
Create new ubuntu container and run the bash command
docker run -it ubuntu bash
In the container's bash
exit
The new container will be in state EXITED
docker ps -a
Then I use docker start to restart the container
docker start xxxx(container name)
docker exec -it xxxx(container name) /bin/bash
In the restarted container's bash
exit
The restarted container is still running
docker ps -a
May I know the reason behind for this behavior? Thank you!
With the docker run command:
docker run -it ubuntu bash
the container is started with the execution of the bash command, so when you exit from the bash, the container also exits as bash is the main process running inside the container.
However with the docker exec command:
docker exec -it xxxx(container name) /bin/bash
the container is already running the command defined by the CMD/ENTRYPOINT and bash is the command executed as a separate process. So, exiting from bash after docker start exits the bash process and the main process is still continued.

what is docker run -it flag?

I was doing some complex stuff with docker, but as turn out I don't know what -it flag means.
Recently I've come across on some example of docker run command which has confused me a little.
docker run -itd ubuntu:xenial /bin/bash
My question is what is sense to write -it flag here, if container during instantiation run bin/bash
In documentation we have an example
docker run --name test -it debian
with explanation
The -it instructs Docker to allocate a pseudo-TTY connected to the
container’s stdin; creating an interactive bash shell in the
container.
and explanation for -t flag from help page
-t, --tty Allocate a pseudo-TTY
if I delete -it flag during
docker run -d ubuntu:xenial /bin/bash
my newly created container doesn't live so much
in docker ps -a
it is designated as exited
Sorry, if my question quite stupid, I can't find explanation on the Internet (I have significant misunderstanding of that point).
-it is short for --interactive + --tty. When you docker run with this command it takes you straight inside the container.
-d is short for --detach, which means you just run the container and then detach from it. Essentially, you run container in the background.
Edit: So if you run the Docker container with -itd, it runs both the -it options and detaches you from the container. As a result, your container will still be running in the background even without any default app to run.
docker run -it ubuntu:xenial /bin/bash starts the container in the interactive mode (hence -it flag) that allows you to interact with /bin/bash of the container. That means now you will have bash session inside the container, so you can ls, mkdir, or do any bash command inside the container.
The key here is the word "interactive". If you omit the flag, the container still executes /bin/bash but exits immediately. With the flag, the container executes /bin/bash then patiently waits for your input.
Normal execution without any flags:
[ec2-user#ip-172-31-109-14 ~]$ sudo docker exec 69e937450dab ls
bin
boot
dev
docker-entrypoint.d
docker-entrypoint.sh
etc
If your command needs an input like cat, you can try:
[ec2-user#ip-172-31-109-14 ~]$ echo test | sudo docker exec 69e937450dab cat
Nothing will show, because there is no input stream going to the docker container. This can be achieved with the -i flag.
[ec2-user#ip-172-31-109-14 ~]$ echo test | sudo docker exec -i 69e937450dab cat
test
Now, let us suppose, you want the bash to start as process:
sudo docker exec 69e937450dab bash
You will see nothing, because the process started in the container. Adding the flag will do the deal:
[ec2-user#ip-172-31-109-14 ~]$ sudo docker exec -t 69e937450dab bash
root#69e937450dab:/#
But this does not really help, because we need an input stream, which takes our commands and can be received by the bash. Therefore, we need to combine the two:
[ec2-user#ip-172-31-109-14 ~]$ sudo docker exec -i -t 69e937450dab bash
root#69e937450dab:/# ls
bin boot dev docker-entrypoint.d docker-entrypoint.sh etc hi home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root#69e937450dab:/#
small recap:
-t for attaching the bash process to our terminal
-i for being able to send inputs via STDIN for example with the keyboard to the bash in the container
Without -i can be used for commands, that don't need inputs. Without -t and bash can be used, when you dont want to attach the docker containers process to your shell.

Running dev container exec bash not responding

I have following Dockerfile:
FROM elixir:1.4.5
COPY . /
RUN mix compile
CMD echo "Application started" && elixir --name $MY_POD_NAMESPACE#$MY_POD_IP --no-halt --cookie $ERLANG_COOKIE -S mix run
It starts and runs well, but when I try either attatch or exec XXX bash it does not respond at all.
Both the commands are different as such
docker attach containerid gets your to main process which was running and if it doesn't output anything further then you will not see anything. You should rather use docker logs containerid to see the output of your code
docker exec containerId bash means you want to get to a bash process inside the container. This command would execute and end immediately as you have not specified the interactive and the tty flags. Update it to use it as below
docker exec -it containerId bash
And you should be able to get a bash. If it still doesn't work then use docker stats containerId to see what kind of CPU and memory usage your container has
If docker exec -it container-id bash doesn't work then try docker exec -it container-id sh
Sometimes bash command doesn't work.

How do I run a command on an already existing Docker container?

I created a container with -d so it's not interactive.
docker run -d shykes/pybuilder bin/bash
I see that the container has exited:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d6c45e8cc5f0 shykes/pybuilder:latest "bin/bash" 41 minutes ago Exited (0) 2 seconds ago clever_bardeen
Now I would like to run occasional commands on the machine and exit. Just to get the response.
I tried to start the machine. I tried attaching. I thought I could call run with a container, but that does not seem to be allowed. Using start just seems to run and then exist quickly.
I'd like to get back into interactive mode after exiting.
I tried:
docker attach d6c45e8cc5f0
But I get:
2014/10/01 22:33:34 You cannot attach to a stopped container, start it first
But if I start it, it exits anyway. Catch 22. I can't win.
In October 2014 the Docker team introduced docker exec command: https://docs.docker.com/engine/reference/commandline/exec/
So now you can run any command in a running container just knowing its ID (or name):
docker exec -it <container_id_or_name> echo "Hello from container!"
Note that exec command works only on already running container. If the container is currently stopped, you need to first run it with the following command:
docker run -it -d shykes/pybuilder /bin/bash
The most important thing here is the -d option, which stands for detached. It means that the command you initially provided to the container (/bin/bash) will be run in the background and the container will not stop immediately.
Your container will exit as the command you gave it will end. Use the following options to keep it live:
-i Keep STDIN open even if not attached.
-t Allocate a pseudo-TTY.
So your new run command is:
docker run -it -d shykes/pybuilder bin/bash
If you would like to attach to an already running container:
docker exec -it CONTAINER_ID /bin/bash
In these examples /bin/bash is used as the command.
So I think the answer is simpler than many misleading answers above.
To start an existing container which is stopped
docker start <container-name/ID>
To stop a running container
docker stop <container-name/ID>
Then to login to the interactive shell of a container
docker exec -it <container-name/ID> bash
To start an existing container and attach to it in one command
docker start -ai <container-name/ID>
Beware, this will stop the container on exit. But in general, you need to start the container, attach and stop it after you are done.
To expand on katrmr's answer, if the container is stopped and can't be started due to an error, you'll need to commit it to an image. Then you can launch bash in the new image:
docker commit [CONTAINER_ID] temporary_image
docker run --entrypoint=bash -it temporary_image
Some of the answers here are misleading because they concern containers that are running, not stopped.
Sven Dowideit explained on the Docker forum that containers are bound to their process (and Docker can't change the process of a stopped container, seemingly due at least to its internal structure: https://github.com/docker/docker/issues/1437). So, basically the only option is to commit the container to an image and run it with a different command.
See https://forums.docker.com/t/run-command-in-stopped-container/343
(I believe the "ENTRYPOINT with arguments" approach wouldn't work either, since you still wouldn't be able to change the arguments to a stopped container.)
I had to use bash -c to run my command:
docker exec -it CONTAINER_ID bash -c "mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql mysql"
Creating a container and sending commands to it, one by one:
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
If you are trying to run shell script, you need run it as bash.
docker exec -it containerid bash -c /path/to/your/script.sh
This is a combined answer I made up using the CDR LDN answer above and the answer I found here.
The following example starts an Arch Linux container from an image, and then installs git on that container using the pacman tool:
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"
That is all.
Pipe a command to docker exec bash stdin
Must remove the -t for it to work:
echo 'touch myfile' | docker exec -i CONTAINER_NAME bash
This can be more convenient that using CLI options sometimes.
Tested with:
docker run --name ub16 -it ubuntu:16.04 bash
then on another shell:
echo 'touch myfile' | docker exec -i ub16 bash
Then on first shell:
ls -l myfile
Tested on Docker 1.13.1, Ubuntu 16.04 host.
I would like to note that the top answer is a little misleading.
The issue with executing docker run is that a new container is created every time. However, there are cases where we would like to revisit old containers or not take up space with new containers.
(Given clever_bardeen is the name of the container created...)
In OP's case, make sure the docker image is first running by executing the following command:
docker start clever_bardeen
Then, execute the docker container using the following command:
docker exec -it clever_bardeen /bin/bash
I usually use this:
docker exec -it my-container-name bash
to continuously interact with a running container.
Assuming the image is using the default entrypoint /bin/sh -c, running /bin/bash will exit immediately in daemon mode (-d). If you want this container to run an interactive shell, use -it instead of -d. If you want to execute arbitrary commands in a container usually executing another process, you might want to try nsenter or nsinit. Have a look at https://blog.codecentric.de/en/2014/07/enter-docker-container/ for the details.
Unfortunately it is impossible to override ENTRYPOINT with arguments with docker run --entrypoint to achieve this goal.
Note: you can override the ENTRYPOINT setting using --entrypoint, but
this can only set the binary to exec (no sh -c will be used).
For Mac:
$ docker exec -it <container-name> sh
if you want to connect as root user:
$ docker exec -u 0 -it <container-name> sh
Simple answer: start and attach at the same time. In this case you are doing exactly what you asked for.
docker start <CONTAINER_ID/CONTAINER_NAME> && docker attach <CONTAINER_ID/CONTAINER_NAME>
make sure to change <CONTAINER_ID/CONTAINER_NAME>
I am running windows container and I need to look inside the docker container for files and folder created and copied.
In order to do that I used following docker entrypoint command to get the command prompt running inside the container or attach to the container.
ENTRYPOINT ["C:\\Windows\\System32\\cmd.exe", "-D", "FOREGROUND"]
That helped me both to the command prompt attach to container and to keep the container a live. :)
# docker exec -d container_id command
Ex:
# docker exec -d xcdefrdtt service jira stop
A quick way to resume and access the most recently exited container:
docker start -a -i `docker ps -q -l`
An easy solution that solved a similar problem for me:
docker run --interactive --tty <name_of_image>

Resources