Docker Compose – backup wolumenów bez zgadywania, gdzie są dane

Kontener można usunąć i odtworzyć w minutę. Problem zaczyna się wtedy, gdy razem z kontenerem znika baza danych, pliki użytkowników albo konfiguracja aplikacji. Przy Docker Compose trzeba jasno wiedzieć, co jest tylko obrazem, co jest kontenerem, a co jest danymi, które trzeba backupować.

Docker w dokumentacji podkreśla, że wolumeny są wygodne do backupu, odtwarzania i migracji. To prawda, ale sam fakt użycia wolumenu jeszcze nie oznacza, że backup istnieje. Wolumen tylko oddziela dane od cyklu życia kontenera. Kopię trzeba nadal zaplanować, wykonać i przetestować.

Poniżej praktyczny scenariusz dla administratora, który ma prosty stack w Docker Compose: aplikację, bazę danych i kilka wolumenów.

1. Najpierw sprawdź, gdzie są dane

Zacznij od katalogu z projektem:

cd /opt/aplikacja
docker compose ps
docker compose config

W pliku compose.yaml szukaj sekcji volumes. Przykład:

services:
  app:
    image: example/app:latest
    volumes:
      - app_data:/var/www/html/storage
  db:
    image: postgres:16
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  app_data:
  db_data:

W tym przykładzie dane są w dwóch nazwanych wolumenach: app_data i db_data. Kontenery możesz odtworzyć z obrazu, ale zawartość tych wolumenów jest już Twoją odpowiedzialnością.

Lista wolumenów:

docker volume ls
docker volume inspect app_data
docker volume inspect db_data

Uwaga: przy Compose rzeczywista nazwa wolumenu często dostaje prefiks projektu, np. aplikacja_db_data. Dlatego zawsze sprawdzaj docker volume ls, a nie zakładaj nazwy z pamięci.

2. Backup wolumenu przez kontener techniczny

Docker pokazuje w dokumentacji podejście z uruchomieniem osobnego kontenera, który montuje wolumen i zapisuje archiwum do katalogu na hoście. W praktyce wygląda to tak:

mkdir -p /backup/docker/aplikacja

docker run --rm \
  -v aplikacja_app_data:/data:ro \
  -v /backup/docker/aplikacja:/backup \
  alpine \
  tar -czf /backup/app_data-$(date +%F-%H%M).tar.gz -C /data .

Kilka ważnych szczegółów:

  • wolumen montuję jako :ro, czyli tylko do odczytu,
  • archiwum zapisuję poza Dockerem, w /backup/docker/aplikacja,
  • w archiwum nie zapisuję całej ścieżki /var/lib/docker/..., tylko zawartość wolumenu,
  • nazwa pliku zawiera datę i godzinę.

To jest dobre dla plików aplikacji, uploadów, konfiguracji i danych, które mogą być spójnie odczytane jako pliki.

3. Baza danych: nie zawsze wystarczy tar wolumenu

Jeżeli wolumen zawiera bazę danych, sam tar z działającego kontenera może nie dać spójnej kopii. Baza w tym czasie zapisuje dane, ma cache, transakcje i pliki pomocnicze. Dla PostgreSQL albo MySQL bezpieczniej robić logiczny dump.

Przykład PostgreSQL:

mkdir -p /backup/docker/aplikacja

docker compose exec -T db \
  pg_dump -U postgres nazwa_bazy \
  > /backup/docker/aplikacja/postgres-$(date +%F-%H%M).sql

Przykład MySQL/MariaDB:

docker compose exec -T db \
  mysqldump -u root -p nazwa_bazy \
  > /backup/docker/aplikacja/mysql-$(date +%F-%H%M).sql

Jeżeli baza ma dużo danych, rozważ kompresję:

docker compose exec -T db \
  pg_dump -U postgres nazwa_bazy \
  | gzip > /backup/docker/aplikacja/postgres-$(date +%F-%H%M).sql.gz

Najlepszy wariant dla prostego stacka: dump bazy plus backup wolumenów z plikami aplikacji.

4. Restore trzeba przetestować

Backup bez testu odtworzenia to tylko plik, który może działać albo nie. Test nie musi od razu dotyczyć produkcji. Możesz odtworzyć stack w katalogu testowym albo na osobnej maszynie.

Odtworzenie wolumenu z archiwum:

docker volume create restore_app_data

docker run --rm \
  -v restore_app_data:/data \
  -v /backup/docker/aplikacja:/backup \
  alpine \
  tar -xzf /backup/app_data-2026-06-20-1000.tar.gz -C /data

Potem podstawiasz wolumen w testowym compose.yaml i uruchamiasz usługę:

docker compose up -d
docker compose logs -f

Przy bazie danych odtwarzaj dump do pustej bazy. Dla PostgreSQL przykładowo:

cat /backup/docker/aplikacja/postgres-2026-06-20-1000.sql \
  | docker compose exec -T db psql -U postgres nazwa_bazy

Po odtworzeniu sprawdź aplikację normalnie: logowanie, lista rekordów, upload plików, działanie zadań w tle.

5. Nie backupuj tylko tego, co łatwo znaleźć

W stacku Compose często są też rzeczy poza wolumenami:

  • plik compose.yaml,
  • pliki .env,
  • konfiguracje reverse proxy,
  • certyfikaty,
  • katalogi bind mount,
  • skrypty startowe,
  • zadania cron albo systemd timers,
  • konfiguracja firewalla,
  • dokumentacja, jak uruchomić stack po awarii.

Minimum, które warto trzymać w kopii:

tar -czf /backup/docker/aplikacja/compose-config-$(date +%F-%H%M).tar.gz \
  compose.yaml .env nginx/ scripts/

Jeżeli w .env są hasła, pilnuj uprawnień do backupu. Docker w dokumentacji przypomina, żeby nie używać zmiennych środowiskowych do przekazywania wrażliwych danych, jeżeli można użyć secrets. W Compose sekrety trafiają do kontenera jako pliki w /run/secrets/..., a dostęp można ograniczać per usługa.

6. Prosty skrypt backupu

Przykład prostego skryptu dla aplikacji z wolumenem plików i bazą PostgreSQL:

#!/usr/bin/env bash
set -euo pipefail

PROJECT_DIR="/opt/aplikacja"
BACKUP_DIR="/backup/docker/aplikacja"
DATE="$(date +%F-%H%M)"

mkdir -p "$BACKUP_DIR"
cd "$PROJECT_DIR"

docker compose exec -T db \
  pg_dump -U postgres nazwa_bazy \
  | gzip > "$BACKUP_DIR/postgres-$DATE.sql.gz"

docker run --rm \
  -v aplikacja_app_data:/data:ro \
  -v "$BACKUP_DIR":/backup \
  alpine \
  tar -czf "/backup/app_data-$DATE.tar.gz" -C /data .

tar -czf "$BACKUP_DIR/compose-config-$DATE.tar.gz" compose.yaml .env

find "$BACKUP_DIR" -type f -mtime +14 -delete

Nadaj uprawnienia:

chmod 700 backup-docker-aplikacja.sh

I uruchamiaj z crona albo przez systemd timer. Przy ważnych systemach lepiej użyć systemd timer, bo łatwiej sprawdzić logi i status wykonania.

7. Na co uważać

Najczęstsze błędy:

  • backupowany jest kontener, ale nie wolumen z danymi,
  • robiony jest tar działającej bazy zamiast dumpa,
  • backup zostaje na tym samym dysku co Docker,
  • nikt nie testuje odtworzenia,
  • skrypt backupu usuwa stare kopie bez sprawdzenia, czy nowa kopia się udała,
  • plik .env z hasłami trafia do kopii dostępnej dla zbyt wielu osób,
  • nazwa wolumenu w skrypcie nie zgadza się z rzeczywistą nazwą Compose,
  • po migracji na inny serwer zapomniano o reverse proxy, DNS albo certyfikatach.

Szczególnie groźne jest przekonanie, że docker compose down niczego nie rusza. Samo down zwykle nie usuwa nazwanych wolumenów, ale down -v już tak. Na produkcji trzeba bardzo świadomie używać opcji, które kasują wolumeny.

8. Jak sprawdzić, czy backup ma sens

Po wykonaniu kopii sprawdź:

ls -lh /backup/docker/aplikacja
tar -tzf /backup/docker/aplikacja/app_data-YYYY-MM-DD-HHMM.tar.gz | head
gzip -t /backup/docker/aplikacja/postgres-YYYY-MM-DD-HHMM.sql.gz

Raz na jakiś czas zrób pełny test:

  1. Utwórz pustą maszynę albo katalog testowy.
  2. Skopiuj backup.
  3. Odtwórz wolumeny i bazę.
  4. Uruchom stack.
  5. Sprawdź aplikację z przeglądarki.
  6. Zapisz czas odtworzenia.

W firmie bardziej przydaje się informacja „odtworzenie trwa 35 minut i wymaga zmiany DNS” niż samo „backup jest”.

Podsumowanie

W Docker Compose najważniejsze dane zwykle siedzą w wolumenach, bazach danych i plikach konfiguracyjnych obok compose.yaml. Kontener można odtworzyć z obrazu, ale danych użytkowników i bazy nikt za nas nie odzyska.

Dobre minimum to: dump bazy, archiwum wolumenów, kopia konfiguracji Compose, kopia poza serwerem i regularny test restore. Dopiero wtedy można powiedzieć, że stack w Dockerze ma backup, a nie tylko katalog z przypadkowymi plikami.

Źródła

  • Docker volumes: https://docs.docker.com/engine/storage/volumes/
  • Docker Compose secrets: https://docs.docker.com/compose/how-tos/use-secrets/
  • Docker Compose environment variables: https://docs.docker.com/compose/how-tos/environment-variables/set-environment-variables/
☕ Postaw mi kawę