diff --git a/docker-compose.observability.yml b/docker-compose.observability.yml index 1cf48f9..4a09f2a 100644 --- a/docker-compose.observability.yml +++ b/docker-compose.observability.yml @@ -1,14 +1,22 @@ # Standalone observability stack. # # Run this on a host where you want Grafana, Prometheus, Loki, Alertmanager, -# Alloy and Node Exporter without the rest of Manage. It exposes the usual -# ports directly; no Traefik or OIDC integration is required. +# Alloy and Node Exporter without the rest of Manage. # -# cp .env.example .env -# # optionally edit OBSERVABILITY_* paths and ports +# Required environment variables: +# - OBSERVABILITY_DATA_ROOT (absolute path, e.g. /var/lib/manage/observability) +# - CERT_RESOLVER (Traefik cert resolver name) +# - GRAFANA_APP_HOST, PROMETHEUS_APP_HOST, ALERTMANAGER_APP_HOST +# +# Optional environment variables: +# - TRAEFIK_ENTRYPOINT (default: websecure) +# - *_APP_NAME router/service names (defaults below) +# - all *_PORT variables for direct host ports +# +# Deploy: # docker compose -f docker-compose.observability.yml up -d # -# Then open Grafana at http://localhost:3000 (admin / admin by default). +# Then open Grafana at the configured host (default admin / admin). # # To scrape a Manage backend as well, edit monitoring/prometheus/prometheus.standalone.yml # and add a static target for it, or drop a file-SD JSON file into @@ -29,11 +37,12 @@ services: - ./monitoring/prometheus/prometheus.standalone.yml:/etc/prometheus/prometheus.yml:ro - ./monitoring/prometheus/rules:/etc/prometheus/rules:ro - ./monitoring/prometheus/file-sd:/etc/prometheus/file-sd:ro - - ${OBSERVABILITY_DATA_ROOT:-./observability-data}/prometheus:/prometheus + - ${OBSERVABILITY_DATA_ROOT:?set OBSERVABILITY_DATA_ROOT}/prometheus:/prometheus ports: - "${PROMETHEUS_PORT:-9090}:9090" networks: - monitoring + - web restart: unless-stopped healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:9090/-/healthy"] @@ -41,6 +50,12 @@ services: timeout: 5s retries: 3 start_period: 30s + labels: + - "traefik.enable=true" + - "traefik.http.routers.${PROMETHEUS_APP_NAME:-prometheus}.rule=Host(`${PROMETHEUS_APP_HOST:?set PROMETHEUS_APP_HOST}`)" + - "traefik.http.routers.${PROMETHEUS_APP_NAME:-prometheus}.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" + - "traefik.http.routers.${PROMETHEUS_APP_NAME:-prometheus}.tls.certresolver=${CERT_RESOLVER:?set CERT_RESOLVER}" + - "traefik.http.services.${PROMETHEUS_APP_NAME:-prometheus}.loadbalancer.server.port=${PROMETHEUS_APP_PORT:-9090}" deploy: resources: limits: @@ -56,7 +71,7 @@ services: command: -config.file=/etc/loki/loki.yml volumes: - ./monitoring/loki/loki.yml:/etc/loki/loki.yml:ro - - ${OBSERVABILITY_DATA_ROOT:-./observability-data}/loki:/loki + - ${OBSERVABILITY_DATA_ROOT:?set OBSERVABILITY_DATA_ROOT}/loki:/loki ports: - "${LOKI_PORT:-3100}:3100" networks: @@ -88,7 +103,7 @@ services: - ./monitoring/alloy/config.alloy:/etc/alloy/config.alloy:ro - /var/run/docker.sock:/var/run/docker.sock:ro - /var/lib/docker/containers:/var/lib/docker/containers:ro - - ${OBSERVABILITY_DATA_ROOT:-./observability-data}/alloy:/var/lib/alloy + - ${OBSERVABILITY_DATA_ROOT:?set OBSERVABILITY_DATA_ROOT}/alloy:/var/lib/alloy ports: - "${ALLOY_PORT:-12345}:12345" networks: @@ -128,11 +143,12 @@ services: volumes: - ./monitoring/grafana/grafana.ini:/etc/grafana/grafana.ini:ro - ./monitoring/grafana/provisioning:/etc/grafana/provisioning:ro - - ${OBSERVABILITY_DATA_ROOT:-./observability-data}/grafana:/var/lib/grafana + - ${OBSERVABILITY_DATA_ROOT:?set OBSERVABILITY_DATA_ROOT}/grafana:/var/lib/grafana ports: - "${GRAFANA_PORT:-3000}:3000" networks: - monitoring + - web depends_on: prometheus: condition: service_healthy @@ -145,6 +161,12 @@ services: timeout: 5s retries: 3 start_period: 30s + labels: + - "traefik.enable=true" + - "traefik.http.routers.${GRAFANA_APP_NAME:-grafana}.rule=Host(`${GRAFANA_APP_HOST:?set GRAFANA_APP_HOST}`)" + - "traefik.http.routers.${GRAFANA_APP_NAME:-grafana}.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" + - "traefik.http.routers.${GRAFANA_APP_NAME:-grafana}.tls.certresolver=${CERT_RESOLVER:?set CERT_RESOLVER}" + - "traefik.http.services.${GRAFANA_APP_NAME:-grafana}.loadbalancer.server.port=${GRAFANA_APP_PORT:-3000}" deploy: resources: limits: @@ -169,11 +191,12 @@ services: ALERT_EMAIL_TO: ${ALERT_EMAIL_TO:-admin@example.com} volumes: - ./monitoring/alertmanager/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro - - ${OBSERVABILITY_DATA_ROOT:-./observability-data}/alertmanager:/alertmanager + - ${OBSERVABILITY_DATA_ROOT:?set OBSERVABILITY_DATA_ROOT}/alertmanager:/alertmanager ports: - "${ALERTMANAGER_PORT:-9093}:9093" networks: - monitoring + - web restart: unless-stopped healthcheck: test: ["CMD", "wget", "-qO-", "http://127.0.0.1:9093/-/healthy"] @@ -181,6 +204,12 @@ services: timeout: 5s retries: 3 start_period: 30s + labels: + - "traefik.enable=true" + - "traefik.http.routers.${ALERTMANAGER_APP_NAME:-alertmanager}.rule=Host(`${ALERTMANAGER_APP_HOST:?set ALERTMANAGER_APP_HOST}`)" + - "traefik.http.routers.${ALERTMANAGER_APP_NAME:-alertmanager}.entrypoints=${TRAEFIK_ENTRYPOINT:-websecure}" + - "traefik.http.routers.${ALERTMANAGER_APP_NAME:-alertmanager}.tls.certresolver=${CERT_RESOLVER:?set CERT_RESOLVER}" + - "traefik.http.services.${ALERTMANAGER_APP_NAME:-alertmanager}.loadbalancer.server.port=${ALERTMANAGER_APP_PORT:-9093}" deploy: resources: limits: @@ -219,3 +248,5 @@ services: networks: monitoring: + web: + external: true diff --git a/docs/observability-runbooks.md b/docs/observability-runbooks.md index d911b7c..96aa82a 100644 --- a/docs/observability-runbooks.md +++ b/docs/observability-runbooks.md @@ -179,23 +179,32 @@ Run the observability services without the Manage backend or frontend: ```bash cd /path/to/manage -cp .env.example .env -# edit .env as needed -docker compose -f docker-compose.observability.yml up -d +# create an env file with at least the required variables +cat > .env.observability <