Migrate to RunxBuild and earn up to $50 in hosting credit on your first deposit.

Calculate your savings
unxBuild

Upgrade Docker: Doing It Without Losing Your Containers

Sean

Platform Writer

Aug 04, 2026
8 min read

Upgrading Docker Engine restarts the daemon, which stops every running container. Your images and volumes survive; anything written to a container filesystem may not.

Upgrade Docker: Doing It Without Losing Your Containers

Docker upgrades are routine and mostly boring, which is exactly why they occasionally go wrong — nobody plans for a boring operation. The daemon restart is the part that matters, because it takes your workloads down with it.

The good news is that the durable state is genuinely durable. Images, named volumes, and networks all live outside the daemon process. What you lose is whatever was only ever in a container’s writable layer, plus availability for the duration.

Table of contents

Check what you have before changing anything

Two commands worth running first: what version is installed, and what is currently running that is about to stop.

docker version
docker info | head -20

# What will be interrupted
docker ps

# What was installed and from where
apt list --installed 2>/dev/null | grep -i docker

The docker version output shows client and server separately. A mismatch is normal and usually harmless — the API is versioned and negotiates down — but a very old client against a new daemon can be missing commands you expect.

Note the storage driver from docker info. It should be overlay2 on any modern system. If it says devicemapper or aufs, you are on a configuration old enough that the upgrade deserves more caution than this page assumes.

Upgrading on Ubuntu and Debian

If Docker came from the official repository, this is a package upgrade. The important part is upgrading all the components together rather than one at a time.

sudo apt update

# See what is available before committing
apt list --upgradable | grep -i docker

# Upgrade all five packages together, as Docker documents
sudo apt install --only-upgrade \
  docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

docker version

Upgrading docker-ce while leaving containerd.io behind is the usual way to get a broken installation. They are versioned together and the daemon will refuse to start against a containerd it does not recognise.

If Docker was installed from Ubuntu’s own repository rather than Docker’s, the package is docker.io and the version will lag considerably. Migrating to the official repository is worth doing, but that is a removal and reinstall, not an upgrade — plan it separately and back up first.

On RHEL, CentOS, Rocky, and Alma, the same operation with the other package manager.

sudo dnf upgrade docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin
sudo systemctl restart docker

Protecting your data across the restart

Understanding what survives makes the risk assessment simple.

  • Images — stored in /var/lib/docker, unaffected by the upgrade
  • Named volumes — stored separately, unaffected
  • Bind mounts — they are host directories, so entirely unaffected
  • Networks and their configuration — persisted, recreated on daemon start
  • Container writable layers — preserved on disk, but anything in memory is lost
  • Running state — every container stops when the daemon restarts

The risk is concentrated in one place: data written inside a container rather than to a volume. A database running with its data directory on the container’s writable layer will survive an upgrade but not a docker compose down, and people conflate those two operations constantly.

# Confirm your stateful containers actually use volumes
docker inspect my-postgres --format '{{json .Mounts}}'

# Back up a named volume before a major upgrade
docker run --rm \
  -v postgres_data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/postgres_data.tar.gz -C /data .

Do that volume backup before any major-version jump. It takes a minute and removes the entire category of upgrade regret.

The controlled sequence

For anything carrying traffic, stop cleanly rather than letting the daemon restart pull the rug out.

  1. Back up named volumes for stateful services.
  2. Stop application containers gracefully with docker compose stop, giving them time to flush and close connections.
  3. Run the package upgrade.
  4. Verify the daemon is healthy with systemctl status docker and docker info.
  5. Start services again with docker compose up -d.
  6. Check that everything came back, including health status.
cd /opt/myapp
docker compose stop

sudo apt update && sudo apt install --only-upgrade \
  docker-ce docker-ce-cli containerd.io \
  docker-buildx-plugin docker-compose-plugin

sudo systemctl status docker --no-pager
docker compose up -d
docker ps --format "table {{.Names}}\t{{.Status}}"

Use stop, not down. down removes containers and networks, and with -v it removes named volumes too — which is the command that actually deletes your database. stop halts them and leaves everything in place.

Containers with restart: unless-stopped come back automatically when the daemon starts. That is convenient, but it means they restart in whatever order the daemon chooses rather than respecting your dependency graph, which is why an explicit compose up -d afterwards is worth the extra command.

Live restore, for hosts that cannot take the downtime

Live restore keeps containers running while the daemon itself restarts. It is off by default and worth enabling on any host running something that matters.

# /etc/docker/daemon.json
{
  "live-restore": true,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
sudo systemctl reload docker
docker info | grep -i "live restore"

The limits are real. Live restore covers daemon restarts and patch upgrades, not major-version changes to the daemon. It is incompatible with Swarm mode. And while the daemon is down, container logs are not collected and health checks do not run.

Enable it before you need it — the setting only takes effect from the restart that applies it, so turning it on during the upgrade you were trying to protect does not help.

The log-opts in that config are unrelated to upgrades but belong in every daemon.json. Without them, container logs grow without limit until they fill the disk, which is a far more common outage cause than a bad upgrade.

When the daemon does not come back

Occasionally the upgrade completes and Docker refuses to start. The journal will tell you why.

sudo systemctl status docker.service --no-pager -l
sudo journalctl -xeu docker.service --no-pager | tail -50

# Validate daemon.json -- a trailing comma stops the daemon dead
sudo python3 -c "import json; json.load(open('/etc/docker/daemon.json'))"

# Check containerd, which must be healthy first
sudo systemctl status containerd --no-pager

In practice the cause is usually one of three things: malformed JSON in daemon.json, a version mismatch because containerd.io was not upgraded alongside docker-ce, or a storage driver that changed underneath existing containers.

The JSON case is the most common and the most annoying, because the daemon exits immediately with a message that does not always name the file. Validate it before restarting, not after.

How this fits the rest of the stack

Every host running Docker directly is a machine somebody has to patch, monitor, and eventually upgrade at an inconvenient hour. That work is real and it does not appear on any invoice. RunxBuild builds from your Dockerfile and runs the result on managed infrastructure, so engine upgrades, daemon configuration, and log rotation stop being your problem. The RunxBuild hosting calculator shows what the equivalent services cost, which is the honest comparison against a VPS once you price the maintenance time.

Useful related references:

FAQ

Will upgrading Docker delete my containers?

No. Images, named volumes, and container filesystems all persist. The daemon restart stops running containers, and anything held only in memory is lost, but nothing on disk is removed by the upgrade itself.

Do I need to stop containers before upgrading?

Not strictly, since the daemon restart stops them anyway. Stopping them gracefully first is better practice for stateful services, because it gives them a chance to flush writes and close connections cleanly.

What is live restore in Docker?

A daemon setting that keeps containers running through a daemon restart. Enable it in /etc/docker/daemon.json with "live-restore": true. It does not cover major-version upgrades and is incompatible with Swarm mode.

Why does Docker fail to start after an upgrade?

Most often malformed JSON in /etc/docker/daemon.json, or a version mismatch because containerd.io was not upgraded alongside docker-ce. Check journalctl -xeu docker.service and validate the JSON file.

Should I upgrade docker-ce on its own?

No. Upgrade docker-ce, docker-ce-cli, containerd.io, and the buildx and compose plugins together. They are versioned as a set and a partial upgrade commonly leaves the daemon unable to start.

#Upgrade Docker#Docker#Docker Engine#Ubuntu#System Administration