Each container has its own process hierarchy, and your specified command is the one that runs as "PID 1" (the parent of the entire process tree) within the container. Whenever the process with PID 1 exits, the entire process namespace (and with it, the container) is automatically destroyed by the kernel (not by Docker engine).
In full-system containers, PID 1 would be the "init" process; having it exit is how the container asks the host OS to be "shut down". Outside of containers, PID 1 is not allowed to exit at all – if this ever happens, the system will deliberately crash (you get a kernel panic), so the container behavior is rather similar to that.
(Among other things, what makes PID 1 special is that all processes that no longer have a parent are automatically re-parented to under PID 1, therefore it must always exist.)
You can experiment with PID namespaces using low-level tools, unshare
and nsenter
as the rough equivalents of your two Docker commands (you don't need to have Docker installed at all). You'll notice that ps axf
inside the namespace shows 'sleep' as PID 1, and that whenever it exits, the rest of the namespace is immediately killed.
unshare --pid --fork --mount-proc sleep 120
nsenter --all --target=<pid_of_sleep> ps axf
,
nsenter --all --target=<pid_of_sleep> /bin/bash