DEV Community

Qian_Xiao
Qian_Xiao

Posted on

Docker Stop Signals Reach PID 1, Not Every Process in the Container

A common misconception says that docker stop sends SIGTERM to every process inside a container. It does not. The signal is sent to the container’s main process: PID 1 in the container’s PID namespace.

This distinction matters when PID 1 is not the application that needs to shut down gracefully. Consider an image with this instruction:

ENTRYPOINT service --listen
Enter fullscreen mode Exit fullscreen mode

This is Dockerfile shell form. Docker normally starts it through a shell equivalent to:

/bin/sh -c 'service --listen'
Enter fullscreen mode Exit fullscreen mode

The shell becomes PID 1, while service runs as its child. When the container is stopped, the runtime signals the shell. Whether the application receives that signal now depends on the shell’s behavior. A non-interactive shell may not forward SIGTERM to its child. The service can therefore miss its opportunity to stop accepting work, flush buffers, close connections, or persist state.

After the configured grace period expires, Docker sends SIGKILL to the container. SIGKILL cannot be caught or handled, so the application is terminated immediately.

Exec form removes this unnecessary intermediary:

ENTRYPOINT ["service", "--listen"]
Enter fullscreen mode Exit fullscreen mode

Here, service itself becomes PID 1 and directly receives the stop signal. A wrapper script can also work, but it should replace itself with the application by using exec:

#!/bin/sh
prepare_environment
exec service --listen
Enter fullscreen mode Exit fullscreen mode

Without exec, the wrapper remains PID 1 and must explicitly forward signals.

PID 1 also has a special process-management responsibility. Orphaned descendants are reparented to it, and it must reap exited children to prevent zombie processes. Applications that spawn subprocesses but do not handle this role well may benefit from a small init process such as Docker’s --init option. That init process can forward signals and reap children while remaining PID 1.

The precise rule is simple: stopping a container signals its designated main process, not every process in the container. Graceful shutdown depends on ensuring that PID 1 either is the application or correctly forwards signals to it.

Top comments (1)

Collapse
 
kashif_manzer profile image
Kashif Manzer •

One more thing worth knowing: even with exec form, the signal alone is not enough. The kernel treats PID 1 specially and quietly ignores signals like SIGTERM unless the process installs a handler for them. So your app must actually trap SIGTERM and start its shutdown path, or docker stop will wait out the full grace period and then SIGKILL anyway. In Go that usually means signal.Notify plus a call to Server.Shutdown or canceling a context. Exec form gets the signal to your app; a handler is what lets the app act on it.