Learning Platform
Глоссарий Troubleshooting
Урок 10.03 · 24 мин
Начальный
dockervolumesbackupdrivers

Named volumes: lifecycle, drivers, backup

Named volume — это persistence-механизм Docker по умолчанию для production-сценариев. В отличие от bind mount, где ты сам отвечаешь за host path, named volume полностью управляется Docker’ом: создаётся, монтируется, удаляется через CLI или compose. Этот урок — про lifecycle, физическое хранение, volume drivers и backup. После него ты будешь спокойно держать Postgres data в named volume и переносить его между машинами.


df и du: сколько диска и где именно

Lifecycle: create, ls, inspect, rm

# Создать.
docker volume create pgdata
# pgdata

# Создать с metadata.
docker volume create \
  --driver local \
  --label env=dev \
  --label app=postgres \
  pgdata-dev

# Все volumes.
docker volume ls
# DRIVER    VOLUME NAME
# local     pgdata
# local     pgdata-dev

# Подробности конкретного.
docker volume inspect pgdata
# [
#   {
#     "CreatedAt": "2026-05-15T10:23:11Z",
#     "Driver": "local",
#     "Labels": {},
#     "Mountpoint": "/var/lib/docker/volumes/pgdata/_data",
#     "Name": "pgdata",
#     "Options": {},
#     "Scope": "local"
#   }
# ]

# Удалить (только если ни один контейнер не использует).
docker volume rm pgdata-dev

# Удалить все unused volumes (опасно, спросит подтверждения).
docker volume prune
WARNING

docker volume prune удаляет все volumes, которые не примонтированы ни к одному контейнеру (даже остановленному). Если ты выключил Postgres-контейнер и сделал prune — Postgres data может уйти. Перед prune всегда сделай docker volume ls и пойми, что удаляется.


Lifecycle взаимодействия с контейнером

Volume и контейнер связаны через mount при docker run -v:

docker run -d --name pg -v pgdata:/var/lib/postgresql/data postgres:17
# pgdata создался автоматически, потому что не существовал

docker rm -f pg
# Контейнер удалён, volume — нет.

docker volume ls
# local     pgdata

docker run -d --name pg2 -v pgdata:/var/lib/postgresql/data postgres:17
# Новый контейнер видит ту же базу.

Volume переживает удаление контейнера. Это и есть его смысл. Удалить volume вместе с контейнером — отдельный явный жест:

docker rm -fv pg          # -v убирает анонимные volumes контейнера, но не именованные
docker volume rm pgdata   # явное удаление именованного volume
Lifecycle: контейнер vs volume
docker volume create pgdataVolume создан, пустой. Лежит в /var/lib/docker/volumes/pgdata/_data/. Контейнера нет
docker run -v pgdata:...Контейнер монтирует volume. Postgres initdb наполняет /var/lib/postgresql/data — пишет на volume
docker rm -f pgКонтейнер удалён. Volume остался, данные на месте. docker volume ls показывает pgdata
docker run -v pgdata:...Новый контейнер монтирует тот же volume. Postgres видит существующий data dir, пропускает initdb, поднимается с готовой базой

Где физически живёт volume

Default driver — local. На Linux:

sudo ls /var/lib/docker/volumes/pgdata/_data/
# base/
# global/
# pg_wal/
# postgresql.conf
# ...

Внутри _data — реальная файловая система Postgres. Можно даже скопировать содержимое отсюда (если хост-Postgres имеет ту же major-версию) и подложить в другой volume — Docker этого не знает, ему всё равно.

На macOS Docker Desktop держит /var/lib/docker/ внутри Linux VM (com.docker.virtualization.framework), и доступа из Finder нет. То же с OrbStack и Rancher Desktop. Чтобы заглянуть внутрь:

# OrbStack: orb shell в alpine.
docker run --rm -it -v pgdata:/data alpine ls -la /data

# Любая платформа: подцепить busybox.
docker run --rm -v pgdata:/d busybox ls -la /d
TIP

Volume — это просто папка на хосте с дополнительной маркировкой. Если ты потерял доступ к Docker daemon, но /var/lib/docker/volumes/ цел, можно восстановить данные через простой cp -r в любую другую FS.


Volume drivers

Default — local. Это просто папка на хосте. Но Docker позволяет подключать другие драйверы:

DriverГде живут данныеКогда полезен
local/var/lib/docker/volumes/Single-host, default
local + NFSNFS-серверНесколько хостов читают одну папку
nfsPlugin для NFS-onlyЧистый NFS без хитростей
glusterfsGlusterFS-кластерРаспределённое хранилище для swarm
s3fsЧерез плагин, S3-bucketАрхив в S3, не для горячих БД
ОблачныеAWS EBS / Azure Disk / GCE PDk8s-стиль persistence через CSI

Local-NFS вариант через стандартный driver:

docker volume create \
  --driver local \
  --opt type=nfs \
  --opt o=addr=10.0.0.5,rw \
  --opt device=:/exports/data \
  shared-data

Этот volume — по сути NFS-mount внутри Docker. Контейнеры на разных хостах могут монтировать shared-data и видеть одни данные.

Для junior DE на одной dev-машине local — достаточный выбор. Кастомные драйверы — это уже зона compose-стенда с несколькими нодами или k8s.


Backup и restore

Стандартный паттерн: одноразовый контейнер монтирует исходный volume и host-папку для tar-архива, копирует данные.

# Backup: pgdata -> ./backups/pgdata-2026-05-15.tar.gz
docker run --rm \
  -v pgdata:/source:ro \
  -v $(pwd)/backups:/backup \
  alpine \
  tar czf /backup/pgdata-2026-05-15.tar.gz -C /source .

Что произошло:

  • Контейнер alpine монтирует pgdata в /source (read-only).
  • Хост-папка ./backups примонтирована в /backup как bind.
  • tar czf ... -C /source . упаковывает содержимое volume в архив, который лежит на хосте.

Restore — обратно:

docker volume create pgdata-restored
docker run --rm \
  -v pgdata-restored:/target \
  -v $(pwd)/backups:/backup \
  alpine \
  tar xzf /backup/pgdata-2026-05-15.tar.gz -C /target
WARNING

Для Postgres простой tar data directory работает только если Postgres-контейнер остановлен в момент бэкапа. На запущенной БД tar поймает inconsistent state — pg_wal не дописан, control file в полпути. Для горячего бэкапа используй pg_dump или pg_basebackup, а не tar volume. Бэкап volume — корректный вариант для остановленного сервиса или для data-only volumes (CSV, parquet, MinIO buckets).


Compose: volumes секция

В compose-файле named volumes объявляются в top-level секции volumes::

services:
  postgres:
    image: postgres:17
    environment:
      POSTGRES_PASSWORD: secret
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init:/docker-entrypoint-initdb.d:ro

  minio:
    image: minio/minio:RELEASE.2026-01-15T00-00-00Z
    command: server /data
    volumes:
      - minio-data:/data

volumes:
  pgdata:
  minio-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /mnt/big-disk/minio

Имена volumes в compose префиксуются именем проекта. Если проект называется etl (по имени папки), volume pgdata будет физически etl_pgdata. Это видно в docker volume ls.


Попробуй сам

# 1. Полный round-trip: volume -> данные -> backup -> restore.
docker volume create demo-data
docker run --rm -v demo-data:/d alpine sh -c \
  'for i in $(seq 1 10); do echo "line $i" > /d/file-$i.txt; done; ls /d'

# 10 файлов в volume. Сделаем бэкап.
mkdir -p ./demo-backups
docker run --rm \
  -v demo-data:/source:ro \
  -v $(pwd)/demo-backups:/backup \
  alpine tar czf /backup/demo.tar.gz -C /source .

ls -la ./demo-backups
# demo.tar.gz весит ~500 байт.

# Уничтожим оригинал.
docker volume rm demo-data
docker volume ls | grep demo-data
# (пусто)

# Restore в новый volume.
docker volume create demo-data-restored
docker run --rm \
  -v demo-data-restored:/target \
  -v $(pwd)/demo-backups:/backup \
  alpine tar xzf /backup/demo.tar.gz -C /target

docker run --rm -v demo-data-restored:/d alpine ls /d
# Те же 10 файлов.

# Cleanup.
docker volume rm demo-data-restored
rm -rf ./demo-backups

# 2. Inspect и labels.
docker volume create --label team=etl --label tier=db etl-pgdata
docker volume inspect etl-pgdata
# Видишь labels в выводе.

docker volume ls --filter label=team=etl
# Только volumes с этим лейблом.

docker volume rm etl-pgdata
TIP

Production-практика: помечай volumes labels (team=, env=, app=). Это позволяет фильтровать в docker volume ls --filter и делать селективный prune --filter. В compose: volumes: pgdata: { labels: { team: etl } }.

В следующем уроке — реальный пример с Postgres: что произойдёт при первом запуске, как мигрировать с major-версии на следующую.


Проверка знанийKnowledge check
Команда docker run --rm -v src:/from -v $(pwd):/to alpine tar czf /to/backup.tar.gz -C /from . — что именно она делает и почему именно так выглядит стандартный паттерн бэкапа named volume?
ОтветAnswer
Команда делает бэкап named volume "src" в host-файл $(pwd)/backup.tar.gz. Механика: запускается одноразовый alpine-контейнер (--rm удалится после), к нему примонтированы два mount'а — named volume src в /from и bind host-папка $(pwd) в /to. Внутри контейнера tar упаковывает содержимое /from в архив, который лежит на /to и из-за bind-mount материализуется как файл на хосте. Этот паттерн стандартный потому, что: (1) named volume напрямую с хоста доступен только через VM, нет нативного 'docker volume cp'; (2) нужно прокидывать одновременно volume (источник) и host path (приёмник); (3) alpine + tar — минимальные накладные расходы, образ весит ~5 МБ. Для рестора — то же самое наоборот: монтируем новый volume в /target и host-папку с архивом в /backup, tar xzf разворачивает обратно.

Проверьте понимание

Результат: 0 из 0
Прикладной
Вопрос 1 из 4. Команда docker run --rm -v src:/from -v $(pwd):/to alpine tar czf /to/backup.tar.gz -C /from . — что она делает и почему это стандартный паттерн?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 5