Przeglądaj źródła

M0(11/12): docker-compose, Dockerfile, .env.example, prometheus.yml

- docker-compose.yml: single-host M0 stack
  - data: postgres+timescale, redis, nats+jetstream, emqx,
    clickhouse
  - app: ingestd/routerd/deliverd/admind
  - obs: prometheus, grafana
  - loadgen-http in 'loadgen' profile (one-shot smoke test)
- Dockerfile: multi-stage Go 1.24 alpine build, all 5 binaries
  in one image; compose command: picks which one to run
- .env.example: every BA_* knob documented
- deploy/prometheus/prometheus.yml: scrape all 5 services
Luis Rosales 2 miesięcy temu
rodzic
commit
7cd922c
4 zmienionych plików z 237 dodań i 0 usunięć
  1. 33 0
      .env.example
  2. 32 0
      Dockerfile
  3. 20 0
      deploy/prometheus/prometheus.yml
  4. 152 0
      docker-compose.yml

+ 33 - 0
.env.example

@@ -0,0 +1,33 @@
+# Broad-Announce M0 env defaults. Copy to .env if you want docker
+# compose to pick them up; otherwise the compose file's inline
+# values are used.
+
+BA_ENV=dev
+BA_LOG_LEVEL=info
+
+# HTTP addrs
+BA_INGESTD_HTTP_ADDR=:8080
+BA_ROUTERD_HTTP_ADDR=:8081
+BA_DELIVERD_HTTP_ADDR=:8082
+BA_ADMIND_HTTP_ADDR=:8083
+
+# Data tier
+BA_NATS_URL=nats://localhost:4222
+BA_REDIS_URL=redis://localhost:6379/0
+BA_POSTGRES_DSN=postgres://ba:ba@localhost:5432/ba?sslmode=disable
+
+# Ingestd source protection defaults (SPEC §22)
+BA_INGESTD_MAX_PAYLOAD_BYTES=262144
+BA_INGESTD_RATE_LIMIT_PER_SOURCE=100
+BA_INGESTD_RATE_LIMIT_PER_COMPANY=10000
+BA_INGESTD_MAX_CONCURRENT_PER_IP=64
+BA_INGESTD_QUARANTINE_HITS_THRESHOLD=100
+BA_INGESTD_QUARANTINE_WINDOW_SECONDS=60
+BA_INGESTD_QUARANTINE_DURATION_SECONDS=300
+
+# M0 source registry (env-only; M2 swaps for DB)
+# Format: comma-separated company:source:secret triples
+BA_INGESTD_SOURCES=acme-001:prom-prod:s3cret-acme,globex-002:grafana:s3cret-globex
+
+# Shutdown
+BA_SHUTDOWN_GRACE_SEC=15

+ 32 - 0
Dockerfile

@@ -0,0 +1,32 @@
+# Multi-stage build for broad-announce services.
+# Stage 1: build the four Go service binaries.
+# Stage 2: tiny alpine with just the binaries + ca-certs.
+
+FROM golang:1.24-alpine AS build
+WORKDIR /src
+
+# Cache deps
+COPY go.mod go.sum ./
+COPY loadgen/go.mod loadgen/go.sum ./loadgen/ 2>/dev/null || true
+RUN go mod download
+
+# Build
+COPY . .
+RUN --mount=type=cache,target=/root/.cache/go-build \
+    CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \
+      -o /out/ingestd  ./cmd/ingestd && \
+    CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \
+      -o /out/routerd  ./cmd/routerd && \
+    CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \
+      -o /out/deliverd ./cmd/deliverd && \
+    CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \
+      -o /out/admind   ./cmd/admind && \
+    cd loadgen && \
+    CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" \
+      -o /out/loadgen-http ./cmd/http
+
+FROM alpine:3.20
+RUN apk add --no-cache ca-certificates
+COPY --from=build /out/ /app/
+# Default: print which binary to invoke; compose overrides command.
+CMD ["/app/ingestd"]

+ 20 - 0
deploy/prometheus/prometheus.yml

@@ -0,0 +1,20 @@
+global:
+  scrape_interval: 5s
+  evaluation_interval: 10s
+
+scrape_configs:
+  - job_name: ingestd
+    static_configs:
+      - targets: ['ingestd:8080']
+  - job_name: routerd
+    static_configs:
+      - targets: ['routerd:8081']
+  - job_name: deliverd
+    static_configs:
+      - targets: ['deliverd:8082']
+  - job_name: admind
+    static_configs:
+      - targets: ['admind:8083']
+  - job_name: loadgen
+    static_configs:
+      - targets: ['loadgen-http:9091']

+ 152 - 0
docker-compose.yml

@@ -0,0 +1,152 @@
+# docker-compose.yml — single-host M0 stack.
+# Run: docker compose up -d
+# Then: see M0_VERIFICATION.md for the loadgen smoke test.
+
+services:
+  # ── Data tier ────────────────────────────────────────────────────
+  postgres:
+    image: timescale/timescaledb:latest-pg16
+    environment:
+      POSTGRES_USER: ba
+      POSTGRES_PASSWORD: ba
+      POSTGRES_DB: ba
+    ports: ["5432: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
+    ports: ["6379:6379"]
+    healthcheck:
+      test: ["CMD", "redis-cli", "ping"]
+      interval: 5s
+      timeout: 3s
+      retries: 10
+
+  nats:
+    image: nats:2.10-alpine
+    command: ["-js", "-sd", "/data"]
+    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: 10
+
+  emqx:
+    image: emqx/emqx:5-alpine
+    ports: ["1883:1883", "18083:18083"]   # MQTT + admin UI
+    healthcheck:
+      test: ["CMD", "/opt/emqx/bin/emqx", "ping"]
+      interval: 10s
+      timeout: 5s
+      retries: 10
+
+  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: ":8080"
+      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: ["8080:8080"]
+    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: ":8081"
+      BA_NATS_URL: nats://nats:4222
+      BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
+    ports: ["8081:8081"]
+    depends_on:
+      nats:     { condition: service_healthy }
+      postgres: { condition: service_healthy }
+
+  deliverd:
+    build: .
+    command: ["/app/deliverd"]
+    environment:
+      BA_ENV: dev
+      BA_HTTP_ADDR: ":8082"
+      BA_NATS_URL: nats://nats:4222
+      BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
+    ports: ["8082:8082"]
+    depends_on:
+      nats:     { condition: service_healthy }
+      postgres: { condition: service_healthy }
+
+  admind:
+    build: .
+    command: ["/app/admind"]
+    environment:
+      BA_ENV: dev
+      BA_HTTP_ADDR: ":8083"
+      BA_NATS_URL: nats://nats:4222
+      BA_POSTGRES_DSN: postgres://ba:ba@postgres:5432/ba?sslmode=disable
+    ports: ["8083:8083"]
+    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, admind]
+
+  grafana:
+    image: grafana/grafana:latest
+    ports: ["3000: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"]
+    environment:
+      BA_TARGET: http://ingestd:8080
+      BA_API_KEY: "acme-001:prom-prod:s3cret-acme"
+      BA_RATE: "50"
+      BA_DURATION: "30s"
+    profiles: ["loadgen"]
+    depends_on:
+      ingestd: { condition: service_started }
+
+volumes:
+  pgdata: {}
+  natsdata: {}
+  chdata: {}