version: "3.8" services: # ── LocalStack (S3) ── localstack: image: localstack/localstack:3.8 container_name: localstack ports: - "4566:4566" environment: SERVICES: s3 DEFAULT_REGION: us-east-1 DOCKER_HOST: unix:///var/run/docker.sock volumes: - localstack_data:/var/lib/localstack - ./localstack/init.sh:/etc/localstack/init/ready.d/init.sh healthcheck: test: [ "CMD", "awslocal", "s3", "ls" ] interval: 5s timeout: 3s retries: 10 networks: - price-network # ── Hive Metastore ── metastore: build: context: ./metastore container_name: hive-metastore ports: - "9083:9083" environment: SERVICE_NAME: "metastore" SERVICE_PORT: "9083" SKIP_SCHEMA_INIT: "true" depends_on: localstack: condition: service_healthy healthcheck: test: ["CMD-SHELL", "bash -c 'echo > /dev/tcp/localhost/9083' 2>/dev/null || exit 1"] interval: 5s timeout: 5s retries: 20 networks: - price-network # ── Trino (query engine) ── trino: image: trinodb/trino:443 container_name: trino ports: - "8081:8080" volumes: - ./trino/catalog:/etc/trino/catalog environment: TRINO_JVM_HEAP_SIZE: "1g" healthcheck: test: [ "CMD", "trino", "--execute", "SELECT 1" ] interval: 5s timeout: 5s retries: 20 depends_on: - metastore networks: - price-network # ── Spark ── spark: build: context: ./spark container_name: spark ports: - "8082:8080" - "7077:7077" environment: SPARK_MODE: master AWS_ACCESS_KEY_ID: test AWS_SECRET_ACCESS_KEY: test AWS_ENDPOINT_URL: http://localstack:4566 volumes: - ./data:/data:ro - ./spark/scripts/init-iceberg.py:/opt/init-iceberg.py depends_on: localstack: condition: service_healthy metastore: condition: service_healthy networks: - price-network entrypoint: [ "sleep", "infinity" ] # ── dbt-runner (stays alive, run dbt via docker exec) ── dbt-runner: build: context: ./dbt container_name: dbt-runner working_dir: /dbt volumes: - ./dbt:/dbt depends_on: trino: condition: service_healthy networks: - price-network entrypoint: [ "sleep", "infinity" ] volumes: localstack_data: networks: price-network: driver: bridge