Interacting with Docker containers
Decided to take a break from C# programming on Wreck.NET today, and went back to studying Docker.
One thing that has always confused me about the multiple ways of interacting with Docker containers. This is a common task for developers seeking to inspect the state of a container’s file system, networking and running processes.
The table below summarizes the different commands one may choose.
Mode | Output | Input | New container | Running container | Same Running Container |
---|---|---|---|---|---|
Foreground (default) | Y | N | docker run |
docker exec <name / id> |
docker attach <name / id> / Ctrl-C |
Interactive | Y | Y | docker run -it |
docker exec -it <name / id> | docker attach <name / id> / Ctrl-p Ctrl-q |
Background | N | N | docker run -d |
docker exec -d <name / id> |
How attach
and exec
Differ
As a side-note, there is a good explanation explaining the differences between attaching to a container versus executing a session within a container.
While it goes down to the guts and gory details of how docker exec
and
docker attach
is actually implemented, which for most users do not matters, so
I shall only focus on the differences and implications from the end-user
perspective as a developer when choosing attach
or exec
.
The main difference is that exec
creates a temporary invisible container that
shares the specified container’s resources, giving the illusion of running a
command in that container. Whereas attach
actually runs the command directly
inside the container.
The implication is that if we exec
a /bin/bash
session and then exit it by
choice or accident, the original detached running container keeps running.
Simply because it is running in a temporary container as a different process.
If we attach
to a running container, we are directly interacting with the
running process in that container. In cases where we press Ctrl-C or type exit
at the shell prompt when we are attached to the container’s running process –
whether consciously or by mistake – it will end the process and its container.
This is the typical behaviour we can expect.
TLDR: The Bottomline
The bottomline when we don’t have much time to study Docker in-depth is:
- Use
exec
to execute and run a one-off command within a container. - Use
exec -it /bin/bash
if we want an interactive session. - Use
docker stop
to stop and end the running process/container from the host. There is no need to use Ctrl-C andattach
to stop the process in the foreground. - Always run containers with
-d
in detached mode in the background like in production. - If we just want to see the outputs from the container, use
docker logs
.
Rants and Criticisms of attach
All these said, I have my criticisms about attach
. The attach
option seems
like it exists due to implementation, but without a real use case for users. I
wonder why Docker is keeping it.
In most cases, we do not need to use attach
. Just ignore it. The presence of
attach
seems to me an unnecessary distraction that only confuses people by
adding complexity without an unique use case that demands it. attach
connects
to the main running process. If it’s a shell, we get an interactive prompt when
we attach to it. If it isn’t, we get the scrolling outputs from the running
process. All of these can be achieved with docker exec
without forcing the
users think hard about how to redirect and map their stdin
, stdout
and
stderr
IO streams, or having to understand the teeny weeny difference between
attach
and exec
.
Trying to use attach
properly seems like it depends on the phase of the
moon because its behaviour is dependent on several factors. For example, whether
the container was started in detached mode or not, whether the main process is a
interactive shell or some other non-interactive one. All of which affects
what a user actually experiences.
We just need one consistent method that always works. It does not help
that in different user guides, articles and tutorials, their author choose to
use attach
or exec
without explaining why adding to the confusion in new
learners. Not many has time to carefully study the inner details of how Docker
is actually implemented unless one is a Docker developer.