Ctrl K
ComunidadGuías…

deployment/production/docker-compose.production.yml

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
version: "3.8"

services:
  # API Service
  janua-api:
    image: janua/api:latest
    container_name: janua-api
    restart: unless-stopped
    environment:
      - ENVIRONMENT=production
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - JWT_SECRET_KEY=${JWT_SECRET_KEY}
      - SECRET_KEY=${SECRET_KEY}
      - SENDGRID_API_KEY=${SENDGRID_API_KEY}
      - SENTRY_DSN=${SENTRY_DSN}
      # Database SSL Configuration
      - DATABASE_SSL_MODE=${DATABASE_SSL_MODE:-require}
      - DATABASE_SSL_CA_FILE=/etc/ssl/certs/db-ca.crt
      # Email (Resend) - Centralized for all MADFAM apps
      - RESEND_API_KEY=${RESEND_API_KEY}
      # Internal API - Service-to-service communication for MADFAM apps
      - INTERNAL_API_KEY=${INTERNAL_API_KEY}
    volumes:
      # Mount database CA certificate for SSL verification
      - ./ssl/db/ca.crt:/etc/ssl/certs/db-ca.crt:ro
    ports:
      - "4100:4100"  # MADFAM standard: 4100 = Janua API
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:4100/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - janua-network
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
    deploy:
      resources:
        limits:
          cpus: "2.0"
          memory: 2G
        reservations:
          cpus: "1.0"
          memory: 1G

  # Database with SSL enabled
  postgres:
    image: postgres:15-alpine
    container_name: janua-postgres
    restart: unless-stopped
    environment:
      POSTGRES_DB: ${POSTGRES_DB:-janua}
      POSTGRES_USER: ${POSTGRES_USER:-janua}
      POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?set POSTGRES_PASSWORD in an untracked local env file}"
      POSTGRES_INITDB_ARGS: "--auth-host=scram-sha-256 --auth-local=scram-sha-256"
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./postgresql.conf:/etc/postgresql/postgresql.conf
      - ./pg_hba.conf:/etc/postgresql/pg_hba.conf
      # SSL certificates for encrypted connections
      - ./ssl/db/server.crt:/var/lib/postgresql/server.crt:ro
      - ./ssl/db/server.key:/var/lib/postgresql/server.key:ro
      - ./ssl/db/ca.crt:/var/lib/postgresql/ca.crt:ro
    command: >
      postgres
      -c config_file=/etc/postgresql/postgresql.conf
      -c ssl=on
      -c ssl_cert_file=/var/lib/postgresql/server.crt
      -c ssl_key_file=/var/lib/postgresql/server.key
      -c ssl_ca_file=/var/lib/postgresql/ca.crt
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "pg_isready -U ${POSTGRES_USER:-janua} -d ${POSTGRES_DB:-janua}",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 60s
    networks:
      - janua-network
    deploy:
      resources:
        limits:
          cpus: "1.5"
          memory: 1.5G
        reservations:
          cpus: "0.5"
          memory: 512M

  # Redis Cache
  redis:
    image: redis:7-alpine
    container_name: janua-redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD} --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru
    ports:
      - "6379:6379"
    volumes:
      - redis_data:/data
    healthcheck:
      test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 30s
    networks:
      - janua-network
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.25"
          memory: 256M

  # Nginx Load Balancer
  nginx:
    image: nginx:alpine
    container_name: janua-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx-ssl.conf:/etc/nginx/conf.d/default.conf
      - ./ssl/certs:/etc/ssl/certs
      - ./ssl/private:/etc/ssl/private
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - janua-api
      - janua-dashboard
      - janua-website
      - janua-docs
    networks:
      - janua-network
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://localhost/health",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 256M

  # Dashboard Frontend (app.janua.dev)
  janua-dashboard:
    image: janua/dashboard:latest
    container_name: janua-dashboard
    restart: unless-stopped
    environment:
      - NODE_ENV=production
      # INTERNAL_API_URL: Server-side API route calls (runtime, internal network)
      # Uses Docker network hostname for container-to-container communication
      - INTERNAL_API_URL=http://janua-api:4100
      # NEXT_PUBLIC_API_URL: Client-side calls (build-time, external URL)
      - NEXT_PUBLIC_API_URL=https://api.janua.dev
      - NEXT_PUBLIC_APP_URL=https://app.janua.dev
    ports:
      - "4101:3000"  # MADFAM standard: 4101 = Janua Dashboard
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://localhost:3000/health",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - janua-network

  # Public Website (janua.dev)
  janua-website:
    image: janua/website:latest
    container_name: janua-website
    restart: unless-stopped
    environment:
      - NODE_ENV=production
      - NEXT_PUBLIC_API_URL=https://api.janua.dev
      - NEXT_PUBLIC_APP_URL=https://app.janua.dev
    ports:
      - "4104:3000"  # MADFAM standard: 4104 = Janua Website
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://localhost:3000/health",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - janua-network

  # Documentation Site (docs.janua.dev)
  janua-docs:
    image: janua/docs:latest
    container_name: janua-docs
    restart: unless-stopped
    environment:
      - NODE_ENV=production
    ports:
      - "4103:3000"  # MADFAM standard: 4103 = Janua Docs
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://localhost:3000/health",
        ]
      interval: 30s
      timeout: 10s
      retries: 3
    networks:
      - janua-network

  # Monitoring Stack
  prometheus:
    image: prom/prometheus:v2.45.0
    container_name: janua-prometheus
    restart: unless-stopped
    ports:
      - "9090:9090"
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml
      - ./monitoring/rules:/etc/prometheus/rules
      - prometheus_data:/prometheus
    command:
      - "--config.file=/etc/prometheus/prometheus.yml"
      - "--storage.tsdb.path=/prometheus"
      - "--web.console.libraries=/etc/prometheus/console_libraries"
      - "--web.console.templates=/etc/prometheus/consoles"
      - "--storage.tsdb.retention.time=30d"
      - "--web.enable-lifecycle"
    networks:
      - janua-network
    healthcheck:
      test:
        [
          "CMD",
          "wget",
          "--no-verbose",
          "--tries=1",
          "--spider",
          "http://localhost:9090/-/healthy",
        ]
      interval: 30s
      timeout: 10s
      retries: 3

  grafana:
    image: grafana/grafana:10.0.0
    container_name: janua-grafana
    restart: unless-stopped
    ports:
      - "3003:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_INSTALL_PLUGINS=grafana-piechart-panel
    volumes:
      - grafana_data:/var/lib/grafana
      - ./monitoring/grafana-dashboard.json:/etc/grafana/provisioning/dashboards/janua.json
    networks:
      - janua-network
    healthcheck:
      test:
        [
          "CMD-SHELL",
          "wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1",
        ]
      interval: 30s
      timeout: 10s
      retries: 3

  # PostgreSQL Exporter for Prometheus
  postgres-exporter:
    image: prometheuscommunity/postgres-exporter
    container_name: janua-postgres-exporter
    restart: unless-stopped
    ports:
      - "9187:9187"
    environment:
      # SSL enabled: verify-full requires CA cert, require just needs encryption
      DATA_SOURCE_NAME: "postgresql://${POSTGRES_USER:-janua}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-janua}?sslmode=require"
    volumes:
      # Mount CA certificate for SSL verification (optional, for sslmode=verify-full)
      - ./ssl/db/ca.crt:/etc/ssl/certs/ca.crt:ro
    depends_on:
      - postgres
    networks:
      - janua-network

  # Redis Exporter for Prometheus
  redis-exporter:
    image: oliver006/redis_exporter
    container_name: janua-redis-exporter
    restart: unless-stopped
    ports:
      - "9121:9121"
    environment:
      - REDIS_ADDR=redis://redis:6379
      - REDIS_PASSWORD=${REDIS_PASSWORD}
    depends_on:
      - redis
    networks:
      - janua-network

  # Node Exporter for System Metrics
  node-exporter:
    image: prom/node-exporter:v1.6.0
    container_name: janua-node-exporter
    restart: unless-stopped
    ports:
      - "9100:9100"
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - "--path.procfs=/host/proc"
      - "--path.rootfs=/rootfs"
      - "--path.sysfs=/host/sys"
      - "--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)"
    networks:
      - janua-network

  # ============================================
  # Automated PostgreSQL Backup Service
  # ============================================
  # Runs daily backups at 2 AM UTC with 30-day retention
  # Backups are stored locally and can be synced to S3/GCS
  postgres-backup:
    image: prodrigestivill/postgres-backup-local:15
    container_name: janua-postgres-backup
    restart: unless-stopped
    environment:
      - POSTGRES_HOST=postgres
      - POSTGRES_DB=${POSTGRES_DB:-janua}
      - POSTGRES_USER=${POSTGRES_USER:-janua}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_EXTRA_OPTS=--blobs --format=custom --compress=9
      # Schedule: Daily at 2:00 AM UTC
      - SCHEDULE=0 2 * * *
      # Keep 30 days of daily backups
      - BACKUP_KEEP_DAYS=30
      # Keep 4 weekly backups (Sundays)
      - BACKUP_KEEP_WEEKS=4
      # Keep 6 monthly backups (1st of month)
      - BACKUP_KEEP_MONTHS=6
      # Naming convention
      - BACKUP_SUFFIX=.sql.gz
      # Health check interval
      - HEALTHCHECK_PORT=8080
      # Optional: SSL mode for backup connection
      - POSTGRES_SSL_MODE=require
    volumes:
      - postgres_backups:/backups
      # Mount CA certificate for SSL verification
      - ./ssl/db/ca.crt:/etc/ssl/certs/ca.crt:ro
    depends_on:
      postgres:
        condition: service_healthy
    networks:
      - janua-network
    healthcheck:
      test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/"]
      interval: 60s
      timeout: 10s
      retries: 3
    deploy:
      resources:
        limits:
          cpus: "0.5"
          memory: 512M
        reservations:
          cpus: "0.1"
          memory: 128M
    labels:
      - "com.janua.description=Automated PostgreSQL backup service"
      - "com.janua.backup.schedule=Daily at 2:00 AM UTC"
      - "com.janua.backup.retention=30 days daily, 4 weekly, 6 monthly"

networks:
  janua-network:
    driver: bridge
    ipam:
      driver: default
      config:
        - subnet: 172.20.0.0/16

volumes:
  postgres_data:
    driver: local
  postgres_backups:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /var/backups/janua/postgres
  redis_data:
    driver: local
  prometheus_data:
    driver: local
  grafana_data:
    driver: local