Docker images on SSD
Goal
Guarantee Docker image layers are written under /local-ssd, so the root
filesystem (/) never fills up from image data.
The core rule (read this first)
Docker 29 has TWO possible image stores, and each keeps images in a DIFFERENT place. You must check which store is active, then verify the matching root.
Storage driver (docker info) |
Image layers live in | Knob that must point to SSD |
|---|---|---|
overlay2 (classic) |
Docker data-root |
/etc/docker/daemon.json → "data-root" |
overlayfs (containerd store) |
containerd root |
/etc/containerd/config.toml → root |
Key facts learned on these machines:
- Docker 29 fresh installs default to the containerd store (
overlayfs), even with NO"features"block indaemon.json. Do not add acontainerd-snapshotterfeature flag — it is not needed and not what the fresh machines use. - An in-place upgrade that finds existing overlay2 data keeps using
overlay2. That is why some machines areoverlay2and freshly-imaged ones areoverlayfs. - The classic trap: setting
data-rootindaemon.jsonlooks correct, but on a containerd-store machine it does NOTHING for image location — images still go to containerd'sroot(default/var/lib/containerd, which is on/). This is the usual cause of/filling up. - Verify the EFFECTIVE containerd root with
containerd config dump, not just the file — drop-ins or defaults can differ from what config.toml appears to say.
Assumptions / policy (confirmed with the user)
- SSD mount is
/local-ssd. Confirm it is a SEPARATE mount from/(viadf). Targets: overlay2 →/local-ssd/docker; containerd →/local-ssd/containerd. - Report first, then fix only after the user confirms each change. Never auto-edit or restart daemons unattended.
- Re-pull/rebuild is acceptable. No need to preserve or migrate existing image layers when switching stores or roots — losing image visibility is OK.
Workflow
1. Audit (read-only, always safe)
Run the bundled audit script as root:
sudo bash scripts/audit.sh
It reports: OS, docker version, storage driver, docker root dir, both config
files, effective containerd root, directory existence, disk usage per candidate
store path, and df for / vs /local-ssd. Makes zero changes.
2. Diagnose
From the audit output determine:
- Is
/local-ssda separate mount with free space? (If not, STOP — tell the user.) - Which store is active (
overlay2vsoverlayfs)? - Is the matching root already on
/local-ssd?- overlay2 →
DockerRootDirshould be/local-ssd/docker. - overlayfs → effective containerd
rootshould be/local-ssd/containerd.
- overlay2 →
- Where does the disk usage actually sit? The path holding gigabytes is the real
store. If that path is on
/(e.g./var/lib/containerd/...content), that is the bug.
If everything already points at /local-ssd, report "already correct" and stop.
3. Report
Present a short table: store type, current root, whether it is on SSD, and the exact change needed. Then ask the user to confirm before editing anything.
4. Fix (only after confirmation)
Apply the minimal change for the active store, then restart:
- overlay2: set
"data-root": "/local-ssd/docker"in/etc/docker/daemon.json. - overlayfs / containerd: set
root = "/local-ssd/containerd"in/etc/containerd/config.toml(keep existing lines likedisabled_plugins = ["cri"]). Optionally also setdata-rootin daemon.json for consistency, but note it does not govern image location in this mode. - Create the target dir if missing:
sudo mkdir -p <target>. - Restart in order:
sudo systemctl restart containerd && sudo systemctl restart docker. - Because re-pull is acceptable, do not attempt to migrate old layers; the user
can
docker pull/ rebuild as needed. Optionally note the old store path (e.g./local-ssd/docker/overlay2or/var/lib/...) that can be reclaimed.
5. Verify
Re-run sudo bash scripts/audit.sh and confirm:
- Active store's root is now on
/local-ssd. - New image data lands there (pull a small image, e.g.
docker pull alpine, and confirm size grows under the SSD path, not on/).
Notes
- Restarting docker on a machine that switches store type will hide images stored in the previous store. That is expected and acceptable per policy (re-pull).
- Never run
chmod -Ron store directories; they are root-only by design. Usesudofor reads instead of loosening permissions.