Skip to content
Lesson 18 of 19

Step 1 of 5 · Reading · ~3 min

Read

Container Lifecycle

exec & attach

A running container is a process in six namespaces. There are two ways to reach it, they are not variations on each other, and choosing the wrong one is how people accidentally kill production.

attach: the same terminal

docker attach connects your terminal to the streams of PID 1 itself — the process the container was started with. Nothing new is created.

$ docker attach mybox
nginx logs streaming...
^C            # SIGINT goes to PID 1, nginx exits, the container is down

That last line is the trap. Ctrl-C is not "leave"; it is a signal to the container's main process. Detaching without killing anything is the escape sequence Ctrl-P Ctrl-Q. And because there is exactly one PID 1, two people attached to one container share one stream and one keyboard.

exec: a new process in the same walls

docker exec starts a new process inside the container's namespaces:

$ docker exec -it mybox sh
/ # ls

Internally it is four steps and one syscall you have not met:

1. read the container's namespace handles from /proc/<pid-of-init>/ns/
2. setns() into each one: pid, mount, net, uts, ipc, (user)
3. fork; the child execs the requested command, now inside those namespaces
4. the CLI wires your terminal to the child's stdin/stdout/stderr

Two consequences that explain otherwise baffling output. The exec'd process is not a child of the container's PID 1 — it was forked by a process outside the container, so ps inside shows it with a parent that does not exist in this namespace. And by default the process joins the container's namespaces but not all of its cgroups, so a shell you exec in to debug a memory limit may not itself be subject to that limit. Measuring a container from a shell you exec'd into it can therefore mislead you in both directions.

The practical rule: attach to watch the thing that is running, exec to do anything else. Note too that killing an exec'd process leaves the container running, while PID 1 exiting stops the container and takes everything else in it down — which is the exercise's STOP.

Why the exercise is a simulator

setns() requires CAP_SYS_ADMIN, and there is no container in the grader to enter. The bookkeeping is the lesson: which processes exist, which one is special, and what dies with what.

Your exercise: exec & attach Simulator

Docker doesYour simulator does
start the container; the entrypoint becomes PID 1RUN <id> — PID 1 is init
docker exec: a new process in the same namespacesEXEC <id> <name> — pids from 100 upward, per container
signal a process that is not the entrypointKILL <id> <pid>KILLED, or a refusal for PID 1, or ERR no such pid
docker attach: connect to PID 1's streamsATTACH <id>
PID 1 exits: everything in the container goes with itSTOP <id> — reports how many processes died, PID 1 included
ps inside the containerPROCS <id>1 init first, then the exec'd processes by pid

Three rules carry the tests. PID 1 is not killable through KILL — stopping a container is a different operation with different consequences, and the simulator says so rather than pretending. The exec pid counter is per container and never rewinds within a run, so killing pid 100 does not let the next EXEC reuse it. And once stopped, every command against that container answers ERR not running — the namespaces are gone, so there is nothing to enter, attach to, or list. Starting the same id again is a fresh container: PID 1, an empty process list, and the counter back at 100.

Up nextPutting It All TogetherContainer Lifecycle

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…