version: "3.9" networks: eaglevision_net: driver: bridge volumes: timescaledb_data: kafka_data: services: # ───────────────────────────────────────── # ZOOKEEPER # ───────────────────────────────────────── zookeeper: image: confluentinc/cp-zookeeper:7.6.0 container_name: eaglevision_zookeeper networks: [eaglevision_net] environment: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 healthcheck: test: ["CMD", "nc", "-z", "localhost", "2181"] interval: 10s timeout: 5s retries: 5 # ───────────────────────────────────────── # KAFKA BROKER # ───────────────────────────────────────── kafka: image: confluentinc/cp-kafka:7.6.0 container_name: eaglevision_kafka networks: [eaglevision_net] depends_on: zookeeper: condition: service_healthy ports: - "9092:9092" environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092 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" KAFKA_LOG_RETENTION_HOURS: 24 volumes: - kafka_data:/var/lib/kafka/data healthcheck: test: ["CMD", "kafka-topics", "--bootstrap-server", "localhost:9092", "--list"] interval: 15s timeout: 10s retries: 10 # ───────────────────────────────────────── # KAFKA UI (optional monitoring) # ───────────────────────────────────────── kafka_ui: image: provectuslabs/kafka-ui:latest container_name: eaglevision_kafka_ui networks: [eaglevision_net] depends_on: kafka: condition: service_healthy ports: - "8090:8080" environment: KAFKA_CLUSTERS_0_NAME: eaglevision KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092 # ───────────────────────────────────────── # TIMESCALEDB (PostgreSQL + time-series) # ───────────────────────────────────────── timescaledb: image: timescale/timescaledb:latest-pg16 container_name: eaglevision_timescaledb networks: [eaglevision_net] ports: - "5432:5432" environment: POSTGRES_DB: eaglevision POSTGRES_USER: eagle POSTGRES_PASSWORD: eagle_secret volumes: - timescaledb_data:/var/lib/postgresql/data - ./db/init.sql:/docker-entrypoint-initdb.d/init.sql healthcheck: test: ["CMD-SHELL", "pg_isready -U eagle -d eaglevision"] interval: 10s timeout: 5s retries: 10 # ───────────────────────────────────────── # CV MICROSERVICE # ───────────────────────────────────────── cv_service: build: context: ./cv_service dockerfile: Dockerfile container_name: eaglevision_cv networks: [eaglevision_net] depends_on: kafka: condition: service_healthy timescaledb: condition: service_healthy volumes: - ./cv_service:/app - ./data:/app/data # mount video files here environment: KAFKA_BOOTSTRAP_SERVERS: kafka:29092 KAFKA_TOPIC: equipment_events VIDEO_SOURCE: /app/data/input.mp4 # override via .env YOLO_MODEL: yolov8m.pt FLOW_THRESHOLD: 1.5 INACTIVE_THRESHOLD: 0.5 DB_HOST: timescaledb DB_PORT: 5432 DB_NAME: eaglevision DB_USER: eagle DB_PASSWORD: eagle_secret restart: unless-stopped # ───────────────────────────────────────── # STREAMLIT UI # ───────────────────────────────────────── streamlit_ui: build: context: ./ui dockerfile: Dockerfile container_name: eaglevision_ui networks: [eaglevision_net] depends_on: kafka: condition: service_healthy timescaledb: condition: service_healthy ports: - "8501:8501" volumes: - ./ui:/app environment: KAFKA_BOOTSTRAP_SERVERS: kafka:29092 KAFKA_TOPIC: equipment_events DB_HOST: timescaledb DB_PORT: 5432 DB_NAME: eaglevision DB_USER: eagle DB_PASSWORD: eagle_secret restart: unless-stopped