Volume Lifecycle and Drivers
In one sentence: Volumes are first-class objects with their own lifecycle — created, attached, detached, removed — deliberately decoupled from any container's lifecycle, and provisioned through a pluggable driver interface.
You already know
- From Lesson 25: a volume is engine-owned storage, the default for precious data.
- From Lesson 17: reference counting and reachability decide what's safe to delete.
Decoupled on purpose
The whole point of a volume is to outlive containers, so its lifecycle can't be nested inside theirs. The engine tracks each volume with a reference count of attached containers: remove a container and the volume detaches but persists (refcount decrements); a volume is only removable when its refcount is zero, and even then only by an explicit command or prune — never as a side effect. Ten containers can attach one volume simultaneously (shared state — useful, and a consistency footgun the app must handle). The corner case every engine faces: run -v data:/db where data doesn't exist yet — auto-create it, because requiring a separate create step first breaks the common path.
stateDiagram-v2
[*] --> Exists: create (or auto-create on first use)
Exists --> Attached: container starts with -v (refcount 1+)
Attached --> Attached: more containers attach (refcount++)
Attached --> Exists: last container removed (refcount 0)
Exists --> [*]: explicit volume rm / prune
note right of Exists
refcount 0 = "dangling" —
still never auto-deleted
end note
The driver seam
"Give me a directory to mount" is an interface, not an implementation. The default local driver makes a host directory; an NFS driver mounts a remote share; a cloud driver attaches a network disk. The engine speaks four verbs — create, mount, unmount, remove — and never knows which backend answers:
sequenceDiagram
participant E as Engine
participant VS as Volume store
participant DR as Driver (local / nfs / cloud)
participant C as Container setup
E->>VS: does volume "data" exist?
VS-->>E: no
E->>DR: create("data")
DR-->>E: ready
E->>DR: mount("data")
DR-->>E: host path /mnt/…/data
E->>C: bind that path over /db in the rootfs
E->>VS: refcount("data") = 1
note over VS: container rm later → refcount 0,
volume and bytes remain
Anchor these
- Volume lifecycle is deliberately independent; refcounts link it to containers.
- Deletion is always explicit — dangling ≠ deletable-automatically.
- Four verbs (create/mount/unmount/remove) form the driver seam; backends are swappable.
See what actually stuck.
Take the practice scenarios now.