Why does stopping an idle container take the full 10-second timeout?

0
0
Asked By MellowCedar42 On

On a Linux host, stopping an otherwise idle container can consistently take about 10 seconds. For example:

`docker run -d --name sleeper alpine sleep 1000`
`time docker stop sleeper`

The 10 seconds is Docker's default grace period, but the interesting part is why SIGTERM does not appear to start the shutdown. A process running as PID 1 inside a PID namespace is treated specially by the kernel: signals from outside the namespace are only delivered if that process has installed a handler for them. SIGKILL and SIGSTOP are exceptions, so after the grace period Docker kills the process.

You can check whether the container's PID 1 has a signal handler by inspecting `SigCgt` in `/proc//status`. For SIGTERM, bit 15 corresponds to `0x4000`. If that bit is absent, SIGTERM will not be delivered to PID 1 and the container will wait for the full timeout.

There are two common fixes, but they solve slightly different problems. Using `exec` in an entrypoint script replaces the shell with the application, allowing the application to receive the stop signal directly. Using `--init` places a small init process such as tini at PID 1; it catches signals and reaps child processes, which is useful when the entrypoint cannot be changed. Also check the image's configured `STOPSIGNAL`, since Docker may send something other than SIGTERM for applications such as nginx or PostgreSQL.

4 Answers

Answered By AmberFalcon54 On

Also inspect the image's stop signal. `docker inspect -f '{{.Config.StopSignal}}' ` shows what Docker will send. nginx commonly uses SIGQUIT for graceful shutdown, while PostgreSQL uses SIGINT. Testing only for a SIGTERM handler can therefore give the wrong diagnosis. A shell that has no handler for either signal can still force the entire grace period on every stop or container recreation.

NeonPebble86 -

This can add up during deployments: recreating several services repeatedly incurs the grace period for each old container, even when startup is fast.

Answered By SilverLattice3 On

If you control the entrypoint script, use `exec` for the long-running application. For example, change `nginx -g 'daemon off;'` to `exec nginx -g 'daemon off;'`. Without `exec`, the shell remains PID 1; with it, nginx becomes PID 1 and can handle its shutdown signal directly. This can reduce a stop from roughly 10 seconds to a fraction of a second when the application exits promptly.

BrightOtter61 -

The important check is not simply whether a shell appears in the command line. Some shells replace themselves with a single simple command, while others remain for scripts involving additional commands. Check which process is actually PID 1.

Answered By QuietHarbor7 On

The 10 seconds is Docker's normal grace period, not a slow shutdown. Docker sends the configured stop signal first and waits; if the container is still running, it sends SIGKILL. With a simple `alpine sleep 1000` process as PID 1, `sleep` has no signal handler, so the signal from the parent PID namespace is not delivered. It remains alive until SIGKILL arrives.

VividMango18 -

That distinction matters: saying the process ignores SIGTERM suggests the signal reached it. In this PID-namespace case, the kernel prevents delivery because PID 1 has not registered a handler.

Answered By CrispWillow29 On

`--init` is the alternative when changing the entrypoint is impractical: `docker run --init ...`. The init process catches signals and reaps orphaned children, so the stop signal has somewhere to land. It does not magically make a slow application shut down faster; an app that needs two seconds will still need about two seconds.

Related Questions

LEAVE A REPLY

Please enter your comment!
Please enter your name here

This site uses Akismet to reduce spam. Learn how your comment data is processed.