Docker Compose for Microservices — Base/Override Pattern, Traefik, and Per-Service DB Isolation
How I structure Docker Compose for real microservice projects — secrets, network isolation, and Traefik routing without the mess.
Most Docker Compose tutorials show a single service with a database. Microservice setups are messier. Here's the pattern I settled on after building Unirift's infrastructure from scratch.
Base/override pattern
docker-compose.yml defines the full service topology. docker-compose.override.yml adds local dev config — volume mounts, debug ports, hot reload. Production gets its own override. This keeps dev and prod in sync without duplication.
Per-service DB isolation
Each service gets its own Postgres database and user with minimal grants. The key step most tutorials skip: REVOKE ALL ON DATABASE from PUBLIC before granting targeted permissions. Without this, any service can read any database.
Traefik v3 routing
Traefik as the reverse proxy means each service declares its own routing rules via Docker labels. No central nginx config to maintain. HTTPS terminates at Traefik, internal services talk plain HTTP. Clean, maintainable, and easy to extend.