Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке Docker volume і навіщо він потрібен?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Docker volume** це Docker-managed персистентне сховище, що живе поза writable-шаром будь-якого container. Container можуть приходити і йти; volume і його дані лишаються. ```bash $ docker volume create pgdata $ docker run -d --name db -v pgdata:/var/lib/postgresql/data postgres:16 $ docker rm -f db # дані ще на диску у pgdata $ docker run -d --name db2 -v pgdata:/var/lib/postgresql/data postgres:16 # новий container, ті самі дані ``` **Головне:** все, що пишеш у writable-шар, помирає з container. Все, що пишеш у volume mount-шлях, лишається. Volume для баз, аплоадів, логів, будь-якого стану, який варто зберегти.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Docker volume** це стандартний спосіб тримати дані живими через рестарти і ребілди container. Container задумано як замінні; volume це частина, що *не* замінна. ## Теорія ### TL;DR - Volume це **named, Docker-managed директорія** поза файловою системою будь-якого container. - Container A пише у `/data` (змонтовано з volume `pgdata`); ти робиш `docker rm` A; створюєш 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. ### Швидкий приклад ```bash # Створимо 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 ```bash 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` ```bash # Коротка форма -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-шар** ```bash # НЕПРАВИЛЬНО: записи йдуть у 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** ```bash $ 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 ```bash $ 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 ```yaml # 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: ``` ```bash $ 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 для стану.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.