Що таке Docker volume і навіщо він потрібен?
Docker volume це стандартний спосіб тримати дані живими через рестарти і ребілди container. Container задумано як замінні; volume це частина, що не замінна.
Теорія
TL;DR
- Volume це named, Docker-managed директорія поза файловою системою будь-якого container.
- Container A пише у
/data(змонтовано з volumepgdata); ти робишdocker rmA; створюєш container B з тим самим mount; B бачить дані A. - Volume лежить під
/var/lib/docker/volumes/<name>/_dataна Linux. На Mac/Windows за Docker Desktop VM. - Створюється через
docker volume createабо неявно при першому посиланні черезdocker run -v. - Рекомендований спосіб обробки персистентного стану. Альтернатива (писати у writable-шар container) втрачає дані при видаленні container.
Швидкий приклад
# Створимо volume явно (або пропустимо і дамо docker run створити)
$ docker volume create pgdata
pgdata
# Запустимо базу, що зберігає файли у volume
$ docker run -d --name db \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=devpass \
postgres:16
# Вставимо дані
$ docker exec -it db psql -U postgres -c "CREATE TABLE users(id int);"
# Знищимо container, volume і його дані лишаються
$ docker rm -f db
# Запустимо новий container; старі дані ще там
$ docker run -d --name db2 \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=devpass \
postgres:16
$ docker exec db2 psql -U postgres -c "\\dt"
# таблиця users все ще у спискуЧотири docker rm не змогли стерти дані. Саме для цього volume.
Чому container без volume втрачають дані
Файлова система container це шари image (read-only) плюс тонкий writable-шар зверху через OverlayFS. Записи у writable-шар йдуть через copy-on-write у upperdir. Коли робиш docker rm, upperdir видаляється. Усе, що там було, зникло.
Volume mount перехоплює записи у конкретний шлях і направляє їх поза union FS у host-директорію, якою Docker керує незалежно. Writable-шар container ніколи не тримає ці дані; docker rm їх не дістає.
Команди життєвого циклу volume
docker volume create <name> # явне створення з опціями
docker volume ls # список всіх volume
docker volume inspect <name> # показати driver, mountpoint, labels
docker volume rm <name> # видалити volume (не має бути used)
docker volume prune # видалити всі unused volumeБільшість workflow пропускає volume create, бо docker run -v <name>:<path> авто-створює volume при першому використанні. Явне створення важливе, коли треба driver-специфічні опції (--driver, --driver-opt).
Синтаксис монтування: -v vs --mount
# Коротка форма -v (компактна, поширена у туторіалах)
docker run -v pgdata:/var/lib/postgresql/data postgres:16
# Розгорнута форма --mount (явна, рекомендована для проду)
docker run --mount type=volume,source=pgdata,target=/var/lib/postgresql/data postgres:16Обидві працюють. --mount більш розгорнута, але менш двозначна (немає «перша частина це host-шлях чи ім'я volume?»). Прод-скрипти і Compose-файли зазвичай беруть --mount.
Типові помилки
Класти стан у writable-шар
# НЕПРАВИЛЬНО: записи йдуть у writable-шар container; зникають при rm
$ docker run -d --name db postgres:16
$ docker rm -f db # бай, таблиці
# ПРАВИЛЬНО: записи йдуть у volume; переживають видалення container
$ docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16Перша форма виглядає, ніби працює (дані там, поки container крутиться) і тихо знищує дані при першому ж docker rm.
Забути, який шлях всередині container тримає стан
Кожен image документує свій data-шлях. Postgres використовує /var/lib/postgresql/data. Mongo використовує /data/db. Redis (з персистенцією) використовує /data. Змонтуй неправильний шлях, і змонтуєш порожню директорію, а реальний стан все одно піде у writable-шар.
Перевіряй doc image (або директиву VOLUME у його Dockerfile, що перелічує шляхи, які image очікує бути volume-mounted).
Видалити volume, який в use
$ docker volume rm pgdata
Error response from daemon: remove pgdata: volume is in useСпочатку зупини і видали container, потім видаляй. Або docker rm -v, щоб видалити container разом з його анонімними volume.
Монтування non-empty шляху container поверх volume на першому запуску
Коли монтуєш named volume у шлях container, що вже має файли (з image), Docker копіює ці image-файли у порожній volume при першому старті. Після цього volume стає source of truth; апдейти image не поширюються. Дивує перший раз, коли апгрейдиш image бази і дивуєшся, чому нові файли не з'явилися.
Реальне застосування
- Бази у проді: кожен Postgres, MySQL, Mongo, Redis container у проді використовує named volume для свого data-dir. Без винятків.
- Локальна розробка з Docker Compose: блок
volumes:нагоріcompose.yamlвизначає named volume; сервіси їх монтують. Зупиняй і піднімай стек скільки хочеш, дані зберігаються. - CI/CD тестові фікстури: test runner піднімає Postgres-container з named volume, проганяє міграції + seed один раз, потім перевикористовує volume між тестовими прогонами, щоб пропустити setup-час.
- Аплоади застосунку:
/app/uploadsзмонтовано у named volume для застосунку, що приймає user file uploads. Інакше кожен redeploy їх стирає.
Питання для поглиблення
Q: Що відбудеться, якщо я взагалі забуду флаг -v?
A: Усе, що container пише, іде у його writable-шар. Container працює нормально, поки крутиться. У момент docker rm весь цей стан зникає. Для ефемерних навантажень (CI білди, тести) це навмисно. Для баз або чогось важливого це data-loss баг.
Q: Де саме на моєму диску лежать файли volume?
A: На Linux: /var/lib/docker/volumes/<volume-name>/_data/. На macOS / Windows всередині Docker Desktop Linux VM (не видно прямо на host filesystem). Знайти шлях через docker volume inspect <name> --format '{{.Mountpoint}}'.
Q: Чи можуть два container поділяти volume?
A: Так. Змонтуй той самий volume у два container, і обидва бачать ті самі файли. Корисно для sidecar log shipper, shared cache або producer/consumer патернів. Конкурентні записи можуть один одного затирати; координуй на рівні застосунку.
Q: Що таке anonymous volume?
A: Volume, створений без імені (авто-згенерований UUID). Трапляється, коли Dockerfile має VOLUME /path без явного -v під час запуску. Легко загубити: docker volume ls -f dangling=true їх знаходить, docker volume prune видаляє. Краще named volume.
Q: (Senior) Коли б ти НЕ використав Docker volume?
A: Три кейси. (1) Для ефемерного стану (CI білди, single-test-run container) пропусти volume; дані задумано померти. (2) Для розробки, де хочеш host-side редагувати ті самі файли, бери bind mount замість volume. (3) Для стану, що вимагає конкретної файлової системи (high-IOPS NVMe, розподілена FS як NFS/Ceph) бери volume driver plugin або bind mount у конкретний filesystem mount.
Приклади
Postgres з персистентним volume
$ docker volume create pgdata
$ docker run -d --name pg \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=devpass \
-p 5432:5432 \
postgres:16
# Підключаємось, працюємо
$ psql -h localhost -U postgres
postgres=# CREATE DATABASE app;
# Container знищено; volume лишається
$ docker rm -f pg
# Перестворюємо; дані ще там
$ docker run -d --name pg \
-v pgdata:/var/lib/postgresql/data \
-e POSTGRES_PASSWORD=devpass \
-p 5432:5432 \
postgres:16
$ psql -h localhost -U postgres -c '\l' | grep app
app | postgres | UTF8 | ...База app пережила повне знищення container.
Приклад з Compose
# compose.yaml
services:
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: devpass
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7
volumes:
- redis-data:/data
volumes:
pgdata:
redis-data:$ docker compose up -d
# Postgres + Redis з персистентним станом.
$ docker compose down # container зникли
$ docker compose up -d # container повернулися; дані не зачеплені
$ docker compose down -v # -v ще й стирає volume (деструктивно!)docker compose down за замовчуванням лишає volume. Флаг -v їх видаляє, це kill switch для стану.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.
Коментарі
Ще немає коментарів