Containers are ephemeral by default, but Docker provides several mechanisms for persisting data outside the container's writable layer. A Docker volume is a persistent storage object managed by Docker itself and stored in /var/lib/docker/volumes/. There are three flavors: named volumes (created explicitly with docker volume create mydata and easy to back up, list, and reuse), bind mounts (which map an arbitrary host path directly into a container and are favored in development for live-reload workflows), and tmpfs mounts (which live in the host's RAM and swap, making them extremely fast but non-persistent, and ideal for secrets or temporary caches). The VOLUME instruction in a Dockerfile declares a mount point for externally attached storage, and docker run --tmpfs /tmp:size=100m attaches a memory-backed mount at /tmp.
Anonymous volumes are created implicitly when a Dockerfile declares VOLUME without a name or when you run docker run -v /data. Docker generates a random name, which makes them hard to reference later, so the recommended pattern is to use named volumes in production. When a container is removed, its volumes are not deleted by default, which protects data, but you can use docker rm -v to also clean up anonymous volumes associated with a container, or docker volume prune to remove all unused volumes. Volume drivers and plugins extend Docker to mount external storage such as NFS, AWS EBS, Azure Disk, GCE Persistent Disk, and Ceph; the built-in local driver handles simple cases and others are installed separately. Bind mounts also have a propagation mode (rprivate, private, rshared, shared, slave, rslave) that controls how mounts created inside a mount propagate to the host, though most users should leave this at its default.