Docker & ContainersXXX Β· Host MaintenanceReboots
Planned reboot β what happens to containers, in order
What you'll learn
- Trace the shutdown sequence from `systemctl reboot` to container SIGKILL
- Tune `shutdown-timeout` and `default-stop-timeout` against the systemd stop timeout
- Predict which containers come back on boot and which do not
- Verify the host after a reboot rather than assuming
Prerequisites
Verified against Docker Engine 29.x Β· Docker Engine 28.x Β· Docker Compose 2.x Β· containerd 2.x Β· runc 1.2.x Β· BuildKit 0.20+ Β· Linux kernel 5.15+ Β· Ubuntu 24.04 LTS Β· Debian 12 (Bookworm) Β· 2026-08-11
The upgrades part spent a lot of effort on containers surviving a daemon restart. None of it applies here. A reboot takes the kernel down, and every container is a process on that kernel.
So the question for a reboot is not βdo containers surviveβ β they do not β but βdo they shut down cleanly and come back correctlyβ. Both answers are decided by configuration you can check in advance.
The shutdown sequence
The timeouts, and why the defaults bite
There is no docker info field for the daemonβs shutdown budget, which is part
of why it goes unnoticed. Read it from the configuration instead β an absent
key means the default:
$ grep -E 'shutdown-timeout|default-stop-timeout' /etc/docker/daemon.json ; systemctl show docker.service -p TimeoutStopUSec ; docker inspect --format '{{.Name}} {{.Config.StopTimeout}}' $(docker ps -q)TimeoutStopUSec=1min 30s
/web <nil>
/postgres 60Illustrative output
No grep output at all means neither daemon key is set, so the daemon is using
shutdown-timeout 15 and default-stop-timeout 10. A container printing
<nil> for Config.StopTimeout has no per-container override and inherits the
daemon default; /postgres above was created with --stop-timeout 60.
Consider a Postgres container configured with --stop-timeout 60, because a
checkpoint on a large database takes that long:
- Step 4 gives that container its 60 seconds. Correct.
- Step 5 gives the daemon 15 seconds total. After 15 seconds
dockerdstops waiting and exits. - The container is SIGKILLed mid-checkpoint.
The per-container timeout is capped in practice by the daemonβs overall
shutdown-timeout, and the default is 15 seconds. A container asking for more
than that does not get it during a host shutdown, even though docker stop -t 60 by hand works perfectly.
{
"shutdown-timeout": 90,
"default-stop-timeout": 30
}Then raise the systemd unit budget above the daemonβs, so systemd is the last thing to lose patience rather than the first:
[Service]
TimeoutStopSec=120sudo systemctl daemon-reload
systemctl show docker.service -p TimeoutStopUSec
# Validate the daemon config before restarting into it
sudo dockerd --validate --config-file /etc/docker/daemon.json
sudo systemctl restart docker
# The daemon logs its effective configuration at startup
journalctl -u docker --since '2 minutes ago' --no-pager | head -20The ordering rule: container stop timeout β€ daemon shutdown-timeout β€ systemd TimeoutStopSec. Any inversion means something gets killed by a layer that does not know what it is interrupting.
What comes back on boot
Restart policy decides, and the four policies behave differently:
| Policy | After a host reboot |
|---|---|
no | Does not start. Stays exited. |
on-failure | Does not start. The policy responds to exit codes, not to daemon startup. |
always | Starts. |
unless-stopped | Starts, unless it was manually stopped before the shutdown. |
The on-failure row is the trap. It reads like a reasonable production
setting and it means the container will not come back from a reboot. Dockerβs
documentation is explicit that on-failure does not restart the container if
the daemon restarts.
The difference between always and unless-stopped matters exactly once per
reboot: a container you deliberately stopped last week comes back with
always and stays stopped with unless-stopped. For a host you reboot for
maintenance, unless-stopped respects your intent and always overrides it.
docker ps -a --format '{{.Names}}' | xargs -r -I{} docker inspect --format '{{.Name}} {{.State.Status}} {{.HostConfig.RestartPolicy.Name}}' {}$ docker ps -a --format '{{.Names}}' | xargs -r -I{} docker inspect --format '{{.Name}} {{.State.Status}} {{.HostConfig.RestartPolicy.Name}}' {}/web running unless-stopped
/api running unless-stopped
/worker running on-failure
/postgres running always
/debug-box running noIllustrative output
worker and debug-box will be gone after the reboot. debug-box is
probably fine β it is a debugging container. worker is a production service
with the wrong policy, and this audit is how you find it while you can still
fix it.
The reboot procedure
#!/usr/bin/env bash
set -euo pipefail
# --- Before
uname -r
cat /var/run/reboot-required.pkgs 2>/dev/null || echo 'no reboot flagged'
docker ps --format '{{.Names}}' | sort > /tmp/running.before
docker ps -a --format '{{.Names}}' | xargs -r -I{} docker inspect --format '{{.Name}} {{.HostConfig.RestartPolicy.Name}}' {} > /tmp/policies.before
cat /tmp/policies.before
# --- Optional: stop the stack in dependency order rather than letting
# systemd do it. Gives the application a clean shutdown it controls.
# docker compose -f /srv/app/compose.yaml stop --timeout 60
sudo systemctl rebootExplicitly stopping a Compose stack before the reboot is worth it when services depend on each other. Compose stops them in reverse dependency order, so an application shuts down before the database it writes to. The daemonβs own shutdown has no such ordering β it stops containers concurrently, which means a database can go away while an application is still writing to it.
uname -r
systemctl is-system-running
systemctl is-active docker containerd
docker ps --format '{{.Names}}' | sort > /tmp/running.after
diff /tmp/running.before /tmp/running.after && echo 'PASS: same containers running' || echo 'FAIL: container set changed - see diff above'
docker ps --filter health=unhealthy --format '{{.Names}}'Knowledge check
Knowledge check Β· 4 questions
Q1. A container is configured with `--stop-timeout 60` but the daemon still has the default `shutdown-timeout`. What happens to it during a host reboot?
Q2. Which restart policy leaves a container stopped after a host reboot even though it was running before?
Q3. Which statements about a host reboot are correct? Select all that apply.
Q4. A container SIGKILLed during shutdown often shows no visible symptom, because the application performs crash recovery on the next boot and starts normally.
Passing score: 75%. Answers are checked in this browser.