Docker volumes a zálohy: jak nepřijít o data v kontejnerech
Rozdíl mezi volume a bind mountem, kde Docker data fyzicky ukládá, záloha a obnova volume přes tar, konzistentní dump PostgreSQL a MySQL a automatizace cronem.
Kontejnery jsou dočasné – smažete je a vytvoříte znovu. Data ale dočasná být nesmí. Docker na to má volumes a bind mounty. A protože volume není záloha, ukážeme si také, jak data spolehlivě zálohovat a obnovit.
Tři způsoby ukládání dat
| Typ | Zápis | Kde data jsou | Kdy použít |
|---|---|---|---|
| Pojmenovaný volume | -v pgdata:/var/lib/postgresql/data |
spravuje Docker (/var/lib/docker/volumes/) |
databáze, data aplikací |
| Bind mount | -v /srv/app/uploads:/app/uploads |
konkrétní složka hostitele | konfigurace, nahrané soubory, vývoj |
| tmpfs | --tmpfs /tmp |
v RAM | dočasná data, nic se neukládá |
Bez žádné z těchto možností data zmizí při smazání kontejneru.
Práce s volumes
docker volume ls
docker volume inspect pgdata
docker volume rm pgdata # smaže data!
docker volume prune # smaže nepoužívané volumes
inspect ukáže Mountpoint, typicky /var/lib/docker/volumes/pgdata/_data. Do této složky sice jde nahlédnout jako root, ale přímo do ní nesahejte za běhu kontejneru.
V Compose se volume jmenuje s prefixem projektu: volume pgdata v projektu shop bude shop_pgdata.
Pozor na prune
docker system prune ve výchozím stavu volumes nemaže. docker system prune --volumes a docker volume prune ano – smažou volumes nepřipojené k žádnému kontejneru. Pokud jste mezitím udělali docker compose down, databázový volume je „nepoužívaný“. Před prune vždy zkontrolujte docker volume ls.
Bind mount: práva k souborům
U bind mountů musí uživatel v kontejneru mít práva k souborům na hostiteli. Pokud kontejner běží jako UID 1000:
sudo chown -R 1000:1000 /srv/app/uploads
Konfiguraci připojujte jen pro čtení:
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
Záloha databáze: dump, ne kopie souborů
Kopírovat soubory běžící databáze je riskantní – můžete zachytit nekonzistentní stav. Pro databáze použijte jejich nástroj na export.
PostgreSQL:
docker compose exec -T db pg_dump -U app -Fc app > backup_$(date +%F).dump
Volba -T vypne pseudo-terminál, jinak by se výstup mohl poškodit. -Fc je komprimovaný vlastní formát pro pg_restore.
Obnova:
docker compose exec -T db pg_restore -U app -d app --clean --if-exists < backup_2026-10-12.dump
MySQL / MariaDB:
docker compose exec -T db sh -c 'mysqldump -u root -p"$MYSQL_ROOT_PASSWORD" --single-transaction --databases app' | gzip > mysql_$(date +%F).sql.gz
U MariaDB 11 se klient jmenuje mariadb-dump. Obnova:
gunzip < mysql_2026-10-12.sql.gz | docker compose exec -T db sh -c 'mysql -u root -p"$MYSQL_ROOT_PASSWORD"'
Záloha libovolného volume přes tar
Pro data, která nejsou databáze (nahrané soubory, konfigurace aplikace), použijte pomocný kontejner:
docker run --rm \
-v appdata:/data:ro \
-v "$PWD":/backup \
alpine tar czf /backup/appdata_$(date +%F).tar.gz -C /data .
Obnova do (nového) volume:
docker volume create appdata
docker run --rm \
-v appdata:/data \
-v "$PWD":/backup \
alpine sh -c "cd /data && tar xzf /backup/appdata_2026-10-12.tar.gz"
Stejný postup slouží k přesunu volume na jiný server.
Pokud aplikace do volume během zálohy zapisuje, je bezpečnější ji na chvíli zastavit (docker compose stop web).
Automatizace cronem
Skript /usr/local/bin/backup-app.sh:
#!/usr/bin/env bash
set -euo pipefail
DEST=/var/backups/app
mkdir -p "$DEST"
cd /srv/app
docker compose exec -T db pg_dump -U app -Fc app > "$DEST/db_$(date +%F_%H%M).dump"
docker run --rm -v app_uploads:/data:ro -v "$DEST":/backup alpine \
tar czf "/backup/uploads_$(date +%F_%H%M).tar.gz" -C /data .
# smazat zálohy starší 14 dní
find "$DEST" -type f -mtime +14 -delete
sudo chmod +x /usr/local/bin/backup-app.sh
sudo crontab -e
# každou noc ve 3:15
15 3 * * * /usr/local/bin/backup-app.sh >> /var/log/backup-app.log 2>&1
Pravidlo 3-2-1
Záloha na stejném disku jako data vás neochrání před selháním serveru. Držte se pravidla: 3 kopie, 2 různá média, 1 mimo server. Pro odeslání mimo server se hodí rclone (S3, Backblaze B2, Google Drive…) nebo restic, který umí deduplikaci a šifrování:
restic -r sftp:[email protected]:/restic-repo backup /var/backups/app
Testujte obnovu
Záloha, ze které jste nikdy neobnovovali, je jen naděje. Jednou za čas obnovte dump do testovacího kontejneru:
docker run -d --name pgtest -e POSTGRES_PASSWORD=test postgres:16
docker exec -i pgtest createdb -U postgres app
docker exec -i pgtest pg_restore -U postgres -d app < db_2026-10-12_0315.dump
docker exec -it pgtest psql -U postgres app -c '\dt'
docker rm -f pgtest
Pokud chcete skript zálohy přizpůsobit svému serveru, ColdHost AI v režimu Server a DevOps ho s vámi upraví a na připojeném VPS můžete jednotlivé kroky spustit po schválení.