Aller au contenu

Commandes Grafana Alloy

Grafana Alloy est une distribution OpenTelemetry flexible et neutre vis-à-vis des fournisseurs pour collecter, traiter et exporter des données de télémétrie (métriques, journaux, traces). Successeur de Grafana Agent, il utilise un langage de configuration basé sur les composants.

Installation

Référentiels de paquets Linux

Debian/Ubuntu

sudo mkdir -p /etc/apt/keyrings/
wget -qO - https://apt.grafana.com/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/grafana.gpg
echo "deb [signed-by=/etc/apt/keyrings/grafana.gpg] https://apt.grafana.com stable main" | sudo tee /etc/apt/sources.list.d/grafana.list
sudo apt-get update
sudo apt-get install alloy

RHEL/CentOS/Fedora

sudo tee /etc/yum.repos.d/grafana.repo << EOF
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://rpm.grafana.com/gpg.key
EOF
sudo dnf install alloy

macOS

brew install grafana/grafana/alloy
alloy --version

Téléchargement binaire

# Télécharger la dernière version
wget https://github.com/grafana/alloy/releases/download/v1.14.0/alloy-v1.14.0-linux-amd64.zip
unzip alloy-v1.14.0-linux-amd64.zip
sudo mv alloy /usr/local/bin/
alloy --version

Docker

docker pull grafana/alloy:latest
docker run -v /path/to/config.alloy:/etc/alloy/config.alloy \
  grafana/alloy:latest run /etc/alloy/config.alloy --server.http.listen-addr=0.0.0.0:12345

Graphique Helm

helm repo add grafana https://grafana.github.io/helm-charts
helm repo update
helm install alloy grafana/alloy --namespace monitoring --create-namespace \
  -f values.yaml

Commandes de base

CommandeDescription
alloy run config.alloyExécuter Alloy avec le fichier de configuration spécifié
alloy run config.alloy --server.http.listen-addr=0.0.0.0:12345Exécuter avec une adresse de serveur HTTP personnalisée
alloy fmt config.alloyFormater et valider le fichier de configuration (mode essai)
alloy fmt -w config.alloyFormater le fichier de configuration en place
alloy tools parse config.alloyAnalyser et valider la syntaxe de la configuration
alloy tools lint config.alloyLinter la configuration pour les problèmes
alloy --versionAfficher la version d’Alloy
alloy --helpAfficher l’aide
alloy run --helpAfficher les options de la commande run

Concepts de base de configuration

Extension de fichier et syntaxe

Alloy utilise l’extension de fichier .alloy avec un langage de configuration basé sur les composants (similaire à HCL).

Structure de base

// Les commentaires utilisent //

// Instanciation de composant : <component_type>.<unique_name> { ... }
prometheus.scrape "example" {
  targets = [{"__address__" = "localhost:9090"}]
  forward_to = [prometheus.remote_write.grafana.receiver]
}

// Exporter les données d'un composant à un autre
prometheus.remote_write "grafana" {
  endpoint {
    url = "https://prometheus.grafana.net/api/prom/push"
    headers = {
      "Authorization" = "Bearer ${GRAFANA_TOKEN}"
    }
  }
}

Variables et secrets

// Variables d'environnement
GRAFANA_TOKEN = env("GRAFANA_TOKEN")
PROMETHEUS_URL = env("PROMETHEUS_URL")

// Variables locales
local "my_targets" {
  value = [
    {"__address__" = "localhost:9090"},
    {"__address__" = "localhost:9100"},
  ]
}

// Références de variables
prometheus.scrape "nodes" {
  targets = local.my_targets.value
}

Blocs d’arguments et d’exportation

// La plupart des composants acceptent des arguments
prometheus.scrape "example" {
  targets    = [{"__address__" = "localhost:9090"}]
  scrape_interval = "30s"
  scrape_timeout  = "10s"
  forward_to = [prometheus.remote_write.grafana.receiver]
}

// Les composants exportent des données (visibles dans l'interface utilisateur sous Exports)
// Exemple : prometheus.scrape exporte scraped_targets et targets

Composants - Sources

Scrape Prometheus

prometheus.scrape "kubernetes" {
  targets    = discovery.kubernetes.nodes.targets
  scrape_interval = "30s"
  scrape_timeout  = "10s"
  metrics_path    = "/metrics"
  scheme          = "http"

  forward_to = [prometheus.relabel.drop_internal.receiver]
}

Source de fichier Loki

loki.source.file "app_logs" {
  targets = [
    {
      __path__ = "/var/log/app/*.log",
      job      = "app",
      env      = "production",
    }
  ]

  forward_to = [loki.relabel.add_labels.receiver]
}

Récepteur OpenTelemetry (OTLP)

otelcol.receiver.otlp "default" {
  grpc {
    endpoint = "0.0.0.0:4317"
  }

  http {
    endpoint = "0.0.0.0:4318"
  }

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

Récepteur Prometheus Remote Write

prometheus.receive_http "example" {
  http {
    address = "0.0.0.0:9009"
  }

  forward_to = [prometheus.relabel.example.receiver]
}

Serveur API Loki

loki.relabel "add_labels" {
  forward_to = [loki.write.grafana.receiver]

  rule {
    source_labels = ["__path__"]
    target_label  = "job"
    replacement   = "app-logs"
  }
}

Composants - Processeurs

Processeur batch

otelcol.processor.batch "default" {
  send_batch_size    = 1000
  timeout            = "10s"
  send_batch_max_size = 2000

  output {
    traces  = [otelcol.exporter.otlp.grafana.input]
    metrics = [otelcol.exporter.prometheus.grafana.input]
    logs    = [otelcol.exporter.loki.grafana.input]
  }
}

Processeur de filtre

otelcol.processor.filter "drop_internal" {
  metrics {
    exclude {
      match_type = "regexp"
      regexp     = "internal_.*"
    }
  }

  output {
    metrics = [otelcol.exporter.prometheus.grafana.input]
  }
}

Processeur de détection de ressources

otelcol.processor.resourcedetection "default" {
  detectors = ["env", "system", "gcp", "aws", "azure", "docker", "kubernetes"]

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

Processeur d’attributs

otelcol.processor.attributes "add_env" {
  action {
    key    = "environment"
    value  = "production"
    action = "insert"
  }

  action {
    key         = "pod_name"
    from_attribute = "k8s.pod.name"
    action      = "insert"
  }

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

Processeur de limiteur de mémoire

otelcol.processor.memory_limiter "default" {
  check_interval       = "5s"
  limit_mib            = 512
  spike_limit_mib      = 256

  output {
    traces  = [otelcol.processor.batch.default.input]
    metrics = [otelcol.processor.batch.default.input]
    logs    = [otelcol.processor.batch.default.input]
  }
}

Processeur d’étendue (traces)

otelcol.processor.span "extract_attributes" {
  name {
    to_attributes {
      rules = ["^/api/(?P<version>v\\d)/(?P<resource>\\w+)"]
    }
  }

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

Composants - Exportateurs

Prometheus Remote Write

prometheus.remote_write "grafana" {
  endpoint {
    url = "https://prometheus.grafana.net/api/prom/push"

    basic_auth {
      username = "GRAFANA_USER_ID"
      password = "${GRAFANA_TOKEN}"
    }

    headers = {
      "X-Custom-Header" = "value"
    }

    tls_config {
      insecure_skip_verify = false
    }
  }

  wal {
    enabled = true
    directory = "/var/lib/alloy/wal"
  }

  queue_settings {
    capacity = 10000
  }
}

Écriture Loki

loki.write "grafana" {
  endpoint {
    url = "https://logs.grafana.net/loki/api/v1/push"

    basic_auth {
      username = "GRAFANA_USER_ID"
      password = "${GRAFANA_TOKEN}"
    }
  }

  tenant_id = "production"
}

Exportateur OpenTelemetry (OTLP)

otelcol.exporter.otlp "grafana_cloud" {
  client {
    endpoint = "tempo.grafana.net:4317"

    auth = otelcol.auth.basic "grafana" {}

    tls {
      insecure = false
    }
  }

  retry_on_failure {
    enabled       = true
    initial_interval = "5s"
    max_interval  = "30s"
    max_elapsed_time = "5m"
  }
}

Authentification OTLP

otelcol.auth.basic "grafana" {
  username = "GRAFANA_USER_ID"
  password = "${GRAFANA_TOKEN}"
}

// OTLP avec authentification de base
otelcol.exporter.otlp "example" {
  client {
    endpoint = "tempo.grafana.net:4317"
    auth = otelcol.auth.basic.grafana.handler
  }
}

Exportateur Prometheus (style Node Exporter)

prometheus.exporter.unix "local_system" {
  disabled_collectors = ["netdev", "netstat"]
}

prometheus.scrape "local_system" {
  targets = prometheus.exporter.unix.local_system.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

Composants - Découverte

Découverte Kubernetes

discovery.kubernetes "cluster" {
  role = "pod"
  namespaces {
    names = ["default", "monitoring", "production"]
  }
}

prometheus.scrape "kubernetes" {
  targets    = discovery.kubernetes.cluster.targets
  forward_to = [prometheus.remote_write.grafana.receiver]

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

Découverte Docker

discovery.docker "local" {
  host = "unix:///var/run/docker.sock"
}

prometheus.scrape "docker" {
  targets    = discovery.docker.local.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

Découverte Consul

discovery.consul "example" {
  server   = "localhost:8500"
  datacenter = "dc1"
  services = ["prometheus", "app"]
}

prometheus.scrape "consul" {
  targets    = discovery.consul.example.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

Découverte basée sur fichier

discovery.file "dynamic_targets" {
  files = ["/etc/alloy/targets.json"]
  refresh_interval = "30s"
}

prometheus.scrape "file_targets" {
  targets    = discovery.file.dynamic_targets.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

Collecte de métriques

Scrape Prometheus avec relabeling

prometheus.scrape "prometheus" {
  targets = [
    {
      __address__ = "prometheus.example.com:9090",
      job         = "prometheus",
    },
    {
      __address__ = "alertmanager.example.com:9093",
      job         = "alertmanager",
    },
  ]

  metrics_path    = "/metrics"
  scrape_interval = "30s"
  scrape_timeout  = "10s"

  relabel_configurations {
    source_labels = ["__address__"]
    target_label  = "instance"
    regex         = "([^:]+)(?::\\d+)?"
    replacement   = "${1}"
  }

  metric_relabel_configurations {
    source_labels = ["__name__"]
    regex         = "up|job|instance"
    action        = "keep"
  }

  forward_to = [prometheus.relabel.drop_internal.receiver]
}

Intégration Node Exporter

prometheus.exporter.unix "node_metrics" {
  collectors = ["cpu", "diskstats", "filesystem", "loadavg", "meminfo", "netdev", "netstat"]
  disabled_collectors = ["netdev"]
  set_collectors = ["textfile"]
  textfile_directory = "/var/lib/node_exporter/textfile_collector"
}

prometheus.scrape "node_exporter" {
  targets    = prometheus.exporter.unix.node_metrics.targets
  forward_to = [prometheus.remote_write.grafana.receiver]
}

Point de terminaison de métriques personnalisé

prometheus.scrape "custom_app" {
  targets = [
    {
      __address__ = "app.example.com:8080",
      __metrics_path__ = "/api/metrics",
      job = "custom-app",
      env = "production",
    },
  ]

  scrape_interval = "15s"
  forward_to = [prometheus.remote_write.grafana.receiver]
}

Collecte de journaux

Suivi de fichiers avec Loki

loki.source.file "application" {
  targets = [
    {
      __path__ = "/var/log/app/app.log",
      job      = "app",
      service  = "web",
      env      = "production",
    },
    {
      __path__ = "/var/log/app/error.log",
      job      = "app",
      level    = "error",
    },
  ]

  forward_to = [loki.relabel.add_labels.receiver]
}

Journaux Journal (systemd)

loki.source.journal "systemd" {
  path   = "/var/log/journal"
  labels = {
    job = "systemd",
  }

  forward_to = [loki.relabel.add_labels.receiver]
}

Analyse des journaux JSON

loki.relabel "parse_json" {
  forward_to = [loki.process.extract_json.receiver]

  rule {
    source_labels = ["__path__"]
    target_label  = "filename"
  }
}

loki.process "extract_json" {
  forward_to = [loki.write.grafana.receiver]

  stage {
    json {
      expressions = {
        timestamp = "ts",
        message   = "msg",
        level     = "level",
        service   = "service",
      }
    }
  }

  stage {
    labels {
      values = {
        level   = "level",
        service = "service",
      }
    }
  }

  stage {
    timestamp {
      source = "timestamp"
      format = "Unix"
    }
  }
}

Journaux multilignes (traces de pile)

loki.process "multiline" {
  forward_to = [loki.write.grafana.receiver]

  stage {
    multiline {
      line_start_pattern = "^\\d{4}-\\d{2}-\\d{2}"
    }
  }

  stage {
    regex {
      expression = "^(?P<timestamp>\\d{4}-\\d{2}-\\d{2}) (?P<level>\\w+) (?P<message>.*)"
    }
  }

  stage {
    labels {
      values = {
        level = "level",
      }
    }
  }
}

Collecte de traces

Pipeline de traces OpenTelemetry

otelcol.receiver.otlp "app" {
  grpc {
    endpoint = "0.0.0.0:4317"
  }

  http {
    endpoint = "0.0.0.0:4318"
  }

  output {
    traces = [otelcol.processor.memory_limiter.default.input]
  }
}

otelcol.processor.memory_limiter "default" {
  check_interval  = "5s"
  limit_mib       = 512
  spike_limit_mib = 256

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

otelcol.processor.batch "default" {
  send_batch_size = 100
  timeout         = "10s"

  output {
    traces = [otelcol.exporter.otlp.grafana.input]
  }
}

otelcol.exporter.otlp "grafana" {
  client {
    endpoint = "tempo.grafana.net:4317"
    auth = otelcol.auth.basic.grafana.handler
  }
}

otelcol.auth.basic "grafana" {
  username = "GRAFANA_USER_ID"
  password = "${GRAFANA_TOKEN}"
}

Récepteur Jaeger

otelcol.receiver.jaeger "default" {
  protocols {
    grpc {
      endpoint = "0.0.0.0:14250"
    }

    thrift_http {
      endpoint = "0.0.0.0:14268"
    }
  }

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

Récepteur Zipkin

otelcol.receiver.zipkin "default" {
  endpoint = "0.0.0.0:9411"

  output {
    traces = [otelcol.processor.batch.default.input]
  }
}

Déploiement Kubernetes

Valeurs Helm (values.yaml)

config: |
  otelcol.receiver.otlp "default" {
    grpc {
      endpoint = "0.0.0.0:4317"
    }
    http {
      endpoint = "0.0.0.0:4318"
    }
    output {
      traces = [otelcol.processor.batch.default.input]
    }
  }

  otelcol.processor.batch "default" {
    send_batch_size = 100
    output {
      traces = [otelcol.exporter.otlp.grafana.input]
    }
  }

  otelcol.exporter.otlp "grafana" {
    client {
      endpoint = "tempo.grafana.net:4317"
      auth = otelcol.auth.basic.grafana.handler
    }
  }

  otelcol.auth.basic "grafana" {
    username = "GRAFANA_USER_ID"
    password = "${GRAFANA_TOKEN}"
  }

alloy:
  remoteConfigUrl: ""

serviceAccount:
  create: true

rbac:
  create: true

daemonset:
  enabled: true

deployment:
  enabled: true
  replicas: 1

configMap:
  content: ""

livenessProbe:
  enabled: true

readinessProbe:
  enabled: true

Installation Helm

# Installer avec des valeurs personnalisées
helm install alloy grafana/alloy \
  --namespace monitoring \
  --create-namespace \
  -f values.yaml

# Mettre à jour l'installation existante
helm upgrade alloy grafana/alloy \
  --namespace monitoring \
  -f values.yaml

# Désinstaller
helm uninstall alloy --namespace monitoring

Exemple DaemonSet

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: alloy
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: alloy
  template:
    metadata:
      labels:
        app: alloy
    spec:
      serviceAccountName: alloy
      containers:
      - name: alloy
        image: grafana/alloy:latest
        args:
        - run
        - /etc/alloy/config.alloy
        - --server.http.listen-addr=0.0.0.0:12345
        ports:
        - name: http
          containerPort: 12345
        - name: otlp-grpc
          containerPort: 4317
        - name: otlp-http
          containerPort: 4318
        volumeMounts:
        - name: config
          mountPath: /etc/alloy
        - name: varlog
          mountPath: /var/log
          readOnly: true
      volumes:
      - name: config
        configMap:
          name: alloy-config
      - name: varlog
        hostPath:
          path: /var/log
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: alloy-config
  namespace: monitoring
data:
  config.alloy: |
    prometheus.scrape "kubernetes" {
      targets = discovery.kubernetes.nodes.targets
      forward_to = [prometheus.remote_write.grafana.receiver]
    }

    discovery.kubernetes "nodes" {
      role = "node"
    }

    prometheus.remote_write "grafana" {
      endpoint {
        url = "https://prometheus.grafana.net/api/prom/push"
        basic_auth {
          username = "GRAFANA_USER_ID"
          password = "${GRAFANA_TOKEN}"
        }
      }
    }

Exemple ServiceMonitor

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: app-metrics
  namespace: production
spec:
  selector:
    matchLabels:
      app: myapp
  endpoints:
  - port: metrics
    interval: 30s
    path: /metrics

Configuration Docker

Fichier Compose

version: '3.8'
services:
  alloy:
    image: grafana/alloy:latest
    container_name: alloy
    command:
      - run
      - /etc/alloy/config.alloy
      - --server.http.listen-addr=0.0.0.0:12345
    ports:
      - "12345:12345"
      - "4317:4317"
      - "4318:4318"
    volumes:
      - ./alloy-config.alloy:/etc/alloy/config.alloy
      - /var/run/docker.sock:/var/run/docker.sock
      - /var/log:/var/log:ro
    environment:
      - GRAFANA_TOKEN=${GRAFANA_TOKEN}
    networks:
      - monitoring

  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
      - monitoring

networks:
  monitoring:
    driver: bridge

Exécuter un conteneur

# Exécuter avec le fichier de configuration
docker run -d \
  --name alloy \
  -v /path/to/config.alloy:/etc/alloy/config.alloy \
  -p 12345:12345 \
  -p 4317:4317 \
  -p 4318:4318 \
  -e GRAFANA_TOKEN=$GRAFANA_TOKEN \
  grafana/alloy:latest run /etc/alloy/config.alloy \
  --server.http.listen-addr=0.0.0.0:12345

# Afficher les journaux
docker logs -f alloy

# Arrêter le conteneur
docker stop alloy
docker rm alloy

Débogage

Accès à l’interface web

# Accéder à l'interface utilisateur d'Alloy (port par défaut 12345)
# Affiche l'état des composants, les exportations, les métriques
curl http://localhost:12345
# Navigateur : http://localhost:12345/graph

Niveaux de journalisation

# Exécuter avec journalisation de débogage
alloy run config.alloy --log.level=debug

# Exécuter avec journalisation d'info (par défaut)
alloy run config.alloy --log.level=info

# Exécuter avec journalisation d'avertissement
alloy run config.alloy --log.level=warn

Valider la configuration

# Analyser la configuration sans l'exécuter
alloy tools parse config.alloy

# Vérifier les erreurs de syntaxe
alloy fmt config.alloy

# Linter et valider
alloy tools lint config.alloy

Inspecter les composants

# Afficher tous les types de composants
alloy tools component list

# Obtenir la documentation des composants
alloy tools component doc prometheus.scrape

# Afficher le schéma des composants
alloy tools component schema prometheus.scrape

Profilage Pprof

# Activer le serveur pprof (par défaut : http://localhost:6060/debug/pprof)
alloy run config.alloy --pprof.enabled=true --pprof.address=0.0.0.0:6060

# Afficher le profil de tas
curl http://localhost:6060/debug/pprof/heap > heap.prof
go tool pprof heap.prof

# Afficher le profil de goroutine
curl http://localhost:6060/debug/pprof/goroutine

Inspection des traces

# Activer le traçage distribué
alloy run config.alloy --traces.enabled=true

# Accéder à l'interface de trace (si exposée)
curl http://localhost:12345/traces

Variables d’environnement

VariableDescription
ALLOY_CONFIG_FILEChemin d’accès au fichier de configuration
GRAFANA_TOKENJeton d’authentification pour Grafana Cloud
PROMETHEUS_URLPoint de terminaison du serveur Prometheus
LOKI_URLPoint de terminaison de l’API Loki
TEMPO_URLPoint de terminaison de l’API Tempo
OTEL_EXPORTER_OTLP_ENDPOINTPoint de terminaison de l’exportateur OpenTelemetry OTLP
OTEL_EXPORTER_OTLP_HEADERSEn-têtes de l’exportateur OTLP
OTEL_SDK_DISABLEDDésactiver le SDK OpenTelemetry
LOG_LEVELNiveau de journalisation : debug, info, warn, error
ALLOY_REMOTE_CONFIG_URLURL de configuration à distance
NODE_NAMEIdentificateur de nœud (nom de nœud k8s)
POD_NAMENom du pod (pour k8s)
NAMESPACEEspace de noms Kubernetes

Utilisation des variables d’environnement

# Exporter des variables
export GRAFANA_TOKEN="glc_xxx"
export PROMETHEUS_URL="https://prometheus.grafana.net"

# Exécuter Alloy
alloy run config.alloy

# Dans config.alloy, référencer avec ${ }
prometheus.remote_write "grafana" {
  endpoint {
    url = "${PROMETHEUS_URL}/api/prom/push"
    basic_auth {
      password = "${GRAFANA_TOKEN}"
    }
  }
}

Ressources