RousselTMLEARNING

Observabilité

Grafana Alloy et Prometheus : collecter et envoyer des métriques

Apprenez à configurer Grafana Alloy pour collecter, transformer et envoyer des métriques en utilisant l'écosystème Prometheus et le standard OpenTelemetry (OTLP).

1. Discovery #

Auto-détection des cibles via Kubernetes, Consul ou fichiers statiques.

Trouver les cibles automatiquement #

Disponible dans : ✓ OSS ✓ Enterprise ✓ Cloud

Dans un environnement moderne, les cibles apparaissent et disparaissent sans prévenir. Plutôt que de lister des adresses, on confie cette tâche aux composants discovery.*, qui publient une liste de cibles dans targets.

La chaîne des métriques dans Alloy
ComposantSource
discovery.kubernetesPods, services, nœuds… par l’API Kubernetes
discovery.dockerConteneurs du démon Docker
discovery.fileFichiers JSON ou YAML maintenus par un autre outil
discovery.httpUne API qui renvoie les cibles
discovery.dnsEnregistrements DNS
discovery.processProcessus de la machine

Qu'est-ce qu'une cible ? #

Une cible est un simple objet d'étiquettes. __address__ donne l'adresse. Les étiquettes commençant par __ sont internes : elles servent au relabeling, puis disparaissent avant le stockage. Vous pouvez les lire dans l'interface, sur la page du composant.

Exemple avec un fichier #

Une équipe décrit ses cibles dans un fichier, sans toucher à la configuration d'Alloy :

[
  {
    "targets": ["app-1:8080", "app-2:8080"],
    "labels": { "equipe": "plateforme", "env": "prod" }
  }
]
discovery.file "applis" {
  files            = ["/etc/alloy/cibles/*.json"]
  refresh_interval = "30s"
}

discovery.relabel "applis" {
  targets = discovery.file.applis.targets

  rule {
    source_labels = ["env"]
    regex         = "dev"
    action        = "drop"
  }

  rule {
    target_label = "cluster"
    replacement  = "paris"
  }
}

Résultat observé dans l'interface d'Alloy, pour chaque cible : __address__, env=lab, equipe=plateforme et cluster=paris. Les cibles de dev sont écartées.

action = "drop" écarte ce qui correspond, "keep" ne garde que cela. Une règle sans action remplace : elle écrit replacement dans target_label.

Exemple sur Kubernetes #

On ne garde que les pods annotés, et on transforme les métadonnées internes en étiquettes durables :

discovery.kubernetes "pods" {
  role = "pod"
}

discovery.relabel "annotes" {
  targets = discovery.kubernetes.pods.targets

  rule {
    source_labels = ["__meta_kubernetes_pod_annotation_prometheus_io_scrape"]
    regex         = "true"
    action        = "keep"
  }

  rule {
    source_labels = ["__meta_kubernetes_namespace"]
    target_label  = "namespace"
  }

  rule {
    source_labels = ["__meta_kubernetes_pod_name"]
    target_label  = "pod"
  }
}
Piège : sans règle explicite, les étiquettes __meta_* disparaissent. Si vous voulez namespace et pod dans vos métriques, il faut les copier, comme ci-dessus.

2. Scraping #

Configuration du composant prometheus.scrape.

Le composant prometheus.scrape #

prometheus.scrape interroge régulièrement chaque cible et transmet les métriques à la suite du pipeline. Il fonctionne comme Prometheus, mais sans stocker quoi que ce soit.

prometheus.scrape "applis" {
  targets         = discovery.relabel.applis.output
  scrape_interval = "30s"
  scrape_timeout  = "10s"
  metrics_path    = "/metrics"
  forward_to      = [prometheus.relabel.filtre.receiver]
}

discovery.relabel "applis" {
  targets = []
}

prometheus.relabel "filtre" {
  rule {
    source_labels = ["__name__"]
    regex         = "go_gc_.*"
    action        = "drop"
  }
  forward_to = [prometheus.remote_write.mimir.receiver]
}

prometheus.remote_write "mimir" {
  endpoint {
    url = "http://mimir:9009/api/v1/push"
  }
}
ArgumentRôleDéfaut
scrape_intervalFréquence de collecte60s
scrape_timeoutDélai maximal10s
metrics_pathChemin des métriques/metrics
job_nameValeur de l’étiquette jobNom du composant
honor_labelsGarder les étiquettes de la cible en cas de conflitfalse
Attention au défaut : 60 secondes, contre 15 dans de nombreuses configurations Prometheus. Si vos courbes paraissent moins précises après une migration, regardez d'abord ce réglage.

Deux niveaux de filtrage #

ComposantAgit surQuandExemple
discovery.relabelLes ciblesAvant la collecteIgnorer les pods de dev
prometheus.relabelLes métriquesAprès la collecteRetirer go_gc_.*

Ne pas collecter une cible économise bien plus que de filtrer ses métriques ensuite : filtrez le plus tôt possible.

Collecter le système sans node_exporter #

Alloy embarque des exportateurs. prometheus.exporter.unix remplace le node_exporter, et publie ses cibles comme n'importe quel composant de découverte :

prometheus.exporter.unix "hote" {
  enable_collectors = ["cpu", "meminfo", "diskstats", "filesystem", "netdev"]
}

prometheus.scrape "hote" {
  targets    = prometheus.exporter.unix.hote.targets
  forward_to = [prometheus.remote_write.mimir.receiver]
}

prometheus.remote_write "mimir" {
  endpoint {
    url = "http://mimir:9009/api/v1/push"
  }
}

Vérifier la collecte #

Dans l'interface, la page du composant prometheus.scrape indique pour chaque cible son URL, son état (up ou down) et sa dernière erreur. La métrique prometheus_scrape_targets_gauge compte les cibles. Une cible down n'empêche pas le composant d'être healthy : surveillez aussi la série up.

3. Remote Write #

Envoi des données vers Grafana Cloud ou une instance locale.

Envoyer vers Mimir, Prometheus ou Grafana Cloud #

prometheus.remote_write envoie les métriques vers tout backend compatible. Il écrit d'abord dans un journal sur disque (WAL), puis expédie depuis ce journal : une panne du backend ne fait donc pas perdre les données immédiatement.

prometheus.remote_write "mimir" {
  external_labels = { region = "eu-west" }

  endpoint {
    url = "https://mimir.example.com/api/v1/push"

    basic_auth {
      username = sys.env("MIMIR_USER")
      password = sys.env("MIMIR_PASSWORD")
    }

    queue_config {
      capacity             = 10000
      max_shards           = 10
      max_samples_per_send = 2000
    }

    write_relabel_config {
      source_labels = ["__name__"]
      regex         = "up|node_.*"
      action        = "keep"
    }
  }

  wal {
    truncate_frequency = "2h"
    max_keepalive_time = "8h"
  }
}

Les réglages utiles #

RéglageRôleDéfaut
external_labelsÉtiquettes ajoutées à tout l’envoi–
queue_config.capacityÉchantillons en attente par shard10000
queue_config.max_shardsEnvois simultanés au maximum50
queue_config.max_samples_per_sendTaille d’un envoi2000
wal.truncate_frequencyFréquence de nettoyage du journal2h
wal.max_keepalive_timeConservation maximale, faute d’envoi8h
En cas de panne : les données sont conservées environ 8 heures par défaut, et le disque grossit pendant ce temps. Prévoyez l'espace pour --storage.path.

Filtrer par destination #

write_relabel_config filtre pour un seul backend. Nous l'avons mesuré en envoyant les mêmes données vers deux destinations : celle qui ne gardait que up et alloy_build_info a reçu 8 échantillons, l'autre 1765. C'est le moyen le plus simple de réduire une facture de stockage.

Superviser l'envoi #

# Échantillons qui n'arrivent pas à partir (à alerter)
rate(prometheus_remote_storage_samples_failed_total[5m]) > 0

# File d'attente vers le backend
prometheus_remote_storage_samples_pending

# Cibles collectées
prometheus_scrape_targets_gauge
Bonne pratique : mettez les mots de passe dans l'environnement ou un fichier (voir Gestion des secrets), et rendez --storage.path persistant : sans cela, le WAL disparaît au redémarrage du conteneur.

4. Interopérabilité OTLP #

Recevoir et transformer des métriques OpenTelemetry.

Le pont entre Prometheus et OTLP #

Alloy brille par sa capacité à unifier les écosystèmes. Avec les composants otelcol, Alloy peut agir comme un collecteur OpenTelemetry, recevant des métriques au format OTLP envoyées directement par vos applications instrumentées, les convertir à la volée, et les intégrer dans votre pipeline d'expédition Prometheus existant.

Articles liés

Alloy et l'écosystème Grafana Labs : quel composant pour quel outil ?

La carte des intégrations d'Alloy avec Faro, Beyla, k6, Loki, Mimir, Tempo, Pyroscope, Database Observability…

Faro et Alloy : recevoir le RUM front-end avec faro.receiver

Configurer faro.receiver : CORS, clé d'API, limite de débit, source maps, puis envoyer erreurs, Web Vitals et…

Beyla et Alloy : métriques RED et traces sans code avec beyla.ebpf

Activer l'instrumentation eBPF de Beyla dans Alloy : découverte des services, métriques RED vers Mimir, trace…

Pour aller plus loin

Soutenir

♥ SOUTENIR

Soutenez RousselTM Learning

Les formations, articles, TP et attestations restent gratuits et sans publicité intrusive. Une contribution libre, du montant de votre choix, finance l’hébergement, les environnements de TP et l’écriture de nouveaux contenus.

Contribuer avec PayPal Montant libre · carte bancaire ou compte PayPalEn savoir plus
QR code PayPal
Ou scannez ce QR code avec votre téléphone

Merci, chaque contribution compte !