Storage drivers & the layered filesystem
overlay2 and copy-on-write.
The storage driver is the engine component that implements image layers and copy-on-write on disk. The modern default is overlay2, a union filesystem: it stacks the image’s read-only layers as lower directories, the container’s writable layer as an upper directory, and presents a single merged view to the container. Older drivers (devicemapper, aufs, btrfs) exist for historical or special cases, but overlay2 is what you will run on any current kernel.
$ docker info -f '{{ .Driver }}'overlay2$ docker info -f '{{ json .DriverStatus }}'[["Backing Filesystem","extfs"],["Supports d_type","true"],["Using metacopy","false"]]
How overlay2 works
Each layer is a directory under /var/lib/docker/overlay2. The kernel’s overlay filesystem merges the read-only lowerdir (image layers) with the writable upperdir (the container’s layer): reads come from the topmost layer that has the file, and the first write to a lower-layer file copies the whole file up to the upperdir before modifying it. That copy-up is cheap for small files and increasingly expensive as files grow.
$ sudo ls /var/lib/docker/overlay2 | head -3 # one dir per layer1a2b3c...4d5e6f...$ sudo mount | grep overlay | head -1overlay on /var/lib/docker/overlay2/<id>/merged type overlay(lowerdir=...:...,upperdir=.../diff,workdir=.../work)
Scenario: writes to a large file are slow
A workload that rewrites a large file — a database file, a big log, an on-disk cache — is sluggish, and the reason is copy-on-write: the first modification copies the entire file from a lower layer into the writable layer. The fix is to put that data on a volume, which writes straight to the backing filesystem and bypasses the union/CoW machinery entirely. This is the concrete reason “databases go on volumes.”
# DB data on a volume -> direct writes, no overlay copy-up, and it persists$ docker run -d --name db \--mount type=volume,source=pgdata,target=/var/lib/postgresql/data \postgres:16
Scenario: check the driver and move Docker’s data disk
On a new host you want to confirm the driver is healthy and, often, move Docker’s storage onto a dedicated disk so images and volumes do not fill the root partition. Confirm overlay2 with a backing filesystem that supports d_type (ext4 or xfs with ftype=1 — without it overlay2 misbehaves), then repoint data-root in daemon.json to the mounted disk and restart.
{"storage-driver": "overlay2","data-root": "/mnt/docker-data" // a dedicated disk, not the root partition}// verify after restart: docker info | grep -E "Storage Driver|Docker Root Dir"