Docker & ContainersXXIX Β· Docker UpgradesPre-upgrade
Change review β what to read before you touch the packages
What you'll learn
- Build an inventory of the Docker features this host actually depends on
- Read release notes and the deprecation list against that inventory
- Validate `daemon.json` against the target version before restarting anything
- Decide whether a staging rehearsal is required for this particular upgrade
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
Release notes for a Docker feature release run to several hundred entries. Almost none of them apply to your host. Change review is the work of finding the three that do.
The output of this lesson is a short written statement β βthis upgrade changes X, Y and Z for this host, and nothing elseβ β that you can put in a change ticket and check against afterwards. Without it, βwe upgraded and something brokeβ has no baseline to compare to.
Start with the inventory, not the notes
Reading release notes first is the mistake. You end up scanning for anything alarming, which is both exhausting and unreliable. Build the inventory first, then read the notes with a list of things to search for.
# Component versions
docker version
docker info
# The daemon configuration β every non-default behaviour lives here
sudo cat /etc/docker/daemon.json
# Storage and logging drivers in use
docker info --format 'storage={{.Driver}} logging={{.LoggingDriver}} cgroup={{.CgroupVersion}} runtime={{.DefaultRuntime}}'
# Network drivers actually in use
docker network ls --format '{{.Driver}}' | sort -u
# Volume drivers actually in use
docker volume ls --format '{{.Driver}}' | sort -u
# Non-default runtimes and plugins
docker info --format '{{json .Runtimes}}'
docker plugin lsThat is the whole surface. A change to a driver you do not use is not your
problem; a change to the one in .Driver is.
$ docker info --format 'storage={{.Driver}} logging={{.LoggingDriver}} cgroup={{.CgroupVersion}} runtime={{.DefaultRuntime}}'storage=overlay2 logging=json-file cgroup=2 runtime=runcIllustrative output
Four values. Any release note that does not mention one of them, or a flag in
your daemon.json, or a driver from the network and volume lists, can be
skipped.
Reading the release notes against it
Dockerβs release notes are organised per version with sections for
Bug fixes and enhancements, Deprecated, Removed and Security. Read
them in this order:
- Removed. The only section that can break a working host outright. If nothing here appears in your inventory, the upgrade cannot fail for this reason.
- Deprecated. Nothing breaks yet, but this is your warning for the next line upgrade. Add anything that matches your inventory to a follow-up ticket now, while you have the context.
- Security. Determines urgency, and whether recreating containers is required rather than just restarting the daemon.
- Everything else. Skim for default changes. A changed default is the most under-reported class of breakage because it appears under βenhancementsβ.
Validating the daemon config before it runs
dockerd can parse and validate a configuration file without starting. This
is the single most valuable pre-upgrade check and almost nobody runs it.
sudo dockerd --validate --config-file /etc/docker/daemon.json$ sudo dockerd --validate --config-file /etc/docker/daemon.jsonconfiguration OKIllustrative output
Run it after the packages are staged but before the daemon restarts β
in practice, run it against the new dockerd binary as soon as it is on disk.
A key that the new version no longer accepts turns a silent failure to start
into a one-line answer.
Deciding whether to rehearse
Not every upgrade needs a staging run. Use the size of the version jump and the inventory together:
| Situation | Rehearse on staging? |
|---|---|
Patch release, no daemon.json change, no removals matching inventory | No |
| Patch release fixing a CVE you are exposed to | No β go faster, not slower |
| Feature release with anything in Removed matching your inventory | Yes |
Any line upgrade (28.x to 29.x) | Yes, always |
daemon.json is being changed in the same window | Yes β separate the two changes |
| Host uses a non-default storage driver, runtime or plugin | Yes |
That last row is the one people skip. Anything outside overlay2 + runc +
json-file has a smaller user base upstream and correspondingly less
pre-release exercise.
# 1. Match the production configuration
sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.prod-copy
# 2. Install the exact target version, not "latest"
sudo apt-get install -y docker-ce=5:28.3.2-1~ubuntu.24.04~noble docker-ce-cli=5:28.3.2-1~ubuntu.24.04~noble containerd.io
# 3. Confirm the daemon came back and the versions are what you asked for
systemctl is-active docker
docker version
# 4. Start the actual workload and exercise it
docker compose -f /srv/staging/compose.yaml up -d
docker compose -f /srv/staging/compose.yaml psSubstitute the version string from apt-cache madison docker-ce on the host β
the distribution suffix differs per release and a wrong one makes apt report
that the version is unavailable rather than installing the wrong thing, which
is at least a safe failure.
The change ticket
The output of the review, in the shape it should be written down:
CHANGE: Docker Engine 28.1.3 -> 28.3.2 on host app-01
INVENTORY
storage=overlay2 logging=json-file cgroup=2 runtime=runc
daemon.json keys: live-restore, log-opts, builder.gc, data-root
network drivers in use: bridge
volume drivers in use: local
plugins: none
RELEASE NOTES REVIEWED: 28.2.0, 28.2.1, 28.2.2, 28.3.0, 28.3.1, 28.3.2
Removed: nothing matching inventory
Deprecated: one item matching inventory -> follow-up ticket OPS-4471
Security: two runc fixes -> containers must be RECREATED, not restarted
CONFIG VALIDATION: dockerd --validate -> configuration OK
REHEARSAL: not required (patch-to-feature, no removals matching)
EXPECTED IMPACT: daemon restart, ~5s control-plane gap, containers survive
(live-restore=true confirmed in daemon.json)
ROLLBACK: pin to 5:28.1.3-1~ubuntu.24.04~noble, see rollback lesson
Every line of that is derived from a command in this lesson. None of it is judgement, which is what makes it reviewable by someone else.
Knowledge check
Knowledge check Β· 4 questions
Q1. Which section of the release notes can break a currently working host outright?
Q2. What does `dockerd --validate --config-file /etc/docker/daemon.json` do?
Q3. Which problems will `dockerd --validate` NOT catch? Select all that apply.
Q4. Moving from 28.1.3 to 28.3.2 requires reading the release notes for the intermediate versions, not just for 28.3.2.
Passing score: 75%. Answers are checked in this browser.