# Metricbeat: host and per-container metrics, replacing node_exporter and cAdvisor, plus the Prometheus # endpoints the stack already exposes. Runs on the host network so the system module sees the real interfaces # and so it can reach MediaMTX, Caddy, Elasticsearch and Kibana on loopback. metricbeat.modules: - module: system period: 30s metricsets: [cpu, load, memory, network, process, process_summary, socket_summary, filesystem, fsstat, diskio, uptime] processes: ['.*'] process.include_top_n: by_cpu: 10 by_memory: 10 system.hostfs: /hostfs # the host's real filesystems, not the container's - module: docker period: 30s hosts: ["unix:///var/run/docker.sock"] metricsets: [container, cpu, diskio, healthcheck, info, memory, network] - module: prometheus # MediaMTX: per path bytes/s, readers, publishers, dropped packets period: 30s metrics_path: /metrics hosts: ["http://127.0.0.1:9998"] - module: prometheus # Caddy: requests by host and status, durations, TLS period: 60s metrics_path: /metrics hosts: ["http://127.0.0.1:2019"] - module: prometheus # dumpd: OUR metrics — normalise queue, encode time, live streams period: 30s metrics_path: /metrics hosts: ["http://127.0.0.1:8080"] # dumpd's loopback listener; Caddy routes no host to /metrics # These are real counters, so let them arrive typed: Kibana then gets .rate (per-second) as well as the # raw total, which is what makes "encode seconds per hour" a chart rather than a staircase. use_types: true rate_counters: true processors: - add_host_metadata: ~ # The same correlation fields Filebeat sets, so ONE dashboard filter spans logs and metrics. Without these a # metric event carries container.name while a log event carries service.name, and nothing joins them. - add_docker_metadata: ~ - copy_fields: fields: - from: container.labels.vanguard_service to: service.name - from: container.labels.vanguard_category to: vanguard.category fail_on_error: false ignore_missing: true output.elasticsearch: hosts: ["http://127.0.0.1:9200"] # Elasticsearch requires authentication now (see observability/kibana.yml for why security is on). These # come from the container environment, which compose fills from .env — no secret is committed here. username: "${ES_BEATS_USER}" password: "${ES_BEATS_PASSWORD}" setup.kibana: # no credentials: Kibana's anonymous provider signs these in host: "http://127.0.0.1:5601" setup.dashboards.enabled: true # the system and docker dashboards, so there is something to look at # Single node: a replica has nowhere to go, so every beats index would sit unassigned and hold the # cluster at yellow forever. Zero replicas is the correct setting here, not a workaround. setup.template.overwrite: true setup.template.settings: index.number_of_replicas: 0 logging.level: info