feat(01-01): Next.js app + Docker Compose stack with network segmentation
- Next.js 15 app with Tailwind CSS v4, standalone output for Docker - Root layout with de locale, page with Tessera placeholder - Multi-stage Dockerfile for web with monorepo root context - Docker Compose with 4 services: traefik, web, api, db - Three segregated networks: frontend-net, backend-net, data-net (internal) - Traefik v2.11 reverse proxy routing / to web, /api to api - API strip prefix middleware for clean routing - PostgreSQL 16-alpine with health checks and named volume - Fixed API Dockerfile for pnpm monorepo node_modules structure - Fixed Next.js standalone path for monorepo (apps/web/server.js) - Fixed Traefik Docker API version compatibility - Network segmentation: web NOT on data-net, api NOT on frontend-net
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
services:
|
||||
traefik:
|
||||
image: traefik:v2.11
|
||||
ports:
|
||||
- "80:80"
|
||||
command:
|
||||
- "--api.insecure=true"
|
||||
- "--providers.docker=true"
|
||||
- "--providers.docker.exposedbydefault=false"
|
||||
environment:
|
||||
DOCKER_API_VERSION: "1.40"
|
||||
networks:
|
||||
- frontend-net
|
||||
- backend-net
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/web/Dockerfile
|
||||
environment:
|
||||
HOSTNAME: "0.0.0.0"
|
||||
networks:
|
||||
- frontend-net
|
||||
- backend-net
|
||||
depends_on:
|
||||
api:
|
||||
condition: service_healthy
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.web.rule=PathPrefix(`/`)"
|
||||
- "traefik.http.services.web.loadbalancer.server.port=3000"
|
||||
- "traefik.http.routers.web.priority=1"
|
||||
- "traefik.docker.network=tessera-ctl_frontend-net"
|
||||
|
||||
api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/api/Dockerfile
|
||||
networks:
|
||||
- backend-net
|
||||
- data-net
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
environment:
|
||||
DATABASE_URL: ${DATABASE_URL:-postgresql://tessera:tessera_dev@db:5432/tessera}
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:3001/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
start_period: 10s
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.api.rule=PathPrefix(`/api`)"
|
||||
- "traefik.http.services.api.loadbalancer.server.port=3001"
|
||||
- "traefik.http.routers.api.priority=2"
|
||||
- "traefik.http.middlewares.api-strip.stripprefix.prefixes=/api"
|
||||
- "traefik.http.routers.api.middlewares=api-strip"
|
||||
- "traefik.docker.network=tessera-ctl_backend-net"
|
||||
|
||||
db:
|
||||
image: postgres:16-alpine
|
||||
networks:
|
||||
- data-net
|
||||
volumes:
|
||||
- pgdata:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_USER: tessera
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD:-tessera_dev}
|
||||
POSTGRES_DB: tessera
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U tessera"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 5
|
||||
|
||||
networks:
|
||||
frontend-net:
|
||||
driver: bridge
|
||||
backend-net:
|
||||
driver: bridge
|
||||
data-net:
|
||||
driver: bridge
|
||||
internal: true
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
Reference in New Issue
Block a user