Why Does Docker Take 10 Seconds to Stop? Uncovering SIGTERM and Init Issues
This article explains why Docker containers may need around ten seconds to stop, covering missing init processes, unhandled SIGTERM signals, and practical Dockerfile adjustments such as using exec‑form ENTRYPOINT, adding signal traps, or employing a lightweight init like tini.
As an SRE you often restart containers, but sometimes docker stop takes about 10s to finish. The delay can be caused by (1) the process inside the container not receiving the SIGTERM signal, (2) the process receiving but ignoring it, or (3) the application itself needing a long shutdown time. This article focuses on the first two cases.
Many minimal base images (e.g., Alpine, Busybox) strip away the init system, which is the root cause of the problem.
The init system is the first process (PID 1) in a Linux system; it spawns all other user processes, reaps orphan processes, and forwards OS signals to child processes.
1. Docker container stop process
When you run docker stop mycontainer, the Docker CLI sends a TERM signal to the process with PID 1 inside the container.
If PID 1 is an init process – it forwards the TERM signal to its children, allowing them to shut down gracefully.
If there is no init process – the application defined by ENTRYPOINT or CMD becomes PID 1 and must handle the TERM signal itself. Two sub‑cases arise:
Application does not handle SIGTERM – the container never stops until Docker’s timeout expires.
Container stop time is long – Docker waits the default 10 seconds; if the container is still running, Docker sends a SIGKILL to force termination.
2. Container process not receiving SIGTERM?
If the process inside the container is not PID 1 (e.g., a shell started by a shell‑form ENTRYPOINT), the shell lacks init‑style signal forwarding, so the application never receives SIGTERM.
Typical Dockerfile causing this:
FROM alpine:3.7
COPY popcorn.sh .
RUN chmod +x popcorn.sh
ENTRYPOINT ./popcorn.shHere popcorn.sh runs under a shell, making the shell PID 1.
Solution 1: Use exec‑form ENTRYPOINT
Switch to exec form so the script becomes PID 1:
FROM alpine:3.7
COPY popcorn.sh .
RUN chmod +x popcorn.sh
ENTRYPOINT ["./popcorn.sh"]Now ./popcorn.sh receives signals directly. However, the script must still trap SIGTERM:
#!/bin/sh
trap "exit" TERM
while true; do
date
sleep 1
doneSolution 2: Use exec in a shell‑form ENTRYPOINT
Keep the shell form but prepend exec:
FROM alpine:3.7
COPY popcorn.sh .
RUN chmod +x popcorn.sh
ENTRYPOINT exec ./popcorn.shThe exec replaces the shell with the script, making the script PID 1.
Solution 3: Add a lightweight init system (tini)
If you cannot modify the application, add an init process such as tini:
FROM alpine:3.7
COPY popcorn.sh .
RUN chmod +x popcorn.sh && apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--", "./popcorn.sh"]Alternatively, run the container with Docker’s --init flag to inject tini without baking it into the image.
3. After using tini, does the app still need to handle SIGTERM?
Yes. PID 1 (the init process) does not perform the default action for signals; it must explicitly handle SIGTERM. Therefore, even with tini, the application should implement a SIGTERM trap to exit gracefully.
Original link: https://blog.true-kubernetes.com/why-does-my-docker-container-take-10-seconds-to-stop/
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
