Skip to main content
RunBook Academy

Docker & ContainersXXIX Β· Docker UpgradesPre-upgrade

Change review β€” what to read before you touch the packages

Intermediate⏱ ~24 mindocker

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

Not yet marked complete on this device.

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.

Read-only / Safefeature inventory
# 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 ls

That 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.

Read-only / Safeinventory extract
$ docker info --format 'storage={{.Driver}} logging={{.LoggingDriver}} cgroup={{.CgroupVersion}} runtime={{.DefaultRuntime}}'
storage=overlay2 logging=json-file cgroup=2 runtime=runc

Illustrative 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:

  1. 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.
  2. 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.
  3. Security. Determines urgency, and whether recreating containers is required rather than just restarting the daemon.
  4. 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.

Read-only / Safevalidate config
sudo dockerd --validate --config-file /etc/docker/daemon.json
Read-only / Safevalidate output
$ sudo dockerd --validate --config-file /etc/docker/daemon.json
configuration OK

Illustrative 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:

SituationRehearse on staging?
Patch release, no daemon.json change, no removals matching inventoryNo
Patch release fixing a CVE you are exposed toNo β€” go faster, not slower
Feature release with anything in Removed matching your inventoryYes
Any line upgrade (28.x to 29.x)Yes, always
daemon.json is being changed in the same windowYes β€” separate the two changes
Host uses a non-default storage driver, runtime or pluginYes

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.

Service impact possiblestaging rehearsal
# 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 ps

Substitute 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

  1. Q1. Which section of the release notes can break a currently working host outright?

  2. Q2. What does `dockerd --validate --config-file /etc/docker/daemon.json` do?

  3. Q3. Which problems will `dockerd --validate` NOT catch? Select all that apply.

  4. 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.