Docker & ContainersXXI Β· BackupWhy not docker commit
Why `docker commit` is not a backup
What you'll learn
- State precisely which bytes `docker commit` captures and which it silently omits
- Prove the omission on a running container rather than taking it on trust
- Explain why a `docker commit` restore appears to succeed while losing all persistent data
- Name the three artefacts that actually constitute a restorable Docker backup
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
docker commit web01 myorg/web01:snapshot creates an image from a running
container. It finishes in a second, it produces something you can docker run,
and it feels like a snapshot of the machine. It is a reasonable-looking answer
to βhow do I back this up before I touch itβ.
The Docker CLI reference disposes of it in one sentence:
Commits do not include any data contained in mounted volumes.
Read that against your own stack. The Postgres data directory is a volume. The
uploads directory is a volume. The Letβs Encrypt account key is a volume. The
docker commit image contains none of them, reports no warning, and produces
no error. It contains the parts of the container you did not care about and
omits the parts you did.
What the command actually captures
CONTAINER=web01
docker commit --author 'ops@example.com' --message 'pre-upgrade snapshot' "$CONTAINER" myorg/web01:snapshotThe full option set is four flags: -a/--author, -m/--message,
-c/--change (apply a Dockerfile instruction to the result) and --no-pause.
There is no --include-volumes. There has never been one.
Proving it, in ninety seconds
Do not take the sentence on trust. This runs on any host with a spare gigabyte and demonstrates the failure end to end.
# A container with one volume and one file outside it
docker volume create commit-demo
docker run -d --name commit-demo -v commit-demo:/data alpine:3.20 sleep 3600
# One file on the volume, one on the writable layer
docker exec commit-demo sh -c 'echo "THE IRREPLACEABLE DATA" > /data/important.txt'
docker exec commit-demo sh -c 'echo "junk" > /tmp/scratch.txt'
# Commit
docker commit commit-demo commit-demo:snapshot
# Now run the "backup" on a clean volume and look for both files
docker run --rm -v "$(docker volume create)":/data commit-demo:snapshot sh -c 'echo "--- /tmp:"; ls -la /tmp/scratch.txt; echo "--- /data:"; ls -A /data'$ docker run --rm ... commit-demo:snapshot--- /tmp:
-rw-r--r-- 1 root root 5 Aug 12 09:14 /tmp/scratch.txt
--- /data:Illustrative output
/tmp/scratch.txt β a file nobody would miss β is in the image. /data is
empty. The command exited 0. Nothing anywhere in that sequence said the word
βvolumeβ.
docker rm -f commit-demo
docker volume rm commit-demo
docker image rm commit-demo:snapshotThe verification that would have caught it
Before trusting any container-level snapshot, ask the container what it has mounted. This is the single most useful command in the lesson.
CONTAINER=web01
docker inspect --format '{{range .Mounts}}{{.Type}} | {{.Name}}{{.Source}} -> {{.Destination}}
{{end}}' "$CONTAINER"$ docker inspect --format '{{range .Mounts}}...' web01volume | app_pgdata -> /var/lib/postgresql/data
volume | app_uploads -> /srv/uploads
bind | /etc/myapp/config.yaml -> /etc/myapp/config.yaml
volume | 4f1a9c8e2b7d0a63f5e8c1b4d7a0f3e6c9b2d5a8f1e4c7b0a3d6e9c2b5f8a1d4 -> /var/lib/redisIllustrative output
Every line is a hole in a commit-based backup. The last one β an anonymous
volume with a hex name, created because the image declared a VOLUME and
nobody supplied a mount β is the one people are surprised by, because they did
not know it was there.
The other four problems
Even where volumes are not involved β a genuinely stateless container β commit is a poor backup artefact.
| Property | docker commit image | A real backup |
|---|---|---|
| Reproducible | No Dockerfile, no build context, no provenance | Dockerfile in git, pinned base digest |
| Auditable | Layer diff of unknown origin | Reviewable source |
| Restorable in place | No. There is no docker uncommit | Data restored under the same running service |
| Independent of the registry | No. If the registry is the outage, so is the backup | Copies on separate media |
| Sized sensibly | Includes logs, apt caches, core dumps, /tmp | Only the data |
The βnot restorable in placeβ point is the one that gets underrated. Backups are usually needed for partial loss β one table dropped, one directory deleted β where the requirement is to put some bytes back while everything else keeps serving. A commit image can only be run as a new container. There is no operation that projects it back onto a live system.
What an actual Docker backup consists of
Three artefacts, and you need all three. Any one of them missing turns recovery into archaeology.
STACK=/srv/app
STAMP=$(date +%F)
DEST=/backup
# 1. DATA - via the application's own tool where one exists
docker exec -t app-db pg_dump -U app --format=custom app > "$DEST/app-$STAMP.dump"
# 1b. DATA - for volumes with no dump tool, the volume contents
docker run --rm -v app_uploads:/source:ro -v "$DEST":/backup alpine:3.20 tar czf "/backup/uploads-$STAMP.tar.gz" -C /source .
# 2. DEFINITION - the fully resolved Compose model, image tags pinned to digests
docker compose -f "$STACK/compose.yaml" config --resolve-image-digests > "$DEST/compose-$STAMP.yaml"
# 3. SECRETS - from wherever they authoritatively live, never from the host
# (export from your secret manager here; do not scrape container env)Artefact 2 deserves the emphasis. docker compose config renders the merged,
variable-interpolated model that the engine would actually apply β the file
after .env substitution, extends, override files and short-form-to-long-form
normalisation. --resolve-image-digests rewrites every image: tag to an
immutable name@sha256:... reference. Restoring against nginx:1.27 a year
later gives you a different nginx:1.27 than the one that was running;
restoring against a digest gives you the same bytes.
When docker commit is the right tool
It has a real job, and it is forensic rather than protective. In each of these the artefact is evidence, not a recovery point:
- A container is misbehaving and you must restart it now. Commit first, so you can go back and look at the filesystem after service is restored. The alternative is destroying the evidence.
- Capturing a compromised container for analysis before removing it, so the
writable layer β dropped binaries, modified
/etc/passwd, whiteouts over system files β can be examined offline. - Reproducing a build that only fails on one machine. Commit the failing build container and diff it against a working one.
For that last case there is a sharper tool: docker diff CONTAINER lists every
path added (A), changed (C) or deleted (D) in the writable layer, which is
usually the actual question and does not require producing an image at all.
Knowledge check
Knowledge check Β· 5 questions
Q1. A container runs with `-v pgdata:/var/lib/postgresql/data`. You run `docker commit` on it. What is in the resulting image?
Q2. You restore by running a committed database image. The container starts, the health check passes, and the application connects. What has most likely happened?
Q3. Which artefacts does a `docker commit` image fail to preserve? Select all that apply.
Q4. Which command tells you, before you rely on a snapshot, exactly what data a commit would omit?
Q5. By default `docker commit` pauses the container and its processes while the image is created, and `--no-pause` disables that behaviour.
Passing score: 75%. Answers are checked in this browser.