version: '3.8'
services:
db:
image: postgres:15-alpine
restart: always
environment:
POSTGRES_USER: dev_user
POSTGRES_PASSWORD: dev_password
POSTGRES_DB: my_app_db
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U dev_user -d my_app_db"]
interval: 5s
timeout: 5s
retries: 5
redis:
image: redis:7-alpine
restart: always
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
app:
build: .
ports:
- "3000:3000"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
environment:
DATABASE_URL: postgres://dev_user:dev_password@db:5432/my_app_db
REDIS_URL: redis://redis:6379
volumes:
pgdata:Sincer, m-am săturat să văd colegi care își instalează manual PostgreSQL sau Redis direct pe sistem. E rețeta perfectă pentru un dezastru vineri seara când trebuie să livrezi ceva și „la mine merge” nu mai e un răspuns valid. Am avut cazul unui proiect unde am pierdut aproape o zi întreagă doar pentru că un junior avea o versiune de Redis cu doi ani mai veche decât ce aveam noi pe serverul de staging. De atunci, regula mea e simplă: dacă are nevoie de un port, stă în Docker Compose.
Nu e vorba doar de izolare, ci de liniște mentală. Când ai un setup bine pus la punct, un docker-compose up -d te scapă de orice grijă. La un proiect recent cu vreo 12 microservicii, am calculat că am economisit cam 30% din timpul de onboarding pentru noii veniți doar prin simplul fapt că nu a mai trebuit să configureze manual nicio bază de date. Totul era acolo, gata de drum.
De ce un config „curat” contează?
Mulți aruncă trei imagini într-un fișier YAML și zic că e gata. Dar problema apare când Next.js încearcă să se conecteze la Postgres înainte ca baza de date să fie gata să primească conexiuni. Docker zice că respectivul container e „running”, dar procesul intern de Postgres încă face scanări de fișiere sau recovery. Aici intervine healthcheck-ul. Fără el, app-ul tău o să dea crash la pornire și o să tot dai restart manual ca un disperat.
Un alt aspect e persistența. Am pățit să uit să pun un volum extern pentru datele din Postgres și, după un docker-compose down, m-am trezit că toate datele de test s-au evaporat. E frustrant să pierzi 2 ore de populat tabele doar pentru că ai uitat o linie de configurare.
Trade-off-uri sincere: Docker nu e perfect
Trebuie să fim realiști. Docker pe macOS și Windows mănâncă resurse cu lingura mare. Dacă ai un laptop cu 8GB RAM, o să simți cum începe să decoleze ventilatorul imediat ce pornești containerele. Pe un MacBook mai vechi, am observat o scădere de performanță la build-urile de Next.js de aproape 40% dacă rulam totul în container versus local.
De aceea, eu prefer o abordare hibridă pentru dev-ul activ: țin baza de date și Redis în Docker, dar rulez npm run dev direct pe mașina mea. E mult mai rapid, hot-reload-ul e instant și nu mă lupt cu permisiunile de fișiere mapate între host și container.
Configurația care nu te lasă la greu
În exemplul de mai jos, am pus accent pe sănătatea serviciilor. Folosim depends_on cu condiția service_healthy. Asta îi spune lui Docker: „Nu porni aplicația până când Postgres nu confirmă că e gata să primească query-uri”. E diferența dintre un workflow fluid și unul plin de erori de conexiune.
De asemenea, folosesc întotdeauna versiuni specifice pentru imagini. Nu puneți niciodată postgres:latest. Dacă peste 6 luni echipa de la Postgres scoate o versiune nouă care schimbă formatul de stocare, Docker o să o tragă automat și s-ar putea să te trezești cu baza de date coruptă local. Am pățit asta pe un proiect cu 8k useri în baza de date locală de test și nu a fost deloc amuzant să fac recovery manual.
La final, nu uita de .dockerignore. Dacă trimiți tot folderul node_modules în contextul de build al Docker, o să aștepți o veșnicie să se pornească totul. Ignoră-l și lasă Docker să-și instaleze singur dependențele în interiorul containerului dacă alegi să rulezi și app-ul acolo.
Voi cum procedați? Preferați să țineți totul „la cutie” în Docker sau rulați frontend-ul local pentru viteză maximă?