From 36146904a26c892b2f9c04137f5185563739bc4e Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Tue, 28 Jul 2026 16:17:16 +0200 Subject: [PATCH] obs,alloy: fix alloy config --- .../infrastructure/observability/alloy.river | 82 +++++++--------- .../observability/alloy-config.yaml | 95 +++++++------------ 2 files changed, 70 insertions(+), 107 deletions(-) diff --git a/docker/infrastructure/observability/alloy.river b/docker/infrastructure/observability/alloy.river index da63e0f..a5f11c6 100644 --- a/docker/infrastructure/observability/alloy.river +++ b/docker/infrastructure/observability/alloy.river @@ -1,43 +1,53 @@ -// Grafana Alloy config for the docker host -// Tails Docker container logs via the docker_sd discovery + -// file streaming, applies container_name/image labels, and pushes them to -// the in-cluster Loki at loki-internal.lan (LAN-only Traefik Ingress). +// Grafana Alloy config for the docker host (replaces Promtail, EOL since +// 2026-03-02). Tails Docker container logs via docker_sd discovery, attaches +// container_name/compose_service/stream labels, and pushes them to the +// in-cluster Loki at loki-internal.lan (LAN-only Traefik Ingress on port 80). +// River config produced by `alloy convert -f promtail` from an equivalent +// Promtail YAML (so component names and argument shapes are guaranteed +// correct for Alloy v1.18). -logging { - level = "info" - format = "logfmt" +discovery.docker "docker" { + host = "unix:///var/run/docker.sock" + refresh_interval = "5s" } -// Discover running Docker containers via the host socket. -discovery.docker "containers" { - host = "unix:///var/run/docker.sock" +loki.process "docker" { + forward_to = [loki.write.default.receiver] + + // Parse docker json-file log lines + // ({"log":"...","stream":"stdout","time":"..."}). + stage.json { + expressions = { + log = "log", + stream = "stream", + } + } + stage.labels { + values = { + stream = null, + } + } } -// Relabel rules: strip the leading slash from __meta_docker_container_name and -// expose useful labels (container name, compose service, image). -discovery.relabel "containers" { - targets = discovery.docker.containers.targets +discovery.relabel "docker" { + targets = [] // Strip leading / from container name. rule { source_labels = ["__meta_docker_container_name"] regex = "/(.*)" target_label = "container_name" - replacement = "$1" } - // Compose service name (if label is set). rule { source_labels = ["__meta_docker_container_label_com_docker_compose_service"] target_label = "compose_service" } - // Log stream (stdout/stderr). rule { source_labels = ["__meta_docker_container_log_stream"] target_label = "stream" } - // Mark the source so dashboards/alerts can distinguish the docker host. rule { target_label = "source" @@ -45,39 +55,17 @@ discovery.relabel "containers" { } } -// Tail the container log files based on the docker_sd discovery. Each target -// exposes a `__path__`idders pointing at /var/lib/docker/containers//-json.log -// (the default docker json-file driver path; we mount that host path read-only). -local.file "container_logs" { - targets = discovery.relabel.containers.output - tail_from_end = true +loki.source.docker "docker" { + host = "unix:///var/run/docker.sock" + targets = discovery.docker.docker.targets + forward_to = [loki.process.docker.receiver] + relabel_rules = discovery.relabel.docker.rules + refresh_interval = "5s" } -// Parse docker json-file logs ({"log":"...","stream":"stdout","time":"..."}). -loki.process "containers" { - forward_to = [loki.write.default.receiver] - - stage.json { - expressions = { - log = "log", - stream = "stream", - time = "time", - } - } - stage.labels { - values = { - stream = "stream", - } - } - stage.timestamp { - source = "time" - format = "RFC3339Nano" - } -} - -// Push to Loki in-cluster via the LAN-only Traefik Ingress (port 80). loki.write "default" { endpoint { url = "http://loki-internal.lan/loki/api/v1/push" } + external_labels = {} } \ No newline at end of file diff --git a/kubernetes/infrastructure/observability/alloy-config.yaml b/kubernetes/infrastructure/observability/alloy-config.yaml index 965c8b9..34dfae9 100644 --- a/kubernetes/infrastructure/observability/alloy-config.yaml +++ b/kubernetes/infrastructure/observability/alloy-config.yaml @@ -12,82 +12,57 @@ data: // Grafana Alloy — log collection only (metrics cluster+host collection is // handled by vmagent/node-exporter/cAdvisor elsewhere). // Forwards pod logs to the in-cluster Loki single-binary. + // River config produced by `alloy convert -f promtail` from an equivalent + // Promtail YAML (so component names and argument shapes are guaranteed + // correct for Alloy v1.18). // ----------------------------------------------------------------------------- - logging { - level = "info" - format = "logfmt" - } - - // Tail every pod's log files written under /var/log/pods/* on the host. - local.file_match "pods" { - path_targets = [{ - __path__ = "/var/log/pods/*/*/*.log", - }] - } - - // Discover Kubernetes metadata for the tailed files (pod_name, namespace, - // container_name, uid). - discovery.kubernetes "pods" { + discovery.kubernetes "kubernetes_pods" { role = "pod" - } - // Stream-stage relabel: read the filename to extract namespace/pod/container - // metadata in line with Loki/Promtail's expectations. - lrelabel "pods" { - targets = local.file_match.pods.targets - rule { - source_labels = ["__path__"] - regex = "/var/log/pods/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/(?P[^/]+)/.*" - target_label = "namespace" - replacement = "$namespace" - } - rule { - source_labels = ["__path__"] - regex = "/var/log/pods/([^/]+)/([^/]+)/([^/]+)/[^/]+/.*" - target_label = "pod" - replacement = "$pod" - } - rule { - source_labels = ["__path__"] - regex = "/var/log/pods/([^/]+)/([^/]+)/([^/]+)/[^/]+/.*" - target_label = "container" - replacement = "$container" + selectors { + role = "pod" + field = "spec.nodeName=" + coalesce(sys.env("HOSTNAME"), constants.hostname) } } - // Tail the actual log files. - local.file "pods_logs" { - targets = lrelabel.pods.output - read_from = "beginning" - tail_from_end = false - } - - // Parse CRI-style lines ({"log":"...","stream":"stdout","time":"..."}). - loki.process "pods" { + loki.process "kubernetes_pods" { forward_to = [loki.write.default.receiver] - stage.json { - expressions = { - log = "log", - stream = "stream", - time = "time", - } + // CRI-style log lines on the host: {"log":"...","stream":"stdout","time":"..."} + stage.cri { } + } + + discovery.relabel "kubernetes_pods" { + targets = discovery.kubernetes.kubernetes_pods.targets + + rule { + source_labels = ["__meta_kubernetes_namespace"] + target_label = "namespace" } - stage.labels { - values = { - stream = "stream", - } + rule { + source_labels = ["__meta_kubernetes_pod_name"] + target_label = "pod" } - stage.timestamp { - source = "time" - format = "RFC3339Nano" + rule { + source_labels = ["__meta_kubernetes_pod_container_name"] + target_label = "container" } } - // Push to Loki in-cluster (no auth on .lan). + loki.source.file "kubernetes_pods" { + targets = discovery.relabel.kubernetes_pods.output + forward_to = [loki.process.kubernetes_pods.receiver] + + file_match { + enabled = true + } + legacy_positions_file = "/tmp/positions.yaml" + } + loki.write "default" { endpoint { url = "http://loki.observability.svc.cluster.local:3100/loki/api/v1/push" } + external_labels = {} } \ No newline at end of file