What does the STOPSIGNAL instruction in a Dockerfile control, and when would you set it to something other than SIGTERM?
answer
- signal sent to PID 1 on stop; default SIGTERM
- then SIGKILL after timeout -> exit 137
- nginx graceful = SIGQUIT, httpd = SIGWINCH
- PID 1 ignores signals with no handler installed
- shell form: sh is PID 1 and swallows the signal
basics
~20 sSTOPSIGNAL sets which signal the runtime sends to the container's main process on a stop request; the default is SIGTERM, and SIGKILL follows after the grace period. Change it when the application's graceful shutdown uses a different signal, as nginx does with SIGQUIT.
solid answer
~60 s`STOPSIGNAL SIGQUIT` (name or number) records in the image config which signal `docker stop` sends to PID 1 inside the container. After the stop timeout - 10 seconds by default, tunable with `docker stop -t` or the container's --stop-timeout - the runtime sends an uncatchable SIGKILL and the container exits with 137. You override the default when the process treats signals differently from the Unix norm: nginx does a fast, connection-dropping shutdown on SIGTERM and a graceful drain on SIGQUIT, and Apache httpd uses SIGWINCH for graceful stop. Setting the right signal is the difference between draining in-flight requests and cutting them. Two traps. PID 1 has no default signal actions, so a process that installs no handler for the signal simply ignores it and always waits out the full timeout before being killed. And with shell-form ENTRYPOINT the shell is PID 1 and typically does not forward the signal to your app at all - use exec form or a tiny init. Not every orchestrator honors the image's STOPSIGNAL, so verify on the platform you run.
code
dockerfile · 3 linesFROM nginx:1.27-alpine
STOPSIGNAL SIGQUIT
CMD ["nginx", "-g", "daemon off;"]go deeper
Know that it selects the signal sent on stop and that SIGTERM is the default.
Describe the stop-then-kill sequence, the timeout, exit code 137, and per-application signal meanings such as nginx SIGQUIT.
Diagnose the PID 1 and shell-form traps, tie the timeout to real drain time, and connect it to dropped connections during deploys.
Define a shutdown contract across services - signal, drain budget, load-balancer deregistration ordering - and verify it holds on each runtime you deploy to.
## What it sets `STOPSIGNAL <signal>` accepts a signal name (SIGQUIT) or number (3) and stores it in the image configuration. On a stop request the runtime sends that signal to the container's main process - PID 1 in the container's PID namespace - instead of the default SIGTERM. It can be overridden per container with `docker run --stop-signal`. ## The stop sequence `docker stop` sends the configured signal, then waits the stop timeout (default 10 seconds; `docker stop -t 30`, or bake a default with `--stop-timeout` at create time), then sends SIGKILL, which no process can catch or ignore. A container killed that way exits with code 137 (128 + 9). So the graceful window is entirely determined by the timeout, and any drain that takes longer than it will be cut short regardless of how well the application handles the signal. ## Why a different signal Applications are free to assign their own meanings. nginx: SIGTERM means fast shutdown - workers stop immediately and in-flight connections die - while SIGQUIT means graceful shutdown, finishing current requests before exiting. Apache httpd uses SIGWINCH for graceful stop. Some daemons reserve SIGTERM for an abrupt exit path. If you ship such a program, `STOPSIGNAL SIGQUIT` in the image makes every operator's `docker stop` do the graceful thing, without them having to remember a flag. ## The PID 1 trap Inside the container the main process is PID 1, and the kernel gives PID 1 special treatment: signals whose default action would terminate the process are *not* delivered unless the process has explicitly installed a handler for them. A plain program that never registers a SIGTERM handler will therefore ignore the stop signal completely, sit there until the timeout expires, and die by SIGKILL - no draining, no clean flush, and a ten-second delay on every deploy. The fix is either to install a handler in the application or to run a minimal init (tini, dumb-init, or `docker run --init`) as PID 1 that handles signals and forwards them. ## The shell-form trap If the entrypoint or command is written in shell form, the container's PID 1 is `/bin/sh -c "..."` and your application is a child. Most shells do not forward received signals to children, so the stop signal lands on the shell, your app never sees it, and again the container waits for SIGKILL. Exec form - a JSON array - makes your process PID 1 directly. If a wrapper script is unavoidable, end it with `exec "$@"` so the script is replaced by the real process. ## Diagnosing Symptoms of a mis-set or unhandled stop signal are consistent: every `docker stop` takes exactly the timeout, containers exit 137 rather than 0, and load balancers see dropped connections at deploy time. Check the configured value with `docker inspect --format '{{.Config.StopSignal}}' image`, then test: `time docker stop <c>` should return well under the timeout for a well-behaved container. Watch the application logs for its own shutdown messages to confirm the handler ran. ## Portability STOPSIGNAL is honored by Docker and Compose. Other platforms differ: Kubernetes has historically sent SIGTERM to containers regardless of the image setting, with per-container stop-signal configuration arriving only in recent versions and gated behind a feature stage. Treat the instruction as a good default for Docker-run workloads, and confirm the behavior on whatever runtime actually operates the container rather than assuming it carries over.
- Every docker stop on your container takes exactly 10 seconds and the exit code is 137. What are the likely causes?The main process never acted on the stop signal, so the runtime fell through to SIGKILL after the timeout. Either the entrypoint is in shell form, making /bin/sh PID 1 and swallowing the signal, or the application installs no handler for that signal and PID 1 therefore ignores it, or the configured STOPSIGNAL is not the one the application listens for. Fix with exec form, an init process such as tini, an explicit handler, or the correct STOPSIGNAL.
- How much time does the process actually get to shut down, and how do you extend it?It gets the stop timeout, which defaults to 10 seconds; after that SIGKILL is unconditional. Extend it per invocation with docker stop -t 30, or bake a default into the container with --stop-timeout at create time. If a drain genuinely needs longer, the application must also stop accepting new work early so the drain fits inside the window.
saying these in an interview costs you the question
- Assuming SIGTERM always triggers a graceful shutdown, including for nginx
- Not knowing PID 1 ignores signals for which no handler is installed
- Thinking STOPSIGNAL changes how long the container gets before SIGKILL
- Using shell-form ENTRYPOINT and expecting the app to receive the signal
- Assuming every orchestrator honors the image's STOPSIGNAL