| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- # docker-compose.yml — single-host M0 stack.
- # Run: docker compose up -d
- # Then: see M0_VERIFICATION.md for the loadgen smoke test.
- #
- # Port conventions (project rule):
- # - app HTTP services: 8800–8899 (ingestd/routerd/deliverd-fcm/deliverd-telegram/telegramd/admind/loadgen/faketgmd)
- # - canonical ports stay (5432 postgres, 4222 nats, 6379 redis,
- # 1883 mqtt, 9090 prometheus, 3000 grafana, etc.)
- services:
- # ── Data tier ────────────────────────────────────────────────────
- postgres:
- image: timescale/timescaledb:latest-pg16
- environment:
- POSTGRES_USER: ba
- POSTGRES_PASSWORD: ba
- POSTGRES_DB: ba
- # No host port mapping: a host-local postgres is already on
- # :5432. The app services reach this one via the docker network
- # DNS name 'postgres'. Use `docker compose exec postgres psql ...`
- # to talk to it from the host.
- expose: ["5432"]
- volumes:
- - pgdata:/var/lib/postgresql/data
- healthcheck:
- test: ["CMD-SHELL", "pg_isready -U ba"]
- interval: 5s
- timeout: 3s
- retries: 10
- redis:
- image: redis:7-alpine
- # No host port mapping: a host-local redis is on :6379. App
- # services reach this one via docker DNS 'redis'.
- expose: ["6379"]
- healthcheck:
- test: ["CMD", "redis-cli", "ping"]
- interval: 5s
- timeout: 3s
- retries: 10
- nats:
- image: nats:2.10-alpine
- command: ["-js", "-sd", "/data", "-m", "8222"]
- ports: ["4222:4222", "8222:8222"] # 8222 is the monitoring HTTP
- volumes:
- - natsdata:/data
- healthcheck:
- test: ["CMD", "wget", "-qO-", "http://localhost:8222/healthz"]
- interval: 5s
- timeout: 3s
- retries: 20
- emqx:
- image: emqx/emqx:5.10.4
- ports: ["1883:1883", "18083:18083"] # MQTT + admin UI
- healthcheck:
- test: ["CMD-SHELL", "echo > /dev/tcp/127.0.0.1/1883 || exit 1"]
- interval: 10s
- timeout: 5s
- retries: 20
- clickhouse:
- image: clickhouse/clickhouse-server:24-alpine
- ports: ["8123:8123", "9000:9000"]
- volumes:
- - chdata:/var/lib/clickhouse
- ulimits:
- nofile: { soft: 262144, hard: 262144 }
- # ── App tier ─────────────────────────────────────────────────────
- ingestd:
- build: .
- command: ["/app/ingestd"]
- environment:
- BA_ENV: dev
- BA_HTTP_ADDR: ":8800"
- BA_NATS_URL: nats://nats:4222
- BA_REDIS_URL: redis://redis:6379/0
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- BA_INGESTD_SOURCES: "acme-001:prom-prod:s3cret-acme,globex-002:grafana:s3cret-globex"
- BA_INGESTD_RATE_LIMIT_PER_SOURCE: "100"
- BA_INGESTD_RATE_LIMIT_PER_COMPANY: "10000"
- ports: ["8800:8800"]
- depends_on:
- nats: { condition: service_healthy }
- redis: { condition: service_healthy }
- postgres: { condition: service_healthy }
- routerd:
- build: .
- command: ["/app/routerd"]
- environment:
- BA_ENV: dev
- BA_HTTP_ADDR: ":8801"
- BA_NATS_URL: nats://nats:4222
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- ports: ["8801:8801"]
- depends_on:
- nats: { condition: service_healthy }
- postgres: { condition: service_healthy }
- deliverd-fcm:
- build: .
- command: ["/app/deliverd-fcm"]
- environment:
- BA_ENV: dev
- BA_HTTP_ADDR: ":8802"
- BA_NATS_URL: nats://nats:4222
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- BA_FAKECMD_URL: "http://fakefcmd:8820"
- ports: ["8802:8802"]
- depends_on:
- nats: { condition: service_healthy }
- postgres: { condition: service_healthy }
- fakefcmd: { condition: service_started }
- deliverd-telegram:
- build: .
- command: ["/app/deliverd-telegram"]
- environment:
- BA_ENV: dev
- BA_HTTP_ADDR: ":8821"
- BA_NATS_URL: nats://nats:4222
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- BA_TELEGRAM_BOT_TOKEN: "fake-tg-bot-token-acme-001"
- BA_TELEGRAM_FAKE_URL: "http://faketgmd:8830"
- ports: ["8821:8821"]
- depends_on:
- nats: { condition: service_healthy }
- postgres: { condition: service_healthy }
- faketgmd: { condition: service_started }
- telegramd:
- build: .
- command: ["/app/telegramd"]
- environment:
- BA_ENV: dev
- BA_HTTP_ADDR: ":8822"
- BA_NATS_URL: nats://nats:4222
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- BA_TELEGRAM_FAKE_URL: "http://faketgmd:8830"
- ports: ["8822:8822"]
- depends_on:
- nats: { condition: service_healthy }
- postgres: { condition: service_healthy }
- faketgmd: { condition: service_started }
- faketgmd:
- build: .
- command: ["/app/faketgmd", "--addr", ":8830", "--timeout", "5"]
- ports: ["8830:8830"]
- fakefcmd:
- build: .
- command: ["/app/fakefcmd", "--addr", ":8820"]
- ports: ["8820:8820"]
- healthcheck:
- test: ["CMD", "wget", "-qO-", "http://localhost:8820/health"]
- interval: 5s
- timeout: 3s
- retries: 10
- seed:
- build: .
- command: ["/app/seed"]
- environment:
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- BA_MIGRATIONS_DIR: /migrations
- volumes:
- - ./migrations:/migrations:ro
- depends_on:
- postgres: { condition: service_healthy }
- admind:
- build: .
- command: ["/app/admind"]
- environment:
- BA_ENV: dev
- BA_HTTP_ADDR: ":8803"
- BA_NATS_URL: nats://nats:4222
- BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
- ports: ["8803:8803"]
- depends_on:
- nats: { condition: service_healthy }
- postgres: { condition: service_healthy }
- # ── Observability ────────────────────────────────────────────────
- prometheus:
- image: prom/prometheus:latest
- command:
- - --config.file=/etc/prometheus/prometheus.yml
- volumes:
- - ./deploy/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ports: ["9090:9090"]
- depends_on: [ingestd, routerd, deliverd-fcm, deliverd-telegram, telegramd, admind]
- grafana:
- image: grafana/grafana:latest
- # :3000 is held by gogs (git3) on this host. Map to :3001
- # on the host, keep :3000 internal. M0 ports convention
- # says canonical ports stay; the host-port override is a
- # one-line exception, fully isolated to grafana.
- ports: ["3001:3000"]
- environment:
- GF_SECURITY_ADMIN_USER: admin
- GF_SECURITY_ADMIN_PASSWORD: admin
- depends_on: [prometheus]
- # ── Loadgen (one-shot smoke profile) ────────────────────
- loadgen-http:
- build: .
- command:
- - /app/loadgen-http
- - --target=http://ingestd:8800
- - --api-key=acme-001:prom-prod:s3cret-acme
- - --mode=normal
- - --rate=50
- - --duration=30s
- - --metrics=:8891
- profiles: ["loadgen"]
- depends_on:
- ingestd: { condition: service_started }
- volumes:
- pgdata: {}
- natsdata: {}
- chdata: {}
|