# ============================================================ # INSIGHT MVP - Docker Compose (Basis-Services) # ============================================================ # Startet alle Kerndienste der INSIGHT-Plattform. # Observability-Stack separat: docker-compose.observability.yml # # Nutzung: # docker compose up -d # docker compose logs -f core # docker compose ps # ============================================================ networks: insight-web: driver: bridge name: insight-web insight-db: driver: bridge name: insight-db internal: true insight-cache: driver: bridge name: insight-cache internal: true volumes: postgres-data: name: insight-postgres-data redis-data: name: insight-redis-data step-ca-data: name: insight-step-ca-data traefik-certs: name: insight-traefik-certs services: # -------------------------------------------------------- # Traefik - API Gateway / Reverse Proxy # -------------------------------------------------------- traefik: image: traefik:3 container_name: insight-traefik restart: unless-stopped command: # API & Dashboard - "--api.dashboard=true" - "--api.insecure=true" # Entrypoints (nur HTTP fuer Alpha/Dev mit IP-Zugang) - "--entrypoints.web.address=:80" # Docker Provider - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--providers.docker.network=insight-web" # File Provider (fuer dynamische Konfiguration) - "--providers.file.directory=/etc/traefik/dynamic" - "--providers.file.watch=true" # Logging - "--log.level=INFO" - "--accesslog=true" - "--accesslog.format=json" # Metrics fuer Prometheus - "--metrics.prometheus=true" - "--metrics.prometheus.entryPoint=metrics" - "--entrypoints.metrics.address=:8082" ports: - "80:80" - "8080:8080" # Dashboard (nur intern) volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./config/traefik/dynamic:/etc/traefik/dynamic:ro - traefik-certs:/certs networks: - insight-web labels: - "traefik.enable=true" # Dashboard Route (nur intern, via Port 8080) - "traefik.http.routers.dashboard.rule=Host(`172.20.10.59`) && PathPrefix(`/dashboard`)" - "traefik.http.routers.dashboard.service=api@internal" - "traefik.http.routers.dashboard.entrypoints=web" healthcheck: test: ["CMD", "traefik", "healthcheck"] interval: 30s timeout: 5s retries: 3 # -------------------------------------------------------- # PostgreSQL - Datenbank # -------------------------------------------------------- postgres: image: postgres:16-alpine container_name: insight-postgres restart: unless-stopped environment: POSTGRES_USER: ${DB_USER:-insight} POSTGRES_PASSWORD: ${DB_PASSWORD:?DB_PASSWORD muss gesetzt sein} POSTGRES_DB: ${DB_NAME:-platform_core} # Performance-Tuning fuer 8GB RAM VM POSTGRES_INITDB_ARGS: "--data-checksums" volumes: - postgres-data:/var/lib/postgresql/data - ./config/postgres/init:/docker-entrypoint-initdb.d:ro networks: - insight-db healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DB_USER:-insight} -d ${DB_NAME:-platform_core}"] interval: 10s timeout: 5s retries: 5 start_period: 30s # Performance-Tuning via Command command: - "postgres" - "-c" - "shared_buffers=1GB" - "-c" - "effective_cache_size=4GB" - "-c" - "work_mem=16MB" - "-c" - "maintenance_work_mem=256MB" - "-c" - "max_connections=200" - "-c" - "log_min_duration_statement=500" - "-c" - "log_statement=ddl" # -------------------------------------------------------- # PgBouncer - Connection Pooling # -------------------------------------------------------- pgbouncer: image: edoburu/pgbouncer:latest container_name: insight-pgbouncer restart: unless-stopped environment: DATABASE_URL: "postgres://${DB_USER:-insight}:${DB_PASSWORD}@postgres:5432/${DB_NAME:-platform_core}" POOL_MODE: transaction MAX_CLIENT_CONN: 500 DEFAULT_POOL_SIZE: 25 MIN_POOL_SIZE: 5 RESERVE_POOL_SIZE: 5 SERVER_RESET_QUERY: "DISCARD ALL" SERVER_CHECK_DELAY: 30 SERVER_CHECK_QUERY: "SELECT 1" AUTH_TYPE: scram-sha-256 networks: - insight-db depends_on: postgres: condition: service_healthy healthcheck: test: ["CMD-SHELL", "pg_isready -h 127.0.0.1 -p 6432"] interval: 10s timeout: 5s retries: 3 # -------------------------------------------------------- # Redis - Cache, Sessions, Event Bus # -------------------------------------------------------- redis: image: redis:7-alpine container_name: insight-redis restart: unless-stopped command: > redis-server --requirepass ${REDIS_PASSWORD:-} --maxmemory 512mb --maxmemory-policy allkeys-lru --appendonly yes --appendfsync everysec --save 60 1000 --save 300 100 volumes: - redis-data:/data networks: - insight-cache healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD:-}", "ping"] interval: 10s timeout: 5s retries: 3 # -------------------------------------------------------- # step-ca - Interne Certificate Authority (mTLS) # -------------------------------------------------------- step-ca: image: smallstep/step-ca:latest container_name: insight-step-ca restart: unless-stopped environment: DOCKER_STEPCA_INIT_NAME: "INSIGHT Internal CA" DOCKER_STEPCA_INIT_DNS_NAMES: "step-ca,localhost" DOCKER_STEPCA_INIT_REMOTE_MANAGEMENT: "true" DOCKER_STEPCA_INIT_ACME: "true" volumes: - step-ca-data:/home/step networks: - insight-web - insight-db - insight-cache healthcheck: test: ["CMD", "step", "ca", "health"] interval: 30s timeout: 10s retries: 3 start_period: 30s # -------------------------------------------------------- # Core-Service - NestJS Backend # -------------------------------------------------------- core: build: context: ./packages/core-service dockerfile: Dockerfile target: development container_name: insight-core restart: unless-stopped environment: NODE_ENV: ${NODE_ENV:-development} APP_PORT: ${APP_PORT:-3000} APP_URL: ${APP_URL:-http://172.20.10.59} FRONTEND_URL: ${FRONTEND_URL:-http://172.20.10.59} LOG_LEVEL: ${LOG_LEVEL:-info} # Database (via PgBouncer) DATABASE_URL: "postgresql://${DB_USER:-insight}:${DB_PASSWORD}@pgbouncer:6432/${DB_NAME:-platform_core}" # Database (direkt fuer Migrations) DATABASE_URL_DIRECT: "postgresql://${DB_USER:-insight}:${DB_PASSWORD}@postgres:5432/${DB_NAME:-platform_core}" # Redis REDIS_HOST: redis REDIS_PORT: 6379 REDIS_PASSWORD: ${REDIS_PASSWORD:-} # JWT JWT_PRIVATE_KEY_PATH: ${JWT_PRIVATE_KEY_PATH:-/app/keys/jwt-private.pem} JWT_PUBLIC_KEY_PATH: ${JWT_PUBLIC_KEY_PATH:-/app/keys/jwt-public.pem} JWT_ACCESS_TOKEN_EXPIRY: ${JWT_ACCESS_TOKEN_EXPIRY:-15m} JWT_REFRESH_TOKEN_EXPIRY: ${JWT_REFRESH_TOKEN_EXPIRY:-7d} JWT_ISSUER: ${JWT_ISSUER:-insight-platform} # Bcrypt BCRYPT_COST: ${BCRYPT_COST:-12} # CORS CORS_ORIGINS: ${CORS_ORIGINS:-http://172.20.10.59} # Rate Limiting THROTTLE_TTL: ${THROTTLE_TTL:-60000} THROTTLE_LIMIT: ${THROTTLE_LIMIT:-200} volumes: - ./keys:/app/keys:ro networks: - insight-web - insight-db - insight-cache depends_on: pgbouncer: condition: service_healthy redis: condition: service_healthy labels: - "traefik.enable=true" # API Routing - "traefik.http.routers.core-api.rule=Host(`172.20.10.59`) && PathPrefix(`/api`)" - "traefik.http.routers.core-api.entrypoints=web" - "traefik.http.routers.core-api.service=core-api" - "traefik.http.services.core-api.loadbalancer.server.port=3000" # Health-Endpunkt (ohne Auth) - "traefik.http.routers.core-health.rule=Host(`172.20.10.59`) && Path(`/health`)" - "traefik.http.routers.core-health.entrypoints=web" - "traefik.http.routers.core-health.service=core-api" # Rate Limiting Middleware - "traefik.http.middlewares.api-ratelimit.ratelimit.average=100" - "traefik.http.middlewares.api-ratelimit.ratelimit.burst=50" - "traefik.http.routers.core-api.middlewares=api-ratelimit" healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"] interval: 15s timeout: 5s retries: 3 start_period: 30s # -------------------------------------------------------- # Frontend - React App (via Nginx) # -------------------------------------------------------- frontend: build: context: ./packages/frontend dockerfile: Dockerfile target: development container_name: insight-frontend restart: unless-stopped networks: - insight-web labels: - "traefik.enable=true" # Frontend Routing (Catch-All nach API) - "traefik.http.routers.frontend.rule=Host(`172.20.10.59`)" - "traefik.http.routers.frontend.entrypoints=web" - "traefik.http.routers.frontend.service=frontend" - "traefik.http.routers.frontend.priority=1" - "traefik.http.services.frontend.loadbalancer.server.port=8080" healthcheck: test: ["CMD-SHELL", "curl -f http://localhost:8080/ || exit 1"] interval: 30s timeout: 5s retries: 3