File size: 4,564 Bytes
ac01a7a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
version: "3.9"

# Full local development stack
# Start everything:  docker-compose up -d
# View logs:         docker-compose logs -f inference-api
# Tear down:         docker-compose down -v

services:

  # ── Postgres ────────────────────────────────────────────────────────────────
  postgres:
    image: postgres:15-alpine
    environment:
      POSTGRES_DB:       flights
      POSTGRES_USER:     admin
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-localpassword}
    ports: ["5432:5432"]
    volumes: [postgres_data:/var/lib/postgresql/data]
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U admin -d flights"]
      interval: 10s
      timeout: 5s
      retries: 5

  # ── MLflow tracking server ───────────────────────────────────────────────────
  mlflow:
    image: python:3.11-slim
    depends_on:
      postgres: { condition: service_healthy }
    command: >
      sh -c "pip install -q mlflow psycopg2-binary boto3 &&
             mlflow server
               --host 0.0.0.0
               --port 5000
               --backend-store-uri postgresql://admin:${POSTGRES_PASSWORD:-localpassword}@postgres:5432/flights
               --default-artifact-root /mlruns"
    ports: ["5000:5000"]
    volumes: [mlruns:/mlruns]
    environment:
      MLFLOW_TRACKING_URI: http://localhost:5000

  # ── Airflow (single-container quickstart) ────────────────────────────────────
  airflow:
    image: apache/airflow:2.9.1-python3.11
    depends_on:
      postgres: { condition: service_healthy }
    environment:
      AIRFLOW__CORE__EXECUTOR:                LocalExecutor
      AIRFLOW__DATABASE__SQL_ALCHEMY_CONN:    postgresql+psycopg2://admin:${POSTGRES_PASSWORD:-localpassword}@postgres:5432/flights
      AIRFLOW__CORE__FERNET_KEY:              ${AIRFLOW_FERNET_KEY:-}
      AIRFLOW__WEBSERVER__SECRET_KEY:         ${AIRFLOW_SECRET_KEY:-changeme}
      AIRFLOW__CORE__LOAD_EXAMPLES:           "false"
      MLFLOW_TRACKING_URI:                    http://mlflow:5000
    ports: ["8080:8080"]
    volumes:
      - ./dags:/opt/airflow/dags
      - ./etl:/opt/airflow/etl
      - ./ml:/opt/airflow/ml
      - ./mlops:/opt/airflow/mlops
      - ./data:/opt/airflow/data
    command: >
      bash -c "airflow db init &&
               airflow users create --username admin --password admin
                 --firstname Admin --lastname User --role Admin --email admin@example.com &&
               airflow webserver & airflow scheduler"

  # ── Inference API ────────────────────────────────────────────────────────────
  inference-api:
    build: .
    depends_on:
      postgres: { condition: service_healthy }
    ports: ["8000:8000"]
    environment:
      DATABASE_URL:        postgresql://admin:${POSTGRES_PASSWORD:-localpassword}@postgres:5432/flights
      MLFLOW_TRACKING_URI: http://mlflow:5000
      MODEL_VERSION:       local
    volumes:
      - ./models:/app/models      # mount trained models
      - ./data:/app/data
    healthcheck:
      test: ["CMD-SHELL", "curl -f http://localhost:8000/health || exit 1"]
      interval: 30s
      timeout: 10s
      retries: 3

  # ── Prometheus ───────────────────────────────────────────────────────────────
  prometheus:
    image: prom/prometheus:v2.51.0
    ports: ["9090:9090"]
    volumes:
      - ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - prometheus_data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.retention.time=15d'

  # ── Grafana ──────────────────────────────────────────────────────────────────
  grafana:
    image: grafana/grafana:10.4.0
    depends_on: [prometheus]
    ports: ["3000:3000"]
    environment:
      GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
    volumes:
      - grafana_data:/var/lib/grafana

volumes:
  postgres_data:
  mlruns:
  prometheus_data:
  grafana_data: