docker exec and docker attach seem similar because they both let you interact with a running container, but they operate on fundamentally different principles. The most surprising thing is that docker attach actually connects to the original process that started the container, while docker exec starts a brand new process inside it.

Let’s see docker attach in action. Imagine you have a simple web server running that just prints its output to stdout.

# Start a container that prints a message and exits
docker run -d --name my-nginx nginx
# Wait a moment for nginx to start
sleep 5
# Attach to the container's primary process
docker attach my-nginx

If you run docker attach my-nginx, you’ll see the logs from the nginx process itself, and if you were to type commands (and if the container’s entrypoint allowed it), you’d be interacting with that same nginx process. If you press Ctrl+C here, you’ll likely stop the nginx process and thus the container.

Now, consider docker exec. This is for when you need to run a new command inside an already running container, without disturbing its main process.

# Start a container
docker run -d --name my-app alpine sleep 3600
# Execute a new command inside the running container
docker exec -it my-app sh

When you run docker exec -it my-app sh, a new shell process (sh) is spawned inside the my-app container. You can run commands, inspect files, or do whatever you need, and then exit the shell. The original sleep 3600 process continues running unaffected. Pressing Ctrl+C here will only exit the sh process, not the container.

The core problem docker exec solves is providing ad-hoc access for debugging, inspection, or maintenance without disrupting the container’s primary function. docker attach, on the other hand, is for observing or interacting with the container’s main lifecycle and its direct output.

Internally, docker exec works by leveraging the exec system call within the container’s namespace. Docker tells the container runtime to create a new process and attach its standard input, output, and error streams to your terminal. docker attach, however, connects directly to the stdout and stderr file descriptors of the container’s initial process (PID 1, usually), and optionally its stdin. If that initial process doesn’t expect interactive input, attach might not be useful for typing commands, but it’s perfect for tailing logs.

The common mistake is using docker attach when you intend to run a separate diagnostic command. If you attach to a container running a web server and then try to run ls, you’re trying to do that within the web server’s process, which is almost certainly not what you want and likely won’t work. exec is the tool for running arbitrary new commands.

Many users don’t realize that docker attach will follow the container’s lifecycle. If the main process exits, docker attach will disconnect. If you want to see logs after a container has stopped, docker attach is useless; you’d use docker logs.

The next concept you’ll likely grapple with is managing the lifecycle of these ephemeral processes you create with docker exec, especially when they’re long-running or need to be automated.

Want structured learning?

Take the full Docker course →