| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- # Observability stack — Grafana + Loki + Prometheus + Promtail.
- #
- # Single Dokploy compose project. Sits on the same docker network as
- # apps/api, apps/runtime, apps/realtime so Prometheus can scrape their
- # /metrics endpoints by container name. Grafana is exposed via Traefik
- # behind Cloudflare Access; the rest are internal-only.
- #
- # Per DOCKER.md (project root):
- # - Promtail uses file-based discovery against /var/lib/docker/containers
- # (read-only). NO docker.sock mount. NO docker_sd_configs.
- # - Prometheus uses static_configs against service DNS names. NO
- # docker_sd_configs. NO scraping of unix:///var/run/docker.sock.
- # - Every service has logging.options.max-size set (rule §7).
- #
- # See ./README.md for the operator runbook.
- x-logging: &briven-logging
- driver: json-file
- options:
- max-size: '10m'
- max-file: '3'
- services:
- prometheus:
- image: prom/prometheus:v3.0.1
- restart: unless-stopped
- logging: *briven-logging
- command:
- - '--config.file=/etc/prometheus/prometheus.yml'
- - '--storage.tsdb.path=/prometheus'
- - '--storage.tsdb.retention.time=30d'
- - '--web.enable-lifecycle'
- volumes:
- - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- - ./prometheus/rules:/etc/prometheus/rules:ro
- - prometheus_data:/prometheus
- depends_on:
- - alertmanager
- networks:
- - dokploy-network
- alertmanager:
- image: prom/alertmanager:v0.27.0
- restart: unless-stopped
- logging: *briven-logging
- command:
- - '--config.file=/etc/alertmanager/alertmanager.yml'
- - '--storage.path=/alertmanager'
- volumes:
- - ./alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
- - alertmanager_data:/alertmanager
- networks:
- - dokploy-network
- # Translator sidecar — alertmanager webhook → discord webhook payload.
- # Two instances, one per channel, each holding a different webhook url.
- # The url is held inside the container's env so it never lands in the
- # repo. J sets BRIVEN_DISCORD_WEBHOOK_ALERTS + BRIVEN_DISCORD_WEBHOOK_DEPLOYS
- # in the dokploy project's environment per CLAUDE.md §4.1 (BRIVEN_ prefix
- # on every briven-owned env var) and docs/runbooks/discord-setup.md §4.
- alertmanager-discord-alerts:
- image: benjojo/alertmanager-discord:latest
- restart: unless-stopped
- logging: *briven-logging
- environment:
- DISCORD_WEBHOOK: ${BRIVEN_DISCORD_WEBHOOK_ALERTS}
- LISTEN_ADDRESS: ':9094'
- networks:
- - dokploy-network
- alertmanager-discord-deploys:
- image: benjojo/alertmanager-discord:latest
- restart: unless-stopped
- logging: *briven-logging
- environment:
- DISCORD_WEBHOOK: ${BRIVEN_DISCORD_WEBHOOK_DEPLOYS}
- LISTEN_ADDRESS: ':9094'
- networks:
- - dokploy-network
- loki:
- image: grafana/loki:3.3.2
- restart: unless-stopped
- logging: *briven-logging
- command: -config.file=/etc/loki/config.yaml
- volumes:
- - ./loki/config.yaml:/etc/loki/config.yaml:ro
- - loki_data:/loki
- networks:
- - dokploy-network
- # Promtail — file-based docker log discovery per DOCKER.md §1. The
- # /var/lib/docker/containers bind-mount is read-only so Promtail can
- # tail the json-file driver's output without touching the daemon.
- # DO NOT bind-mount /var/run/docker.sock here (rule §6). DO NOT switch
- # to docker_sd_configs (rule §1).
- promtail:
- image: grafana/promtail:3.3.2
- restart: unless-stopped
- logging: *briven-logging
- command: -config.file=/etc/promtail/config.yaml
- volumes:
- - ./promtail/config.yaml:/etc/promtail/config.yaml:ro
- - /var/lib/docker/containers:/var/lib/docker/containers:ro
- depends_on:
- - loki
- networks:
- - dokploy-network
- # Host metrics — CPU (incl. steal), memory, swap, load, disk/filesystem.
- # Unprivileged; read-only host mounts; NO docker.sock (DOCKER.md §6).
- node-exporter:
- image: prom/node-exporter:v1.8.2
- restart: unless-stopped
- logging: *briven-logging
- command:
- - '--path.rootfs=/host'
- - '--path.procfs=/host/proc'
- - '--path.sysfs=/host/sys'
- - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
- pid: host
- volumes:
- - /:/host:ro,rslave
- networks:
- - dokploy-network
- # Per-container CPU/memory — catches a runaway build before it swap-kills
- # the host. Reads cgroupfs + /var/lib/docker (read-only) for container
- # names; NO docker.sock mount, NO /var/run (DOCKER.md §6). If container
- # metrics don't appear on some kernels, add `privileged: true`.
- cadvisor:
- image: gcr.io/cadvisor/cadvisor:v0.49.1
- restart: unless-stopped
- logging: *briven-logging
- command:
- - '--docker_only=false'
- - '--housekeeping_interval=30s'
- - '--store_container_labels=false'
- devices:
- - /dev/kmsg
- volumes:
- - /:/rootfs:ro
- - /sys:/sys:ro
- - /var/lib/docker/:/var/lib/docker:ro
- - /dev/disk/:/dev/disk:ro
- networks:
- - dokploy-network
- grafana:
- image: grafana/grafana:11.4.0
- restart: unless-stopped
- logging: *briven-logging
- environment:
- # Local-auth mode — operator signs in with the bootstrap admin
- # password set via env. Promotable to cf-access proxy auth later
- # by overriding GF_AUTH_PROXY_ENABLED=true and the header vars.
- GF_SECURITY_ADMIN_USER: ${GRAFANA_ADMIN_USER:-admin}
- GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_ADMIN_PASSWORD}
- GF_USERS_ALLOW_SIGN_UP: 'false'
- GF_SECURITY_ALLOW_EMBEDDING: 'false'
- GF_ANALYTICS_REPORTING_ENABLED: 'false'
- GF_ANALYTICS_CHECK_FOR_UPDATES: 'false'
- volumes:
- - ./grafana/grafana.ini:/etc/grafana/grafana.ini:ro
- - ./grafana/provisioning:/etc/grafana/provisioning:ro
- - ./grafana/dashboards:/var/lib/grafana/dashboards:ro
- - grafana_data:/var/lib/grafana
- depends_on:
- - prometheus
- - loki
- networks:
- - dokploy-network
- labels:
- - 'traefik.enable=true'
- - 'traefik.docker.network=dokploy-network'
- - 'traefik.http.routers.briven-grafana.rule=Host(`grafana.briven.tech`)'
- - 'traefik.http.routers.briven-grafana.entrypoints=websecure'
- - 'traefik.http.routers.briven-grafana.tls.certresolver=letsencrypt'
- - 'traefik.http.services.briven-grafana.loadbalancer.server.port=3000'
- volumes:
- prometheus_data:
- alertmanager_data:
- loki_data:
- grafana_data:
- networks:
- dokploy-network:
- external: true
|