services:
db:
image: postgres:15-alpine
container_name: nextjs-db
environment:
POSTGRES_USER: ${DB_USER:-postgres}
POSTGRES_PASSWORD: ${DB_PASSWORD:-secret}
POSTGRES_DB: ${DB_NAME:-app_dev}
ports:
- "5432:5432"
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-postgres} -d ${DB_NAME:-app_dev}"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
container_name: nextjs-redis
ports:
- "6379:6379"
volumes:
- redisdata:/data
volumes:
pgdata:
redisdata:M-am săturat să văd tutoriale care îți aruncă un fișier Docker Compose de 200 de linii, plin de variabile de mediu hardcodate și flag-uri inutile. Astăzi îți arăt cum am configurat un mediu local curat cu PostgreSQL și Redis, pe care îl folosesc acum la un proiect cu vreo 12k utilizatori activi lunar. Treci de la "la mine pe mașină merge" la un singur docker compose up în mai puțin de 5 minute.
Problema cu setup-ul clasic și primul meu trade-off
La început, acum vreo 6-7 ani, instalam totul nativ pe macOS. Postgres prin Homebrew, Redis prin nu mai știu ce script, iar Next.js direct în Terminal. Chestia asta a mers o perioadă, până când am avut nevoie de versiuni diferite de Postgres pentru două proiecte în paralel. Atunci a început calvarul porturilor blocate și al conflictelor de versiuni.
Docker Compose rezolvă excelent izolarea asta, dar vine cu un cost real: consumul de resurse pe macOS și Windows prin VM-ul din spate. Pe un laptop mai vechi cu 8GB RAM, Docker-ul îți transformă calculatorul în radiator. Dacă ai măcar 16GB RAM, merită din plin trade-off-ul pentru liniștea mentală pe care ți-o oferă.
Structura curată și fișierul compose.yaml
Am trecut complet de la vechiul docker-compose.yml la noul standard compose.yaml. E o chestie minoră de naming introdusă în specificațiile recente, dar arată că îți ții config-ul actualizat.
Regula mea de aur pentru un config curat: fără secrete sau credențiale hardcodate. Folosim un fișier .env local pe care Compose îl citește automat. În exemplul de mai jos, am pus bazele pentru Postgres și Redis. Am separat volumele ca să nu pierdem datele la fiecare restart de container și, cel mai important, am adăugat un healthcheck robust pentru Postgres.
De ce healthcheck-ul este obligatoriu
Multe ghiduri de pe net folosesc doar simplul depends_on: - db. Este o mare greșeală pe care am plătit-o cu zeci de crash-uri inutile în consolă. depends_on doar îi spune Docker-ului să pornească containerul de bază de date, dar nu așteaptă ca serviciul Postgres să fie efectiv pregătit să accepte conexiuni. Next.js va încerca să se conecteze instant și va crăpa în primele 3 secunde.
Cu un healthcheck pe Postgres bazat pe pg_isready și setarea condition: service_healthy în aplicațiile dependente, pornești totul în ordinea corectă. Am economisit cel puțin 30% din timpul de debugging la onboarding-ul colegilor noi în echipă doar prin introducerea acestei verificări automate.
Alternativa hibridă: Trade-off-ul de performanță în Next.js
Să fim complet sinceri. Să rulezi Next.js în interiorul unui container Docker în timpul dezvoltării active (cu hot reload) e destul de lent pe medii non-Linux din cauza modului în care se face sincronizarea de volume (bind mounts). Fișierele modificate se propagă greu din calculatorul tău în container.
Ce fac eu în viața de zi cu zi? Pornesc doar bazele de date și serviciile auxiliare (Postgres, Redis) în Docker folosind Compose. Aplicația de Next.js o rulez direct pe mașina gazdă cu npm run dev, conectată la porturile 5432 și 6379 expuse de containere. Ai izolare perfectă pentru date și viteză maximă de execuție pentru frontend.
Voi cum procedați la proiectele voastre? Rulați totul cap-coadă în Docker sau preferați varianta asta hibridă pentru un workflow mai rapid?