#!/usr/bin/env bash
set -e
CONTAINER_NAME="production_postgres"
DB_USER="app_user"
DB_NAME="app_prod"
BACKUP_DIR="/var/backups/postgres"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/db_dump_${DATE}.sql.gz"
# 1. Export curat direct din containerul care ruleaza
docker exec -t ${CONTAINER_NAME} pg_dump -U ${DB_USER} -d ${DB_NAME} -F c | gzip > "${BACKUP_FILE}"
# 2. Testam restore-ul intr-un container temporar
TEST_CONTAINER="pg_restore_test_${DATE}"
docker run --name ${TEST_CONTAINER} -e POSTGRES_PASSWORD=testpass -d postgres:15-alpine > /dev/null
sleep 5
# Restauram datele in containerul de test
gunzip -c "${BACKUP_FILE}" | docker exec -i ${TEST_CONTAINER} pg_restore -U postgres -d postgres --clean --if-exists > /dev/null 2>&1
# Verificam daca s-au populat tabelele
COUNT=$(docker exec -i ${TEST_CONTAINER} psql -U postgres -d postgres -t -c "SELECT count(*) FROM information_schema.tables;")
echo "Restore testat cu succes. Tabele gasite: ${COUNT}"
# Curatam containerul de test
docker rm -f ${TEST_CONTAINER} > /dev/nullAproape în fiecare lună văd pe cineva pe forum sau la consultanță care își plânge de milă fiindcă i s-a corupt baza de date după un restart de container. Problemă tipică: au pus PostgreSQL pe un bind mount pe un server de producție și s-au trezit cu permisiuni vraiște sau cu fișiere scrise parțial. Hai să lămurim odată pentru totdeauna cum gestionezi datele persistente în Docker și cum faci un backup pe care chiar te poți baza.
Bind mounts vs Named Volumes: trade-off-ul din producție
Bind mount înseamnă că mapăm un director direct de pe host (-v /var/data/postgres:/var/lib/postgresql/data). E visul oricărui developer când lucrează la frontend sau backend pentru că modifici fișierul pe laptop și se reflectă instant în container.
Dar în producție? În producție bind mount-ul e o capcană. În primul rând, te lovești de permisiuni UNIX. Containerul rulează adesea cu un UID intern (de exemplu 999 pentru Postgres), iar pe host acel folder aparține de root sau de userul tău de SSH. Când containerul încearcă să scrie, primești un minunat Permission denied. În al doilea rând, pe sisteme non-Linux sau pe VPS-uri cu sisteme de fișiere mai ciudate, performanța de I/O scade drastic.
Named volumes (-v pgdata:/var/lib/postgresql/data) sunt gestionate complet de Docker Engine. Se află izolate în /var/lib/docker/volumes/ și sunt optimizate direct pentru performanță. La un proiect recent de e-commerce cu vreo 8k useri activi pe zi, trecerea de la un bind mount lăsat din greșeală pe producție la un named volume a redus I/O Wait-ul serverului cu mai bine de 20%.
Trade-off-ul? Named volumes sunt un fel de „cutie neagră”. Nu poți pur și simplu să intri cu cd în folder și să editezi un fișier de configurare fără drepturi de root. Dar pentru o bază de date, exact asta îți dorești: izolare și stabilitate.
Cum faci backup corect (fără să oprești baza)
Cea mai mare greșeală pe care o văd este încercarea de a copia fișierele brute din volumul Docker în timp ce baza de date rulează. Dacă faci cp -r pe dosarul de date în timp ce Postgres scrie un WAL (Write-Ahead Log), backup-ul tău e compromis din start. Vei avea un snapshot inconsecvent și neutilizabil.
Varianta sănătoasă este să folosești utilitarul nativ al bazei de date (ex. pg_dump sau mysqldump) executat direct prin Docker. Baza gestionează tranzacțiile, iar tu primești un stream curat de date pe care îl arunci într-o arhivă pe host sau direct în S3.
Regula de aur: Restore-ul netestat NU este backup
Am văzut echipe care rulau un script de backup de 2 ani, mândre că fișierele .sql.gz apăreau zilnic pe disc. Când a căzut discul principal și au încercat să facă restore, au realizat că din cauza unui flag greșit din script, backup-ul conținea doar schema, fără niciun rând de date. Au pierdut 3 săptămâni de tranzacții.
Sistemul meu e simplu: la fiecare backup automatizat dintr-un cron job, pornesc un container izolat de test, restaurez arhiva, rulez o interogare simplă de validare și abia dacă asta trece cu succes marchez backup-ul ca valid.
Voi cum faceți backup-urile pe stack-urile voastre de Docker? Mergeți pe volume drivere dedicate sau rămâneți pe scripturi clasice de dump?