# Meridian TSDB — Microservices Docker Compose # # Topology: # gateway (1) — public API + dashboard + WebSocket # ingestor (2) — TCP ingestion + hash-sharded writes # storage (3) — TSDB engine, WAL, compression # querier (1) — PromQL parsing, fan-out to storage # compactor (1) — retention enforcement # simulator (1) — metric generator services: # ── Gateway ────────────────────────────────────────────────────────── gateway: build: . container_name: meridian-gateway hostname: gateway entrypoint: ["/app/gateway"] ports: - "8080:8080" environment: GATEWAY_HTTP_ADDR: ":8080" GATEWAY_NODE_ID: "gateway-1" QUERIER_ADDR: "querier:8080" INGESTOR_ADDRS: "ingestor-1:8080,ingestor-2:8080" STORAGE_ADDRS: "storage-1:8080,storage-2:8080,storage-3:8080" depends_on: querier: condition: service_healthy ingestor-1: condition: service_healthy storage-1: condition: service_healthy networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 # ── Ingestor Nodes ──────────────��─────────────────────��────────────── ingestor-1: build: . container_name: meridian-ingestor-1 hostname: ingestor-1 entrypoint: ["/app/ingestor"] ports: - "9090:9090" volumes: - ingestor-1-data:/app/data environment: INGESTOR_HTTP_ADDR: ":8080" INGESTOR_TCP_ADDR: ":9090" INGESTOR_NODE_ID: "ingestor-1" INGESTOR_DATA_DIR: "/app/data" STORAGE_ADDRS: "storage-1:8080,storage-2:8080,storage-3:8080" # Sole anti-entropy coordinator (ADR-030): one ingestor sweeps so the proactive # convergence work is not duplicated across ingestors (hints stay per-ingestor). ANTI_ENTROPY_ENABLED: "true" depends_on: storage-1: condition: service_healthy storage-2: condition: service_healthy storage-3: condition: service_healthy networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 ingestor-2: build: . container_name: meridian-ingestor-2 hostname: ingestor-2 entrypoint: ["/app/ingestor"] ports: - "9091:9090" volumes: - ingestor-2-data:/app/data environment: INGESTOR_HTTP_ADDR: ":8080" INGESTOR_TCP_ADDR: ":9090" INGESTOR_NODE_ID: "ingestor-2" INGESTOR_DATA_DIR: "/app/data" STORAGE_ADDRS: "storage-1:8080,storage-2:8080,storage-3:8080" # ingestor-1 is the anti-entropy coordinator; disable here to avoid duplicate sweeps. ANTI_ENTROPY_ENABLED: "false" depends_on: storage-1: condition: service_healthy storage-2: condition: service_healthy storage-3: condition: service_healthy networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 # ── Storage Nodes ──────��───────────────────────────────────────────── storage-1: build: . container_name: meridian-storage-1 hostname: storage-1 entrypoint: ["/app/storage-svc"] volumes: - storage-1-data:/app/data environment: STORAGE_HTTP_ADDR: ":8080" STORAGE_DATA_DIR: "/app/data" STORAGE_NODE_ID: "storage-1" networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 storage-2: build: . container_name: meridian-storage-2 hostname: storage-2 entrypoint: ["/app/storage-svc"] volumes: - storage-2-data:/app/data environment: STORAGE_HTTP_ADDR: ":8080" STORAGE_DATA_DIR: "/app/data" STORAGE_NODE_ID: "storage-2" networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 storage-3: build: . container_name: meridian-storage-3 hostname: storage-3 entrypoint: ["/app/storage-svc"] volumes: - storage-3-data:/app/data environment: STORAGE_HTTP_ADDR: ":8080" STORAGE_DATA_DIR: "/app/data" STORAGE_NODE_ID: "storage-3" networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 # ── Querier ────────────────────────────────────────────────────────── querier: build: . container_name: meridian-querier hostname: querier entrypoint: ["/app/querier"] environment: QUERIER_HTTP_ADDR: ":8080" QUERIER_NODE_ID: "querier-1" STORAGE_ADDRS: "storage-1:8080,storage-2:8080,storage-3:8080" depends_on: storage-1: condition: service_healthy storage-2: condition: service_healthy storage-3: condition: service_healthy networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 5s timeout: 3s retries: 5 # ── Compactor ────────────────────────────────────��─────────────────── compactor: build: . container_name: meridian-compactor hostname: compactor entrypoint: ["/app/compactor"] environment: COMPACTOR_HTTP_ADDR: ":8080" COMPACTOR_NODE_ID: "compactor-1" STORAGE_ADDRS: "storage-1:8080,storage-2:8080,storage-3:8080" RETENTION: "360h" depends_on: storage-1: condition: service_healthy networks: - meridian-net restart: unless-stopped healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:8080/health"] interval: 10s timeout: 3s retries: 3 # ── Simulator ──────────────────────────────────────────────────────── simulator: build: . container_name: meridian-simulator entrypoint: ["/app/meridian"] depends_on: ingestor-1: condition: service_healthy command: simulate --addr=ingestor-1:9090 --hosts=8 --rate=5s networks: - meridian-net restart: unless-stopped volumes: storage-1-data: storage-2-data: storage-3-data: ingestor-1-data: # buffered hinted-handoff hints (ADR-029), durable across restarts ingestor-2-data: networks: meridian-net: driver: bridge