services:
  fleet-prometheus:
    # Pinned to the Prometheus 3.5 LTS line — NEVER :latest. The home `prom`
    # on PIHA runs :latest, which is the anti-pattern we are deliberately not
    # repeating here: a fleet liveness source must be reproducible.
    image: prom/prometheus:v3.5.0
    container_name: fleet-prometheus
    restart: unless-stopped
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      # Tight VPS (3.7 GiB RAM + 4 GiB swap): keep the TSDB small. Whichever
      # of time/size is hit first triggers compaction/deletion.
      - '--storage.tsdb.retention.time=15d'
      - '--storage.tsdb.retention.size=2GB'
      # Allow `POST /-/reload` so liveness rules (added in a later step) can be
      # hot-loaded without restarting and losing the scrape gap.
      - '--web.enable-lifecycle'
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
      - ./rules:/etc/prometheus/rules:ro
      - fleet_prometheus_tsdb:/prometheus
    ports:
      # tailscale-internal: the listen socket is bound ONLY to the VPS Tailscale
      # interface IP (TAILSCALE_BIND_IP), never 0.0.0.0. The port therefore does
      # not exist on the public Hetzner IP at all — reachability is enforced in
      # the bind itself (defense-in-depth), not solely by the host firewall.
      # brain-watchdog on PIHA reaches this over the VPS Tailscale IP.
      # Requires --env-file services/fleet-prometheus/.env at deploy (see README).
      # Do NOT add this to npm / public DNS.
      - "${TAILSCALE_BIND_IP}:9090:9090"
    # node_exporter on the VPS runs with network_mode: host, so it listens on
    # the host's :9100. This bridged container reaches it via host-gateway.
    extra_hosts:
      - "host.docker.internal:host-gateway"
    # Memory: VPS has 4 GiB RAM. 512m cgroup ceiling; Docker restarts the
    # container on breach. oom_score_adj is POSITIVE on purpose — fleet
    # monitoring is less critical than the control-plane (-900), so the host
    # OOM-killer should sacrifice this container FIRST, never the control-plane.
    mem_limit: 512m
    oom_score_adj: 200
    # The prom/prometheus image is busybox-based and ships `wget` (but no curl),
    # so an in-container HTTP check works here — unlike the vikunja image, which
    # had neither and broke its healthcheck permanently.
    healthcheck:
      test: ["CMD", "wget", "-q", "-O", "-", "http://localhost:9090/-/healthy"]
      interval: 30s
      timeout: 10s
      retries: 5
      start_period: 30s

volumes:
  fleet_prometheus_tsdb:
    name: fleet-prometheus_tsdb
