Skip to main content
RunBook Academy

Docker & ContainersXXXIII Β· Incident ResponseRecovery

Recovery β€” restart, roll back, restore, or rebuild

Advanced⏱ ~20 min

What you'll learn

  • Choose between restart, rollback, restore and rebuild from evidence
  • Roll back by digest so you get the image you intended
  • Define resolution in terms of user outcomes and drained backlog

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

Not yet marked complete on this device.

The damage is contained. Traffic is off the broken instance, the evidence is in /var/tmp, and the channel knows what is happening. Now somebody has to decide how to get back to normal, and there are only four moves.

Choosing between them badly is how a thirty-minute incident becomes a six-hour one. Choosing quickly and reversibly is most of what separates practised teams from unpractised ones.

The four moves

MoveUse whenTypical timeMain risk
Restarta process is wedged or has leaked a finite resourcesecondsit recurs, and you learn nothing
Roll backthe incident began at a deployminutesschema or config incompatibility
Restoredata was lost or corruptedhoursyou lose everything since the backup
Rebuildthe host is compromised or unrecoverably brokenhoursneeds the host to be reproducible

Answer the data question first

Before choosing, answer one question: has data been lost or corrupted?

It comes first because restore is the only move that addresses it, it is the slowest, and every other move can quietly make it worse. A restart against a corrupted volume writes more corruption. A rollback to an older application version against a partially migrated schema can delete columns it does not know about.

Read-only / Safethe data question
# Is the volume still there and does it have the shape you expect?
docker volume inspect proj_pgdata
docker run --rm -v proj_pgdata:/d:ro alpine:3.20 sh -c 'ls -la /d | head -20; du -sh /d'

# Did the application report integrity errors before it went down?
docker logs proj-db-1 --since 2h 2>&1 | grep -iE 'corrupt|checksum|fatal|panic' | tail -20

If the answer is yes, or β€œwe cannot tell”, stop and involve whoever owns the data. Recovery is now a restore, and the sequencing matters far more than the speed.

Roll back if the incident started at a deploy

The single most useful correlation in incident response: did this begin within a few minutes of a change?

Read-only / Safecorrelate
docker events \
--since '2026-08-11T08:00:00Z' \
--until '2026-08-11T10:30:00Z' \
--filter 'event=create' --filter 'event=start' \
--format '{{.Time}} {{.Action}} {{.Actor.Attributes.image}}'

If a new image started at 09:48 and the error rate rose at 09:52, you do not need to understand the bug to act. Roll back. It is the fastest available test of the strongest available hypothesis, and if it works you have both resolved the incident and confirmed the cause.

Roll back by digest, not by tag:

Read-only / Safewhat is actually running
$ docker inspect proj-api-1 --format '{{.Config.Image}} {{.Image}}'
myapp:1.5.0 sha256:9f2b4c8e1a37d5b60c9e8f14a2d7b3c5e60f81a94d2c7b3e5f81a94d2c7b3e5f

Illustrative output

Configuration changepin the previous release
# The digest of the release you are rolling back to
docker image inspect myapp:1.4.2 --format '{{index .RepoDigests 0}}'

# Deploy that exact content
APP_IMAGE='myapp@sha256:REPLACE_WITH_DIGEST_FROM_ABOVE' \
docker compose up -d --wait --wait-timeout 120

# Confirm you got what you asked for
docker inspect proj-api-1 --format '{{.Image}}'

The reason for the digest is specific and it has caused real incidents: tags are mutable. If your pipeline overwrites 1.4.2, or if latest moved, β€œrolling back to 1.4.2” can deploy the same broken content you are rolling back from β€” and you will spend the next twenty minutes concluding that the rollback did not help and the deploy was not the cause.

Restore is a sequence, not a command

  1. Stop writes to the damaged data before anything else, so the amount you have to recover stops growing.
  2. Identify the most recent backup that predates the corruption. The newest backup is not automatically the right one.
  3. Restore into a new volume, never over the live one.
  4. Verify the restored data before cutting over: row counts, the most recent record, and one real application query.
  5. Cut over, and record exactly how much data was lost in wall-clock terms. That number belongs in the postmortem and it is the number leadership will ask for.
  6. Keep the damaged volume until the review is complete.

Rebuild when the host is suspect

If the incident involved a compromise, or host-level state you cannot account for, do not clean the host. Rebuild it.

The argument is asymmetric. Cleaning succeeds only if you found everything, and you cannot prove that. Rebuilding succeeds if your host is reproducible β€” which is a property you either have or need to acquire, and either way the incident has told you something important.

This is also the moment when β€œwe can rebuild this host from configuration in about twenty minutes” stops being a nice-to-have. If the honest answer is β€œnobody knows how this host was built”, that is the top action item of the review, ahead of whatever caused the incident.

β€œResolved” is not β€œthe container is up”

Resolution needs all four of these, not one:

  1. A real user transaction succeeds, executed from outside your infrastructure against the public endpoint β€” not a healthcheck.
  2. The error rate has been at baseline for a sustained period. Ten minutes is a common bar; one green scrape is not.
  3. Every backlog is drained: queues, retry buffers, dead-letter queues, and any batch that did not run during the outage.
  4. Every containment action has been reversed and recorded β€” the load balancer entry restored, docker update --restart=no undone, the disconnected network reconnected, the paused container unpaused or explicitly retired.
Read-only / Safereversal checklist
docker inspect proj-api-1 --format \
'restart={{.HostConfig.RestartPolicy.Name}} status={{.State.Status}} health={{.State.Health.Status}} nets={{range $n, $c := .NetworkSettings.Networks}}{{$n}} {{end}}'

docker ps --filter status=paused

That second command has saved more than one team from discovering a paused container three weeks later.

Sanity check

Knowledge check Β· 4 questions

  1. Q1. Which question should be answered before choosing between restart, rollback, restore and rebuild?

  2. Q2. Why roll back to an image digest rather than to a version tag?

  3. Q3. Which conditions must hold before declaring an incident resolved? Select all that apply.

  4. Q4. When restoring from backup, it is acceptable to restore over the live volume because the live data is already corrupted.

Passing score: 75%. Answers are checked in this browser.