docker-compose.yml 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # docker-compose.yml — single-host M0 stack.
  2. # Run: docker compose up -d
  3. # Then: see M0_VERIFICATION.md for the loadgen smoke test.
  4. #
  5. # Port conventions (project rule):
  6. # - app HTTP services: 8800–8899 (ingestd/routerd/deliverd/admind/loadgen)
  7. # - canonical ports stay (5432 postgres, 4222 nats, 6379 redis,
  8. # 1883 mqtt, 9090 prometheus, 3000 grafana, etc.)
  9. services:
  10. # ── Data tier ────────────────────────────────────────────────────
  11. postgres:
  12. image: timescale/timescaledb:latest-pg16
  13. environment:
  14. POSTGRES_USER: ba
  15. POSTGRES_PASSWORD: ba
  16. POSTGRES_DB: ba
  17. # No host port mapping: a host-local postgres is already on
  18. # :5432. The app services reach this one via the docker network
  19. # DNS name 'postgres'. Use `docker compose exec postgres psql ...`
  20. # to talk to it from the host.
  21. expose: ["5432"]
  22. volumes:
  23. - pgdata:/var/lib/postgresql/data
  24. healthcheck:
  25. test: ["CMD-SHELL", "pg_isready -U ba"]
  26. interval: 5s
  27. timeout: 3s
  28. retries: 10
  29. redis:
  30. image: redis:7-alpine
  31. # No host port mapping: a host-local redis is on :6379. App
  32. # services reach this one via docker DNS 'redis'.
  33. expose: ["6379"]
  34. healthcheck:
  35. test: ["CMD", "redis-cli", "ping"]
  36. interval: 5s
  37. timeout: 3s
  38. retries: 10
  39. nats:
  40. image: nats:2.10-alpine
  41. command: ["-js", "-sd", "/data", "-m", "8222"]
  42. ports: ["4222:4222", "8222:8222"] # 8222 is the monitoring HTTP
  43. volumes:
  44. - natsdata:/data
  45. healthcheck:
  46. test: ["CMD", "wget", "-qO-", "http://localhost:8222/healthz"]
  47. interval: 5s
  48. timeout: 3s
  49. retries: 20
  50. emqx:
  51. image: emqx/emqx:5.10.4
  52. ports: ["1883:1883", "18083:18083"] # MQTT + admin UI
  53. healthcheck:
  54. test: ["CMD-SHELL", "echo > /dev/tcp/127.0.0.1/1883 || exit 1"]
  55. interval: 10s
  56. timeout: 5s
  57. retries: 20
  58. clickhouse:
  59. image: clickhouse/clickhouse-server:24-alpine
  60. ports: ["8123:8123", "9000:9000"]
  61. volumes:
  62. - chdata:/var/lib/clickhouse
  63. ulimits:
  64. nofile: { soft: 262144, hard: 262144 }
  65. # ── App tier ─────────────────────────────────────────────────────
  66. ingestd:
  67. build: .
  68. command: ["/app/ingestd"]
  69. environment:
  70. BA_ENV: dev
  71. BA_HTTP_ADDR: ":8800"
  72. BA_NATS_URL: nats://nats:4222
  73. BA_REDIS_URL: redis://redis:6379/0
  74. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  75. BA_INGESTD_SOURCES: "acme-001:prom-prod:s3cret-acme,globex-002:grafana:s3cret-globex"
  76. BA_INGESTD_RATE_LIMIT_PER_SOURCE: "100"
  77. BA_INGESTD_RATE_LIMIT_PER_COMPANY: "10000"
  78. ports: ["8800:8800"]
  79. depends_on:
  80. nats: { condition: service_healthy }
  81. redis: { condition: service_healthy }
  82. postgres: { condition: service_healthy }
  83. routerd:
  84. build: .
  85. command: ["/app/routerd"]
  86. environment:
  87. BA_ENV: dev
  88. BA_HTTP_ADDR: ":8801"
  89. BA_NATS_URL: nats://nats:4222
  90. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  91. ports: ["8801:8801"]
  92. depends_on:
  93. nats: { condition: service_healthy }
  94. postgres: { condition: service_healthy }
  95. deliverd:
  96. build: .
  97. command: ["/app/deliverd"]
  98. environment:
  99. BA_ENV: dev
  100. BA_HTTP_ADDR: ":8802"
  101. BA_NATS_URL: nats://nats:4222
  102. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  103. BA_FAKECMD_URL: "http://fakefcmd:8820"
  104. ports: ["8802:8802"]
  105. depends_on:
  106. nats: { condition: service_healthy }
  107. postgres: { condition: service_healthy }
  108. fakefcmd: { condition: service_started }
  109. fakefcmd:
  110. build: .
  111. command: ["/app/fakefcmd", "--addr", ":8820"]
  112. ports: ["8820:8820"]
  113. healthcheck:
  114. test: ["CMD", "wget", "-qO-", "http://localhost:8820/health"]
  115. interval: 5s
  116. timeout: 3s
  117. retries: 10
  118. seed:
  119. build: .
  120. command: ["/app/seed"]
  121. environment:
  122. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  123. BA_MIGRATIONS_DIR: /migrations
  124. volumes:
  125. - ./migrations:/migrations:ro
  126. depends_on:
  127. postgres: { condition: service_healthy }
  128. admind:
  129. build: .
  130. command: ["/app/admind"]
  131. environment:
  132. BA_ENV: dev
  133. BA_HTTP_ADDR: ":8803"
  134. BA_NATS_URL: nats://nats:4222
  135. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  136. ports: ["8803:8803"]
  137. depends_on:
  138. nats: { condition: service_healthy }
  139. postgres: { condition: service_healthy }
  140. # ── Observability ────────────────────────────────────────────────
  141. prometheus:
  142. image: prom/prometheus:latest
  143. command:
  144. - --config.file=/etc/prometheus/prometheus.yml
  145. volumes:
  146. - ./deploy/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
  147. ports: ["9090:9090"]
  148. depends_on: [ingestd, routerd, deliverd, admind]
  149. grafana:
  150. image: grafana/grafana:latest
  151. ports: ["3000:3000"]
  152. environment:
  153. GF_SECURITY_ADMIN_USER: admin
  154. GF_SECURITY_ADMIN_PASSWORD: admin
  155. depends_on: [prometheus]
  156. # ── Loadgen (one-shot smoke profile) ────────────────────
  157. loadgen-http:
  158. build: .
  159. command:
  160. - /app/loadgen-http
  161. - --target=http://ingestd:8800
  162. - --api-key=acme-001:prom-prod:s3cret-acme
  163. - --mode=normal
  164. - --rate=50
  165. - --duration=30s
  166. - --metrics=:8891
  167. profiles: ["loadgen"]
  168. depends_on:
  169. ingestd: { condition: service_started }
  170. volumes:
  171. pgdata: {}
  172. natsdata: {}
  173. chdata: {}