Docker
The Docker extension adds Docker Engine, the Docker CLI, containerd, Buildx, and Compose to a Frostyard bootc image. Use it when a workload needs Docker or Docker Compose. Every image carries the extension’s definition, switched off. The extension itself is not in the image: Updex turns it on and downloads it with one command.
Before you start
Section titled “Before you start”You need:
- A Frostyard bootc image. Every image built on Base has
systemd-sysextandfrostyard-updex. - Root access to enable, update, and remove the extension. Checks that change
nothing run without
sudo. - Network access to
https://repository.frostyard.org/ext/docker/. - Free space in
/varfor the download and the installed image. - A backup of any containers and volumes you cannot recreate.
Docker has no published test results on Frostyard images yet. Try it on a machine you can spare first.
Choose Docker
Section titled “Choose Docker”Pick Docker when your workload needs Docker Engine or Compose. Snow already
includes Podman and Distrobox, and the catalog also has a podman extension.
Running Docker next to another container engine on one host is not a
supported setup. Pick the one your workload needs.
The extension gives you the engine and its command-line tools. It does not
give you Docker Desktop, a registry, or a package manager. It adds no APT
repository and runs no apt install. Do not also install Docker from APT.
Enable Docker
Section titled “Enable Docker”See what Updex found:
updex componentsupdex features list --component=dockerdocker appears as a component, with its feature disabled. --component=docker
limits each command to Docker. Without it, Updex acts on every component it
finds.
Enable Docker and download it now:
sudo updex features enable docker --nowUpdex downloads the image, checks its checksum and signature, links it, and
refreshes the merge. A missing or bad signature stops the command; Updex never
installs an unsigned image. Without --now, Updex only marks the feature
enabled, and the next update downloads it.
Enabling writes one file in /etc:
/etc/sysupdate.docker.d/docker.feature.d/00-updex.conf. The extension image
itself does not change.
Check that Docker is merged and its sockets are up:
systemd-sysext statussystemctl status docker.socket containerd.servicesystemd-sysext status lists docker, and both units are active. You do
not start docker.service yourself: docker.socket starts it and hands
dockerd its sockets.
A merge does not prove that setup completed. At boot, reload-sysext.service
runs systemd-sysusers, systemd-tmpfiles --create --graceful, a
systemd-sysctl replay of the inotify, fs.aio-max-nr, and kernel.keys
limits, and systemctl daemon-reload after the merge. A refresh by Updex v2.1.3
and later also runs systemd-sysusers and systemd-tmpfiles --create. After an
interactive --now merge, the systemd-sysctl replay waits for the next boot,
and systemd may not have loaded the new units yet. If the docker group, the
files in /etc/docker, or the sockets are missing, reboot and check again.
If enable --now exits with a refresh error (refresh_error in JSON), the
download worked, but the activation did not. If the output says
activation did not finish, the extension is merged, but users and groups can
be missing: reboot. Otherwise the merge state is unknown: reboot. A
sudo systemd-sysext refresh by hand does not create users and groups. Then run
the two checks above again.
Update
Section titled “Update”See whether an update exists:
updex features check --component=dockerThis changes nothing. It shows one row for each enabled feature. A feature
you have not enabled has no row, so a missing row does not mean “up to date”.
If Updex cannot fetch or verify a manifest, that row shows UPDATE=error and
the command exits non-zero. Treat an error row as unknown, not as up to date.
Install the newest version:
sudo updex features update --component=dockerUpdex downloads and verifies the new image, switches the link, deletes older
versions, and refreshes the merge. Add --no-vacuum to keep older versions.
To see what would change, without changing anything:
sudo updex --dry-run features update --component=dockerThe refresh swaps /usr under the running system, and the engine can
restart. Stop or drain containers first if a restart would hurt them. Images,
containers, and volumes live in /var. An update does not touch them, and it
does not back them up.
Once you enable Docker, it updates on its own: new versions are staged and become
active at the next boot. To opt out for the whole host, run
sudo systemctl mask --now updex-update.timer. See
Automatic updates.
To take one update at the next boot without the timer, run
sudo updex features update --no-refresh --component=docker, then reboot.
Roll back
Section titled “Roll back”Roll back with sudo updex features rollback docker. It takes effect at the next boot. Updex then holds updates until a newer version is published. To stop future updates instead, see below. To remove the extension, use the remove command below. Your images, containers, and volumes in /var stay either way. See Roll back.
Stop updates or remove
Section titled “Stop updates or remove”Stop future updates:
sudo updex features disable dockerThis only sets Enabled=false. Docker stays merged, and the link
/var/lib/extensions/docker.raw stays. The next boot merges the version that the link names. LINKED in
updex features list shows it. To go back to the version you run now, roll
back first. Updex and the timer skip it from now on.
Remove Docker now:
sudo updex features disable docker --now --forceThis unmerges all extensions on the host, deletes the Docker image, and merges the rest again. Running containers can stop immediately. Stop or drain your workloads first, and reboot when the command finishes.
Without --force, Updex refuses while Docker is merged:
Extension docker (version ...) is active. Removing requires --force and a reboot to take effect.
Removal does not touch /var. Images, containers, volumes, and bind-mounted
data stay; only the engine and its units go. Enabling Docker again does not
restart your workloads.
If the refresh at the end fails, the remaining extensions may stay unmerged. Run
sudo systemd-sysext refresh, or reboot. If the output says
activation did not finish, they are merged, but their users and groups can be
missing: reboot.
Special cases
Section titled “Special cases”The extension copies its default files into /etc/docker,
/etc/default/docker, and /etc/containerd only when they are missing. Your
edits there survive reboots and updates. The defaults stay in
/usr/share/factory/etc.
The extension creates a docker group and ships the rootless extras. It adds
nobody to the group. Choose rootless mode or group membership yourself.
The extension owns docker.socket and containerd.service. Do not run a
second container engine’s daemon, or another containerd, on the same host
unless you have tested that combination.
Troubleshooting
Section titled “Troubleshooting”| Symptom | Check | Fix |
|---|---|---|
| Docker is not listed | updex features list --component=docker and updex components |
If docker is listed but disabled, enable it. If it is missing, the image may be older than named components. |
enable --now exits non-zero after the download |
The output shows Error: sysext refresh failed (refresh_error with --json) |
If the output says activation did not finish, reboot. Otherwise reboot too: a refresh by hand does not create the extension’s users and groups. Then check systemd-sysext status. |
| The engine does not answer | systemctl status docker.socket containerd.service |
Start with the socket and containerd. Docker starts through the socket, not docker.service. |
| A signature or manifest check fails | The command output, and updex features check --component=docker |
Check the network and the published manifest. Never turn verification off. |
| An update stopped containers | The journal shows the engine restart after the /usr refresh |
Drain workloads before you update by hand. Back up volumes. |
| Workloads stopped after removal | systemd-sysext status and systemctl status docker.socket |
Enable Docker again if you still need it. Your data in /var is still there. |
Do not repair the extension with apt. If a merged image is missing files,
the fix is a corrected extension build.
What ships
Section titled “What ships”| Item | What you get |
|---|---|
| Packages | docker-ce, docker-ce-cli, containerd.io, docker-buildx-plugin, docker-compose-plugin, docker-ce-rootless-extras |
| Version | The image file name carries the docker-ce version |
| Image file | docker_<version>_<os>_<arch>.raw.zst; .raw.xz, .raw.gz, and .raw also work |
| Download | From https://repository.frostyard.org/ext/docker/, signature required (Verify=true), into /var/lib/extensions.d/ |
| Services | docker.socket and containerd.service, enabled by 20-docker.preset and started at boot by 10-docker.conf |
| Configuration | Defaults for /etc/default/docker, /etc/docker, and /etc/containerd |
| Group | docker, from usr/lib/sysusers.d/docker.conf |
The active image is the link /var/lib/extensions/docker.raw. It points to
the chosen file in /var/lib/extensions.d/. The transfer file names a second
link, CurrentSymlink=docker.raw, but Updex deletes that one
(/var/lib/extensions.d/docker.raw) when it installs.
The Base image ships a preset that disables docker.service and
docker.socket. The extension’s 20-docker.preset sorts first, and the first
matching preset wins, so the extension’s choice applies.
Updex picks the image that matches your OS version (%w in the file name) and
your architecture (%a). The catalog lists versions, not architectures, so it
does not tell you which architectures exist.
The image is an overlay (Overlay=yes) that holds only what Base does not
already have. A later Base can
therefore break an older Docker image. Each build checks that the engine, the
CLI, containerd, the service unit, and the activation drop-in are present. A
build that is missing one fails.
See also
Section titled “See also”- Snow image
- Incus system extension
- Tailscale system extension
- System extension model
- Updex v2.1.3 command reference
Sources
Section titled “Sources”Reviewed 2026-10-27; Updex facts reviewed 2026-10-30. snosi commit
b2858ca0222814c395cf8248db98f3e096d57dc9;
Updex v2.1.3 commit
2661e987faac986f2594d1d9bbbadf1bf3053f5b.
mkosi.images/docker/mkosi.confmkosi.images/docker/mkosi.finalizemkosi.images/docker/required-paths.txtmkosi.images/docker/mkosi.extra/usr/lib/systemd/system-preset/20-docker.presetmkosi.images/docker/mkosi.extra/usr/lib/systemd/system/multi-user.target.d/10-docker.confmkosi.images/docker/mkosi.extra/usr/lib/tmpfiles.d/docker.confmkosi.images/docker/mkosi.extra/usr/lib/sysusers.d/docker.confmkosi.images/base/mkosi.extra/usr/lib/sysupdate.docker.d/docker.featuremkosi.images/base/mkosi.extra/usr/lib/sysupdate.docker.d/docker.transfermkosi.images/base/mkosi.extra/usr/lib/systemd/system-preset/30-docker.presetmkosi.images/base/mkosi.extra/usr/lib/systemd/system/reload-sysext.serviceshared/sysext/postoutput/sysext-postoutput.shdocs/design/sysexts.mddocs/nbc-to-bootc-migration.md- Updex PR #445: refuse removal of a merged extension
- Updex v2.1.3
updex/features.go - Updex v2.1.3
README.md - Updex v2.1.3
updex/install.go - Updex v2.1.3
sysext/manager.go - Updex v2.1.3 configuration reference
- Updex v2.1.3 SDK reference
- Updex v2.1.3 ADR 0007: daemon stages, never activates
- Updex v2.1.3 release
- Updex
docs/adr/0019-apply-merged-sysusers-and-tmpfiles-on-a-live-refresh.md(a live refresh runssystemd-sysusersandsystemd-tmpfiles --create; when the last refresh fails, the merge state is unknown; a refresh by hand does not runsystemd-sysusers) - snosi#1189 and snosi#1193 (open on 2026-10-30): a refresh reloads systemd only when a merged extension sets
EXTENSION_RELOAD_MANAGER=1, and this extension does not set it yet src/data/extensions.jsonmkosi.images/base/mkosi.extra/usr/lib/systemd/system-preset/05-updex.presetdocs/adr/0016-automatic-sysext-updates-apply-at-next-boot.md