Docker и Docker Compose — професионално ръководство

Част 5: Docker Volumes & Persistent Data

По подразбиране данните в Docker контейнерите са временни (ephemeral). Тук разглеждам механизмите за съхранение на персистентни данни: Named Volumes, Bind Mounts, tmpfs, архивиране и добри практики в продукционна среда.

Приложенията са заменими, данните — НЕ. Контейнерът трябва да може да бъде разрушен и пресъздаден по всяко време, без това да застрашава базата данни, качените файлове или конфигурациите.

1. Проблемът с Ephemeral Storage

Всеки Docker контейнер използва слой за писане (writable layer) над неизменяемия си Image. Когато процесът вътре създава или модифицира файлове, те се записват именно в този слой.

Този подход има няколко сериозни недостатъка:

  • Загуба на данни: При изтриване на контейнера (docker rm), целият writable layer се заличава завинаги;
  • Производителност: Писането през Docker Storage Driver (Overlay2) е по-бавно от директния достъп до хост файловата система;
  • Трудна споделяемост: Данните са капсулирани и трудно достъпни за други контейнери или процеси на хоста.

2. Видове Storage в Docker

За да осигури персистентност и висока производителност, Docker предлага три основни типа за монтиране (mounts):

Volumes

Управляват се изцяло от Docker Engine (/var/lib/docker/volumes/). Най-добрият избор за production.

Bind Mounts

Монтират конкретен път от хост системата. Идеални за development и конфигурационни файлове.

tmpfs Mounts

Пазят се единствено в оперативната памет (RAM). За временни или чувствителни данни.

3. Docker Volumes (Named Volumes)

Volumes са за предпочитане при работа с бази данни и съхранение на оперативни данни на приложения в production.

3.1. Управление на Volumes чрез CLI

TERMINAL
# Създаване на нов volume
docker volume create db_data

# Преглед на наличните volumes
docker volume ls

# Детайлна информация за volume (път на хоста, driver и др.)
docker volume inspect db_data

# Премахване на volume
docker volume rm db_data

3.2. Монтиране на Volume в Container

Монтирането става чрез флага -v (съкратен) или --mount (по-подробен и препоръчителен при по-сложни конфигурации).

СИНТАКСИС -V
docker run -d \
  --name postgres_db \
  -v db_data:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:16-alpine
СИНТАКСИС --MOUNT (ПРЕПОРЪЧИТЕЛЕН)
docker run -d \
  --name postgres_db \
  --mount source=db_data,target=/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:16-alpine
Автоматично иницииране: Ако монтирате празен Named Volume към директория в контейнера, която вече съдържа файлове (напр. /etc/nginx), Docker автоматично копира съществуващото съдържание вътре във Volume-а при първоначалното стартиране.

4. Bind Mounts

Bind Mounts монтират съществуваща директория или файл от хост системата директно в контейнера.

ПРИМЕР ЗА BIND MOUNT
docker run -d \
  --name web_server \
  -p 80:80 \
  -v /srv/mywebsite:/usr/share/nginx/html:ro \
  nginx:alpine

В горния пример суфиксът :ro означава Read-Only. Контейнерът може да чете файловете, но няма право да ги променя или изтрива.

Забележка за Bind Mounts: За разлика от Volumes, при Bind Mounts Docker не инициира автоматично съдържанието. Ако хост директорията е празна, тя ще презапише съдържанието на целия целеви път в контейнера.

5. tmpfs Mounts

Когато не искате данни да се записват на диска (нито в контейнера, нито на хоста), използвате tmpfs. Данните се съхраняват в RAM паметта и се изтриват моментално при спиране на контейнера.

TERMINAL
docker run -d \
  --name secure_app \
  --tmpfs /tmp/secrets:rw,noexec,nosuid,size=64m \
  myapp:latest

6. Сравнителна таблица

Характеристика Docker Volumes Bind Mounts tmpfs Mounts
Местоположение Управлява се от Docker (/var/lib/docker/volumes/) Всеки произволен път на хост системата Системната оперативна памет (RAM)
Управление Чрез docker volume CLI / API Ръчно през хост файловата система Автоматично от ОС в RAM
Инициализация Копира началното съдържание от контейнера Презаписва съдържанието в контейнера Празно при стартиране
Основна употреба Бази данни, Production персистентност Source code при development, конфигурации Временна кеш памет, чувствителни ключове

7. Архивиране и възстановяване на Volumes

Тъй като Volumes се намират под контрола на Docker Engine, най-безопасният начин за правене на backup е чрез временен контейнер.

7.1. Backup на Volume

TERMINAL (BACKUP)
docker run --rm \
  -v db_data:/volume \
  -v $(pwd):/backup \
  alpine tar -czvf /backup/db_data_backup.tar.gz -C /volume .

Това създава архива db_data_backup.tar.gz в текущата работна директория на хоста.

7.2. Restore (Възстановяване) на Volume

TERMINAL (RESTORE)
# 1. Създаване на новия volume
docker volume create db_data_new

# 2. Разархивиране на данните вътре в него
docker run --rm \
  -v db_data_new:/volume \
  -v $(pwd):/backup \
  alpine sh -c "cd /volume && tar -xzvf /backup/db_data_backup.tar.gz"

8. Права за достъп (UID / GID) и Permissions

При монтиране на Bind Mounts често възникват проблеми с правата за писане. Процесът вътре в контейнера може да работи с даден UID (напр. 1000 или 999), който няма права да пише в директорията на хоста.

Правилно решение: Не задавайте chmod 777! Използвайте флага --user при стартиране или конфигурирайте потребителя правилно в Dockerfile / Compose.
TERMINAL
docker run -d \
  --user $(id -u):$(id -g) \
  -v $(pwd)/app:/app \
  node:18-alpine npm start

9. Почистване на неизползвани Volumes

Когато премахвате контейнери с docker rm, свързаните с тях Named Volumes не се изтриват автоматично. С времето те могат да заемат значително дисково пространство.

TERMINAL
# Преглед на неизползваните volumes
docker volume ls -q -f dangling=true

# Премахване на всички неизползвани volumes
docker volume prune