# Production deployment. # # Differences to compose.yaml that matter operationally: # - runs compiled output (node dist/, next start) instead of watch mode # - no source bind mounts and no file watchers, so an idle stack costs ~0% CPU # - healthchecks hit the cheap /health JSON endpoint, not a rendered page # - every service has a hard memory limit and may not spill into host swap # - the Express API is reachable only inside the compose network # # Usage: # docker compose -f compose.prod.yaml up --build --detach name: leistungsbilanz x-service-defaults: &service-defaults init: true restart: unless-stopped stop_grace_period: 20s logging: driver: json-file options: max-size: "20m" max-file: "10" services: api: <<: *service-defaults build: context: . target: prod args: # Baked into the Next.js rewrite manifest; see the build stage in the # Dockerfile. Must match the API service address in this network. API_INTERNAL_URL: http://api:3000 command: - sh - -c - node scripts/run-migrations.js && exec node dist/server/index.js environment: NODE_ENV: production PORT: "3000" LOG_LEVEL: "${LOG_LEVEL:-info}" # Not published on the host: the API has no authentication and is reached # through the Next.js rewrite in the web service. expose: - "3000" mem_limit: 512m memswap_limit: 512m volumes: - leistungsbilanz-data:/app/data healthcheck: test: - CMD - node - -e - fetch('http://127.0.0.1:3000/health').then(response=>process.exit(response.ok?0:1)).catch(()=>process.exit(1)) interval: 30s timeout: 5s retries: 3 start_period: 30s web: <<: *service-defaults build: context: . target: prod args: # Baked into the Next.js rewrite manifest; see the build stage in the # Dockerfile. Must match the API service address in this network. API_INTERNAL_URL: http://api:3000 command: - node_modules/.bin/next - start - -p - "3001" - --hostname - 0.0.0.0 environment: NODE_ENV: production API_INTERNAL_URL: http://api:3000 LOG_LEVEL: "${LOG_LEVEL:-info}" depends_on: api: condition: service_healthy ports: - "3090:3001" mem_limit: 1g memswap_limit: 1g healthcheck: # /health is rewritten to the API, so this verifies the web process and # its API connectivity for the cost of one JSON response. test: - CMD - node - -e - fetch('http://127.0.0.1:3001/health').then(response=>process.exit(response.ok?0:1)).catch(()=>process.exit(1)) interval: 30s timeout: 5s retries: 3 start_period: 30s volumes: leistungsbilanz-data: