| services: | |
| kafka: | |
| image: apache/kafka:3.9.0 | |
| ports: | |
| - "9092:9092" | |
| environment: | |
| KAFKA_NODE_ID: "1" | |
| KAFKA_PROCESS_ROLES: "broker,controller" | |
| KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093" | |
| KAFKA_LISTENERS: "PLAINTEXT://:9092,CONTROLLER://:9093" | |
| KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092" | |
| KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: "CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT" | |
| KAFKA_CONTROLLER_LISTENER_NAMES: "CONTROLLER" | |
| KAFKA_INTER_BROKER_LISTENER_NAME: "PLAINTEXT" | |
| CLUSTER_ID: "MkU3OEVBNTcwNTJENDM2Qk" | |
| KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" | |
| KAFKA_NUM_PARTITIONS: "3" | |
| healthcheck: | |
| test: ["CMD-SHELL", "/opt/kafka/bin/kafka-topics.sh --bootstrap-server localhost:9092 --list"] | |
| interval: 10s | |
| timeout: 5s | |
| retries: 15 | |
| deploy: | |
| resources: | |
| limits: | |
| memory: 1G | |
| mlflow: | |
| image: python:3.12-slim | |
| command: > | |
| bash -c "pip install mlflow>=2.13 --quiet --no-cache-dir && | |
| mlflow server --backend-store-uri file:///mlruns --default-artifact-root file:///mlruns --host 0.0.0.0 --port 5000" | |
| ports: | |
| - "5000:5000" | |
| volumes: | |
| - ./data/mlruns:/mlruns | |
| spark: | |
| build: ./services/spark-jobs | |
| command: > | |
| bash -c "until [ -f /data/ml-1m/ratings.dat ]; do echo 'Waiting for bootstrap data...'; sleep 5; done && python streaming.py" | |
| environment: | |
| SPARK_MASTER: "local[*]" | |
| REDIS_URL: "redis://redis:6379" | |
| POSTGRES_URL: "postgresql://recsys:recsys@postgres:5432/recsys" | |
| KAFKA_BOOTSTRAP_SERVERS: "kafka:9092" | |
| DATA_DIR: "/data" | |
| CHECKPOINT_DIR: "/tmp/spark-checkpoint" | |
| MLFLOW_TRACKING_URI: "http://mlflow:5000" | |
| PYTHONUNBUFFERED: "1" | |
| volumes: | |
| - ./data:/data | |
| - spark-checkpoint:/tmp/spark-checkpoint | |
| depends_on: | |
| kafka: { condition: service_healthy } | |
| redis: { condition: service_healthy } | |
| postgres: { condition: service_healthy } | |
| deploy: | |
| resources: | |
| limits: | |
| memory: 2G | |
| restart: on-failure | |
| event-simulator: | |
| build: ./services/event-simulator | |
| environment: | |
| KAFKA_BOOTSTRAP_SERVERS: "kafka:9092" | |
| DATA_DIR: "/data" | |
| EVENT_RATE: "5" | |
| volumes: | |
| - ./data:/data | |
| depends_on: | |
| kafka: { condition: service_healthy } | |
| restart: on-failure | |
| api: | |
| build: ./services/api | |
| ports: | |
| - "8000:8000" | |
| environment: | |
| REDIS_URL: "redis://redis:6379" | |
| POSTGRES_URL: "postgresql://recsys:recsys@postgres:5432/recsys" | |
| KAFKA_BOOTSTRAP_SERVERS: "kafka:9092" | |
| depends_on: | |
| redis: { condition: service_healthy } | |
| postgres: { condition: service_healthy } | |
| kafka: { condition: service_healthy } | |
| healthcheck: | |
| test: ["CMD-SHELL", "python3 -c \"import urllib.request; urllib.request.urlopen('http://localhost:8000/health')\""] | |
| interval: 10s | |
| timeout: 5s | |
| retries: 5 | |
| restart: on-failure | |
| redis: | |
| image: redis:7-alpine | |
| ports: | |
| - "6379:6379" | |
| command: redis-server --save 60 1 --appendonly yes | |
| volumes: | |
| - redis-data:/data | |
| healthcheck: | |
| test: ["CMD", "redis-cli", "ping"] | |
| interval: 5s | |
| timeout: 3s | |
| retries: 10 | |
| postgres: | |
| image: postgres:16-alpine | |
| environment: | |
| POSTGRES_USER: ${POSTGRES_USER:-recsys} | |
| POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-recsys} | |
| POSTGRES_DB: ${POSTGRES_DB:-recsys} | |
| ports: | |
| - "5432:5432" | |
| volumes: | |
| - postgres-data:/var/lib/postgresql/data | |
| - ./services/api/schema.sql:/docker-entrypoint-initdb.d/schema.sql | |
| healthcheck: | |
| test: ["CMD-SHELL", "pg_isready -U recsys"] | |
| interval: 5s | |
| timeout: 3s | |
| retries: 10 | |
| frontend: | |
| build: ./services/frontend | |
| ports: | |
| - "3000:80" | |
| depends_on: | |
| api: { condition: service_healthy } | |
| prometheus: | |
| image: prom/prometheus:v2.51.0 | |
| ports: | |
| - "9090:9090" | |
| volumes: | |
| - ./infra/prometheus.yml:/etc/prometheus/prometheus.yml:ro | |
| grafana: | |
| image: grafana/grafana:10.4.3 | |
| ports: | |
| - "3001:3000" | |
| environment: | |
| GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD:-admin} | |
| GF_AUTH_ANONYMOUS_ENABLED: "true" | |
| GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer | |
| volumes: | |
| - grafana-data:/var/lib/grafana | |
| - ./infra/grafana/datasources:/etc/grafana/provisioning/datasources:ro | |
| - ./infra/grafana/dashboards:/etc/grafana/provisioning/dashboards:ro | |
| volumes: | |
| postgres-data: | |
| grafana-data: | |
| spark-checkpoint: | |
| redis-data: | |