Docker & ContainersIII · Installation & DaemonLive restore
Live restore — surviving daemon restarts
What you'll learn
- Enable and validate live restore without an outage
- Name the four documented limits: Swarm services, major upgrades, changed daemon options, and skipped releases
- Explain why the container processes survive a daemon restart at all
- Plan maintenance around the control-plane gap
- Verify live restore worked with a check that can fail
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-12
live-restore: true keeps container processes running when dockerd restarts.
Without it, systemctl restart docker interrupts every container on the host.
With it, containers keep their PIDs, their network namespaces and their open
sockets, and continue serving traffic; only the daemon’s control plane goes
away and comes back.
That is a genuinely large win, and it is also the single most over-claimed setting in Docker operations. It is worth being precise about what “the daemon was down and nothing happened” actually means.
Enable it — and note that it reloads
{
"live-restore": true
}live-restore is on the documented list of options the daemon applies on
SIGHUP, which means you can turn it on with no container downtime at all:
sudo dockerd --validate --config-file=/etc/docker/daemon.json || exit 1
sudo systemctl reload docker
docker info --format '{{.LiveRestoreEnabled}}'Enabling live restore and then immediately restarting the daemon “to make it take effect” is backwards, and it costs you the outage you were trying to avoid. Reload first. Restart later, when you actually need to.
The docs also document a --live-restore command-line flag, but state it is
“not recommended because it doesn’t set up the environment that systemd or
another process manager would use.” On a packaged install it would also collide
with the config file. Use daemon.json.
What survives, and what does not
| Survives the daemon restart | Does not survive |
|---|---|
| Container processes keep their PIDs | The Docker API — every CLI call fails while dockerd is down |
| Network namespaces, veth pairs and published-port NAT rules | Health checks, which the daemon drives and which stop running |
| Volume and bind mounts stay mounted | docker logs and docker events streams, which are daemon-served |
| Open client connections to the application | Restart policies — nothing restarts a container that dies in the window |
| The container’s writable layer and its data | Containers created with --rm that exit during the window |
| Resource limits, because the cgroups are already written | Swarm services, which are out of scope entirely |
The pattern is simple once you see it: anything the kernel is holding survives, and anything the daemon is actively doing stops. Namespaces, cgroups and mounts are kernel state and do not care that a userspace process exited. Health checks, restart policy enforcement, log collection and the API are all things dockerd does on a timer or on demand, and dockerd is not there.
$ ps -eo pid,ppid,comm --forest | grep -A2 -E 'dockerd|containerd-shim' 1180 1 containerd
1461 1 dockerd
2043 1180 containerd-shim-runc-v2
2065 2043 \_ nginx
2118 2065 \_ nginxIllustrative output
Note that dockerd (1461) is not an ancestor of nginx (2065) at all. That is
the whole mechanism in one screenful.
The four documented limits
The live restore documentation names four constraints. Every one of them has cost somebody a maintenance window.
1. Swarm services are out of scope. The docs are unambiguous: “The live
restore option only pertains to standalone containers, and not to Swarm
services.” If the host is a Swarm node, live restore does nothing for tasks the
orchestrator placed there — Swarm relies on manager availability and quorum
instead. Setting live-restore: true on a Swarm manager does not buy you what
you think it does.
2. Patch upgrades only. “Live restore allows you to keep containers running
across Docker daemon updates, but is only supported when installing patch
releases (YY.MM.x), not for major (YY.MM) daemon upgrades.” Going from
28.3.1 to 28.3.2 is inside the contract. Going from 28.x to 29.x is not, and
you should plan that as a container-restarting change.
3. Do not skip releases. “If you skip releases during an upgrade, the daemon may not restore its connection to the containers.” A host that sat on 28.0 for a year and jumps straight to the newest patch of a later minor is exactly the skipped-release case.
4. Daemon options must not have changed. “The live restore option only works to restore containers if the daemon options, such as bridge IP addresses and graph driver, didn’t change.” This is the one people trip over, because the whole reason they were restarting the daemon was to apply a config change.
The control-plane gap
Even in the happy case, there is a window — usually a couple of seconds, longer on a host with hundreds of containers — where dockerd is not answering. During it:
$ docker psCannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?Illustrative output
Three practical consequences:
- Anything that shells out to
dockerfails, including your monitoring. A check that runsdocker psand alerts on a non-zero exit will page you every time you patch the daemon. Give it a retry, or check the application’s own health endpoint instead — that is what actually matters, and it stays up. - Nothing enforces restart policy in the window. A container that crashes while dockerd is down stays dead until the daemon returns and notices.
- Health checks stop and then resume. A container mid-
health: startingwhen the daemon goes down does not have its probe run; the state machine picks up where it left off, so a slow-starting service can appear unhealthy for longer than itsstart-periodsuggests.
Verification that can actually fail
“Run docker ps and see” is not verification. The test that distinguishes
“survived” from “restarted quietly” is StartedAt: if the container was
restarted, that timestamp moved.
CONTAINER=web
BEFORE=$(docker inspect --format '{{.State.StartedAt}}' "$CONTAINER")
BEFORE_PID=$(docker inspect --format '{{.State.Pid}}' "$CONTAINER")
sudo systemctl restart docker
# Wait for the API to answer again rather than guessing with sleep.
for _ in $(seq 1 30); do
docker info >/dev/null 2>&1 && break
sleep 1
done
AFTER=$(docker inspect --format '{{.State.StartedAt}}' "$CONTAINER")
AFTER_PID=$(docker inspect --format '{{.State.Pid}}' "$CONTAINER")
if [ "$BEFORE" = "$AFTER" ] && [ "$BEFORE_PID" = "$AFTER_PID" ]; then
echo "live restore confirmed: $CONTAINER kept PID $AFTER_PID"
else
echo "live restore did NOT hold: $BEFORE/$BEFORE_PID -> $AFTER/$AFTER_PID" >&2
exit 1
fiComparing the PID as well as the timestamp matters, because a container that
was restarted and started fast can show a StartedAt that is only a second or
two different, and a second or two is easy to talk yourself out of. A different
PID is not.
Knowledge check
Knowledge check · 6 questions
Q1. Which line in the packaged `docker.service` is what actually lets container processes survive `systemctl restart docker`?
Q2. The documentation names limits on live restore. Which of these are among them? Select all that apply.
Q3. Turning on `live-restore` requires a daemon restart before it takes effect.
Q4. A container crashes during the few seconds dockerd is restarting. It has `--restart unless-stopped`. What happens?
Q5. You restart the daemon with live restore on. Which check best distinguishes "the container survived" from "the container was restarted quickly"?
Q6. If dockerd fails to start after a restart, rebooting the host converts a control-plane outage into a full service outage.
Passing score: 75%. Answers are checked in this browser.