docker-compose.yml 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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-fcm/deliverd-telegram/telegramd/admind/loadgen/faketgmd)
  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. volumes:
  54. # M4: per-company auth + ACL bootstrap. The CSV is read once
  55. # on first boot; acl.conf is re-read on SIGHUP. emqx.conf
  56. # overrides default-deny + file-based authorization.
  57. - ./deploy/emqx/emqx.conf:/opt/emqx/etc/emqx.conf:ro
  58. - ./deploy/emqx/acl.conf:/opt/emqx/etc/acl.conf:ro
  59. - ./deploy/emqx/auth-built-in-db-bootstrap.csv:/opt/emqx/etc/auth-built-in-db-bootstrap.csv:ro
  60. healthcheck:
  61. # The default `echo > /dev/tcp/...` healthcheck in earlier
  62. # versions of the compose ran under sh, which doesn't support
  63. # /dev/tcp and reported the broker as unhealthy even when it
  64. # was fine. Switch to `bash -c` and a TCP probe via the
  65. # bundled healthz endpoint.
  66. test: ["CMD", "bash", "-c", "exec 3<>/dev/tcp/127.0.0.1/1883"]
  67. interval: 10s
  68. timeout: 5s
  69. retries: 20
  70. clickhouse:
  71. image: clickhouse/clickhouse-server:24-alpine
  72. ports: ["8123:8123", "9000:9000"]
  73. volumes:
  74. - chdata:/var/lib/clickhouse
  75. ulimits:
  76. nofile: { soft: 262144, hard: 262144 }
  77. # ── App tier ─────────────────────────────────────────────────────
  78. ingestd:
  79. build: .
  80. command: ["/app/ingestd"]
  81. environment:
  82. BA_ENV: dev
  83. BA_HTTP_ADDR: ":8800"
  84. BA_NATS_URL: nats://nats:4222
  85. BA_REDIS_URL: redis://redis:6379/0
  86. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  87. BA_INGESTD_SOURCES: "acme-001:prom-prod:s3cret-acme,globex-002:grafana:s3cret-globex"
  88. BA_INGESTD_RATE_LIMIT_PER_SOURCE: "100"
  89. BA_INGESTD_RATE_LIMIT_PER_COMPANY: "10000"
  90. # M4: MQTT subscriber. ingestd subscribes to ba/+/+/incoming
  91. # with the dedicated `ingestd` user. The auth file lists
  92. # this user (password "ingestd-broker-only") so EMQX's
  93. # built-in-db authenticates the connection.
  94. BA_INGESTD_MQTT_BROKER: "tcp://emqx:1883"
  95. BA_INGESTD_MQTT_USERNAME: "ingestd"
  96. BA_INGESTD_MQTT_PASSWORD: "ingestd-broker-only"
  97. BA_INGESTD_MQTT_SUBSCRIBE: "ba/+/+/incoming"
  98. ports: ["8800:8800"]
  99. depends_on:
  100. nats: { condition: service_healthy }
  101. redis: { condition: service_healthy }
  102. postgres: { condition: service_healthy }
  103. emqx: { condition: service_healthy }
  104. routerd:
  105. build: .
  106. command: ["/app/routerd"]
  107. environment:
  108. BA_ENV: dev
  109. BA_HTTP_ADDR: ":8801"
  110. BA_NATS_URL: nats://nats:4222
  111. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  112. ports: ["8801:8801"]
  113. depends_on:
  114. nats: { condition: service_healthy }
  115. postgres: { condition: service_healthy }
  116. deliverd-fcm:
  117. build: .
  118. command: ["/app/deliverd-fcm"]
  119. environment:
  120. BA_ENV: dev
  121. BA_HTTP_ADDR: ":8802"
  122. BA_NATS_URL: nats://nats:4222
  123. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  124. BA_FAKECMD_URL: "http://fakefcmd:8820"
  125. ports: ["8802:8802"]
  126. depends_on:
  127. nats: { condition: service_healthy }
  128. postgres: { condition: service_healthy }
  129. fakefcmd: { condition: service_started }
  130. deliverd-telegram:
  131. build: .
  132. command: ["/app/deliverd-telegram"]
  133. environment:
  134. BA_ENV: dev
  135. BA_HTTP_ADDR: ":8821"
  136. BA_NATS_URL: nats://nats:4222
  137. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  138. BA_TELEGRAM_BOT_TOKEN: "fake-tg-bot-token-acme-001"
  139. BA_TELEGRAM_FAKE_URL: "http://faketgmd:8830"
  140. ports: ["8821:8821"]
  141. depends_on:
  142. nats: { condition: service_healthy }
  143. postgres: { condition: service_healthy }
  144. faketgmd: { condition: service_started }
  145. telegramd:
  146. build: .
  147. command: ["/app/telegramd"]
  148. environment:
  149. BA_ENV: dev
  150. BA_HTTP_ADDR: ":8822"
  151. BA_NATS_URL: nats://nats:4222
  152. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  153. BA_TELEGRAM_FAKE_URL: "http://faketgmd:8830"
  154. ports: ["8822:8822"]
  155. depends_on:
  156. nats: { condition: service_healthy }
  157. postgres: { condition: service_healthy }
  158. faketgmd: { condition: service_started }
  159. faketgmd:
  160. build: .
  161. command: ["/app/faketgmd", "--addr", ":8830", "--timeout", "5"]
  162. ports: ["8830:8830"]
  163. fakefcmd:
  164. build: .
  165. command: ["/app/fakefcmd", "--addr", ":8820"]
  166. ports: ["8820:8820"]
  167. healthcheck:
  168. test: ["CMD", "wget", "-qO-", "http://localhost:8820/health"]
  169. interval: 5s
  170. timeout: 3s
  171. retries: 10
  172. seed:
  173. build: .
  174. command: ["/app/seed"]
  175. environment:
  176. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  177. BA_MIGRATIONS_DIR: /migrations
  178. volumes:
  179. - ./migrations:/migrations:ro
  180. depends_on:
  181. postgres: { condition: service_healthy }
  182. admind:
  183. build: .
  184. command: ["/app/admind"]
  185. environment:
  186. BA_ENV: dev
  187. BA_HTTP_ADDR: ":8803"
  188. BA_NATS_URL: nats://nats:4222
  189. BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
  190. ports: ["8803:8803"]
  191. depends_on:
  192. nats: { condition: service_healthy }
  193. postgres: { condition: service_healthy }
  194. # ── Observability ────────────────────────────────────────────────
  195. prometheus:
  196. image: prom/prometheus:latest
  197. command:
  198. - --config.file=/etc/prometheus/prometheus.yml
  199. volumes:
  200. - ./deploy/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
  201. ports: ["9090:9090"]
  202. depends_on: [ingestd, routerd, deliverd-fcm, deliverd-telegram, telegramd, admind]
  203. grafana:
  204. image: grafana/grafana:latest
  205. # :3000 is held by gogs (git3) on this host. Map to :3001
  206. # on the host, keep :3000 internal. M0 ports convention
  207. # says canonical ports stay; the host-port override is a
  208. # one-line exception, fully isolated to grafana.
  209. ports: ["3001:3000"]
  210. environment:
  211. GF_SECURITY_ADMIN_USER: admin
  212. GF_SECURITY_ADMIN_PASSWORD: admin
  213. depends_on: [prometheus]
  214. # ── Loadgen (one-shot smoke profile) ────────────────────
  215. loadgen-http:
  216. build: .
  217. command:
  218. - /app/loadgen-http
  219. - --target=http://ingestd:8800
  220. - --api-key=acme-001:prom-prod:s3cret-acme
  221. - --mode=normal
  222. - --rate=50
  223. - --duration=30s
  224. - --metrics=:8891
  225. profiles: ["loadgen"]
  226. depends_on:
  227. ingestd: { condition: service_started }
  228. volumes:
  229. pgdata: {}
  230. natsdata: {}
  231. chdata: {}