version: '3.8' services: # ============================================================================= # PostgreSQL Database # ============================================================================= postgres: image: postgres:15-alpine container_name: churn_postgres environment: POSTGRES_USER: churn_user POSTGRES_PASSWORD: churn_password POSTGRES_DB: churn_db ports: - "5432:5432" volumes: - postgres_data:/var/lib/postgresql/data - ./postgres/init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ["CMD-SHELL", "pg_isready -U churn_user -d churn_db"] interval: 10s timeout: 5s retries: 5 networks: - churn_network # ============================================================================= # Zookeeper (required for Kafka) # ============================================================================= zookeeper: image: confluentinc/cp-zookeeper:7.5.0 container_name: churn_zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 ports: - "2181:2181" healthcheck: test: ["CMD", "nc", "-z", "localhost", "2181"] interval: 10s timeout: 5s retries: 5 networks: - churn_network # ============================================================================= # Kafka Message Broker # ============================================================================= kafka: image: confluentinc/cp-kafka:7.5.0 container_name: churn_kafka depends_on: zookeeper: condition: service_healthy ports: - "9092:9092" - "29092:29092" environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" healthcheck: test: ["CMD", "kafka-topics", "--bootstrap-server", "localhost:9092", "--list"] interval: 30s timeout: 10s retries: 5 networks: - churn_network # ============================================================================= # Kafka UI (optional, for debugging) # ============================================================================= kafka-ui: image: provectuslabs/kafka-ui:latest container_name: churn_kafka_ui depends_on: - kafka ports: - "8082:8080" environment: KAFKA_CLUSTERS_0_NAME: churn-cluster KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 KAFKA_CLUSTERS_0_ZOOKEEPER: zookeeper:2181 networks: - churn_network # ============================================================================= # ML Service (FastAPI) # ============================================================================= ml_service: build: context: ./ml_service dockerfile: Dockerfile container_name: churn_ml_service depends_on: postgres: condition: service_healthy kafka: condition: service_healthy ports: - "8000:8000" environment: DATABASE_URL: postgresql://churn_user:churn_password@postgres:5432/churn_db KAFKA_BOOTSTRAP_SERVERS: kafka:9092 MODEL_DIR: /app/models volumes: - model_data:/app/models healthcheck: test: ["CMD", "python", "-c", "import httpx; httpx.get('http://localhost:8000/health')"] interval: 30s timeout: 10s retries: 3 start_period: 30s networks: - churn_network # ============================================================================= # Kafka Consumer (Async Predictions) # ============================================================================= kafka_consumer: build: context: ./kafka_consumer dockerfile: Dockerfile container_name: churn_kafka_consumer depends_on: postgres: condition: service_healthy kafka: condition: service_healthy ml_service: condition: service_healthy environment: DATABASE_URL: postgresql://churn_user:churn_password@postgres:5432/churn_db KAFKA_BOOTSTRAP_SERVERS: kafka:9092 MODEL_DIR: /app/models volumes: - model_data:/app/models restart: unless-stopped networks: - churn_network # ============================================================================= # Streamlit UI # ============================================================================= streamlit: build: context: ./streamlit_ui dockerfile: Dockerfile container_name: churn_streamlit depends_on: - ml_service - postgres ports: - "8501:8501" environment: API_URL: http://ml_service:8000 DATABASE_URL: postgresql://churn_user:churn_password@postgres:5432/churn_db healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8501/_stcore/health"] interval: 30s timeout: 10s retries: 3 start_period: 30s networks: - churn_network # ============================================================================= # Airflow (Scheduler & ETL) # ============================================================================= airflow-init: build: context: ./airflow dockerfile: Dockerfile container_name: churn_airflow_init depends_on: postgres: condition: service_healthy environment: AIRFLOW__CORE__EXECUTOR: LocalExecutor AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://churn_user:churn_password@postgres:5432/churn_db AIRFLOW__CORE__FERNET_KEY: '' AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'false' AIRFLOW__CORE__LOAD_EXAMPLES: 'false' AIRFLOW__WEBSERVER__EXPOSE_CONFIG: 'true' _AIRFLOW_DB_MIGRATE: 'true' _AIRFLOW_WWW_USER_CREATE: 'true' _AIRFLOW_WWW_USER_USERNAME: airflow _AIRFLOW_WWW_USER_PASSWORD: airflow entrypoint: /bin/bash command: - -c - | airflow db init airflow users create \ --username airflow \ --password airflow \ --firstname Admin \ --lastname User \ --role Admin \ --email admin@example.com || true networks: - churn_network airflow-webserver: build: context: ./airflow dockerfile: Dockerfile container_name: churn_airflow_webserver depends_on: airflow-init: condition: service_completed_successfully postgres: condition: service_healthy ports: - "8080:8080" environment: AIRFLOW__CORE__EXECUTOR: LocalExecutor AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://churn_user:churn_password@postgres:5432/churn_db AIRFLOW__CORE__FERNET_KEY: '' AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'false' AIRFLOW__CORE__LOAD_EXAMPLES: 'false' AIRFLOW__WEBSERVER__EXPOSE_CONFIG: 'true' command: webserver volumes: - model_data:/opt/airflow/models healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/health"] interval: 30s timeout: 10s retries: 5 start_period: 60s restart: unless-stopped networks: - churn_network airflow-scheduler: build: context: ./airflow dockerfile: Dockerfile container_name: churn_airflow_scheduler depends_on: airflow-init: condition: service_completed_successfully postgres: condition: service_healthy environment: AIRFLOW__CORE__EXECUTOR: LocalExecutor AIRFLOW__DATABASE__SQL_ALCHEMY_CONN: postgresql+psycopg2://churn_user:churn_password@postgres:5432/churn_db AIRFLOW__CORE__FERNET_KEY: '' AIRFLOW__CORE__DAGS_ARE_PAUSED_AT_CREATION: 'false' AIRFLOW__CORE__LOAD_EXAMPLES: 'false' command: scheduler volumes: - model_data:/opt/airflow/models restart: unless-stopped networks: - churn_network # ============================================================================= # Prometheus (Metrics Collection) # ============================================================================= prometheus: image: prom/prometheus:v2.47.0 container_name: churn_prometheus ports: - "9090:9090" volumes: - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml - 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' - '--web.enable-lifecycle' healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/-/healthy"] interval: 30s timeout: 10s retries: 3 networks: - churn_network # ============================================================================= # Grafana (Monitoring Dashboards) # ============================================================================= grafana: image: grafana/grafana:10.2.0 container_name: churn_grafana depends_on: - prometheus - postgres ports: - "3000:3000" environment: GF_SECURITY_ADMIN_USER: admin GF_SECURITY_ADMIN_PASSWORD: admin GF_USERS_ALLOW_SIGN_UP: "false" GF_INSTALL_PLUGINS: grafana-clock-panel,grafana-piechart-panel volumes: - grafana_data:/var/lib/grafana - ./grafana/provisioning:/etc/grafana/provisioning healthcheck: test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"] interval: 30s timeout: 10s retries: 3 networks: - churn_network # ============================================================================= # Volumes # ============================================================================= volumes: postgres_data: model_data: prometheus_data: grafana_data: # ============================================================================= # Networks # ============================================================================= networks: churn_network: driver: bridge