difference between docker attach and docker exec
As Michael Sun stated in his answer
docker exec
executes a new command / create a new process in the container’s environment, whiledocker attach
just connects the standard input/output/error of the main process(with PID 1) inside the container to corresponding standard input/output/error of current terminal(the terminal you are using to run the command).
My answer will focus more on letting you validate the above statement and understand it more clearly.
Open up a terminal window and run the command docker run -itd --name busybox busybox /bin/sh
. The command will pull the image busybox
if not already present. It will then create a container with the name busybox
using this image.
You can check the status of your container by running the command docker ps -a | grep busybox
.
If you run docker top busybox
, you should see an output something like this.
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
Of course, the PID
, PPID
and other values will be different in your case. You can use other tools and utilities as well like pstree
, top
, htop
to see the list of PID
and PPID
.
The PID
and PPID
means the process id and parent process id. The process started when we created and started our container with the command /bin/sh
. Now, run the command docker attach busybox
. This will attach the standard input/output/error stream of the container to your terminal.
After attaching the container, create a shell session by running the command sh
. Press CTRL-p CTRL-q
sequence. This will detach the terminal from the container and will keep the container running. If you'll now run docker top busybox
, you should see two processes in the list.
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
root 7737 7469 0 11:43 pts/0 00:00:00 sh
But the PPID
of the two processes will be different. In fact, the PPID
of the second process will be the same as PID
of the first one. The first process acts as the parent process for the shell session that we just created.
Now, run docker exec -it busybox sh
. Once inside the container, check the list of running processes for the container busybox
in another terminal window by running the command docker top busybox
. You should see something like this
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
root 7737 7469 0 11:43 pts/0 00:00:00 sh
root 7880 7451 0 11:45 pts/1 00:00:00 sh
The PPID
of the first and third process will be the same, which confirms that docker exec
creates a new process in the container's environment while docker attach
just connects the standard input/output/error of the main process inside the container to corresponding standard input/output/error of current terminal.
2015: There was a commit PR which added to the doc:
Note: This command (
attach
) is not for running a new process in a container. See:docker exec
.
The answer to "Docker. How to get bash\ssh inside runned container (run -d
)?" illustrates the difference:
(docker >= 1.3) If we use
docker attach
, we can use only one instance of shell.
So if we want to open new terminal with new instance of container's shell, we just need to rundocker exec
if the docker container was started using
/bin/bash
command, you can access it using attach, if not then you need to execute the command to create a bash instance inside the container usingexec
.
As mentioned in this issue:
- Attach isn't for running an extra thing in a container, it's for attaching to the running process.
- "
docker exec
" is specifically for running new things in a already started container, be it a shell or some other process.
The same issue adds:
While
attach
is not well named, particularly because of the LXC commandlxc-attach
(which is more akindocker exec <container> /bin/sh
, but LXC specific), it does have a specific purpose of literally attaching you to the process Docker started.
Depending on what the process is the behavior may be different, for instance attaching to/bin/bash
will give you a shell, but attaching to redis-server will be like you'd just started redis directly without daemonizing.
Update 2022: See more with "Containers 101: attach vs. exec - what's the difference?" (Dec. 2021) from Ivan Velichko:
Extract:
Difference between attach and logs
On the diagram above,
docker attach
streams the container's logs back to the terminal.
However, thedocker logs
command does a similar thing.
So, what's the difference?The logs command provides various options to filter the logs while attach in that regard acts as a simple tail.
But what's even more important is that the stream established by the logs command is always unidirectional and connected to the container's logs, not the container's stdio streams directly.The logs command simply streams the content of the container's logs back to your terminal, and that's it.
So, regardless of how you created your container (interactive or non-interactive, controlled by a pseudo-terminal or not), you cannot accidentally impact the container while using the logs command.However, when attach is used:
- If a container was created in the interactive mode (
-i
), everything you type in the terminal after attach-ing to the container will be sent to its stdin.- You can (intentionally or accidentally) send a signal to the container - for instance, hitting ctrl+c on your end while attached sends
SIGINT
to the container.What does exec command do
The exec command is actually a totally different story.
In the case of attach, we were connecting our terminal to an existing container (read, process).
However, the
exec
commandstarts a totally new container!
In other words,exec
is a form of therun
command (which itself is just a shortcut forcreate
+start
).
Bart reminds us in the comments that docker exec
runs a new command in a running container. Not a "totally new one".
When a container is started using /bin/bash then it becomes the containers PID 1 and docker attach is used to get inside PID 1 of a container. So docker attach < container-id > will take you inside the bash terminal as it's PID 1 as we mentioned while starting the container. Exiting out from the container will stop the container.
Whereas in docker exec command you can specify which shell you want to enter into. It will not take you to PID 1 of the container. It will create a new process for bash. docker exec -it < container-id > bash. Exiting out from the container will not stop the container.
You can also use nsenter to enter inside containers. nsenter -m -u -n -p -i -t < pid of container > You can find PID of container using: docker inspect < container-id > | grep PID
Note: If you have started your container with -d flag then exiting out of container will not stop the container,whether you use attach or exec to get inside.
Docker exec executes a new command / create a new process in the container’s environment, while docker attach just connects the standard input/output/error of the main process(with PID 1) inside the container to corresponding standard input/output/error of current terminal(the terminal you are using to run the command).
A container is an isolated environment, with some processes running in the environment. Specifically, a container has its own file system space and PID space that are isolated from host and other containers. When the container is started using “docker run –it …”, the main process will have a pseudo-tty and STDIN kept open. When attached in the tty mode, you can detach from the container (and leave it running) using a configurable key sequence. The default sequence is CTRL-p CTRL-q. You configure the key sequence using the --detach-keys option or a configuration file. You can reattach to a detached container with docker attach.
Docker exec just starts a new process, inside the container’s environment, that is, belongs to the PID space of the container.
For example, if you start your container using “docker run –dit XXX /bin/bash”,you can attach to the container(‘s main process) using two different terminals. While you are inputting in one terminal, you can see it appears in the other terminal, for both terminal are connected to same tty. Be careful that you are now in the main process of the container, if you type “exit”, you will exit the container(so be careful, using detach-keys to detach), and you will see both terminals exited. But if you run “docker exec –it XXX /bin/bash” in two terminals, you have started two new processes inside the container, and they are not related to each other and to the main process, and you can safely exit from them.