DevOps and Infrastructure

Création d'exportateurs Prometheus personnalisés pour les systèmes hérités

L'infrastructure moderne repose fortement sur les métriques, mais une part significative des fonctionnalités critiques des entreprises s'exécute encore sur des applications héritées. Ces systèmes, souvent conçus il y a des décennies, sont fréquemment opaques et dépourvus de points de terminaison API natifs pour les outils d'observabilité modernes. Ce fossé crée des angles morts qui peuvent entraîner des pannes inattendues et une dégradation des performances. Dans ce guide, nous explorerons comment combler ce vide en construisant des exportateurs Prometheus personnalisés. En enveloppant la logique héritée dans une couche de métriques, vous pouvez exposer des indicateurs de santé vitaux à vos tableaux de bord Grafana et Prometheus existants sans modifier le code de l'application principale.

Comprendre le modèle d'exportateur

Un exportateur Prometheus est un service distinct qui expose des métriques dans un format que Prometheus peut extraire. Contrairement à l'application elle-même, qui peut être écrite en COBOL, Delphi ou dans une version obsolète de Java, l'exportateur agit comme un fin wrapper. Il interagit avec le système hérité via des interfaces disponibles — telles que SNMP, des API HTTP ou des requêtes de base de données — et traduit ces réponses dans un format d'exposition compatible avec Prometheus.

Cette séparation des responsabilités est cruciale. Elle vous permet de gérer la santé de l'application héritée indépendamment de la logique de l'application. Si l'exportateur échoue, votre pile de surveillance reste stable. Si l'application héritée échoue, l'exportateur signale simplement des états nuls ou d'erreur, alertant votre équipe avant que les utilisateurs ne le remarquent.

Choisir le bon langage

Lors de la création d'un exportateur, le choix du langage de programmation dicte souvent la facilité de maintenance et les performances. Deux langages dominent cet espace : Go et Python.

Go est la norme industrielle pour écrire des exportateurs. La bibliothèque officielle prometheus/client_golang est robuste, fortement typée et se compile en un seul binaire statique, ce qui rend le déploiement trivial dans les environnements conteneurisés. Elle est très performante et gère bien la concurrence.

Python est excellent pour le prototypage rapide, surtout si votre équipe maîtrise déjà des bibliothèques de manipulation de données comme Pandas pour l'agrégation des métriques. Le package prometheus_client est simple à utiliser mais peut être plus lent dans des scénarios à haut débit.

Exemple d'implémentation avec Go

Regardons un exemple pratique utilisant Go. Supposons que vous ayez une base de données d'inventaire héritée qui stocke les niveaux de stock. Vous souhaitez exposer le nombre d'articles en stock faible. Voici comment vous pourriez structurer l'exportateur :

package main

import (
    "log"
    "net/http"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

// LowStockCollector implémente l'interface prometheus.Collector.
type LowStockCollector struct {
    LowStockCount *prometheus.Desc
}

// NewLowStockCollector initialise un nouveau collecteur.
func NewLowStockCollector() *LowStockCollector {
    return &LowStockCollector{
        LowStockCount: prometheus.NewDesc(
            "legacy_inventory_low_stock",
            "Nombre d'articles en stock faible dans la base de données héritée",
            nil, nil,
        ),
    }
}

// Describe envoie les descripteurs de chaque Métrique liée à ce collecteur.
func (c *LowStockCollector) Describe(ch chan<- *prometheus.Desc) {
    ch <- c.LowStockCount
}

// Collect est appelée par le registre Prometheus lors de la collecte des métriques.
func (c *LowStockCollector) Collect(ch chan<- prometheus.Metric) {
    // Simule la récupération des données du système hérité
    count := fetchLowStockCountFromLegacyDB()
    ch <- prometheus.MustNewConstMetric(
        c.LowStockCount,
        prometheus.GaugeValue,
        float64(count),
    )
}

func main() {
    registry := prometheus.NewRegistry()
    collector := NewLowStockCollector()
    registry.MustRegister(collector)

    http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
    log.Fatal(http.ListenAndServe(":9100", nil))
}

func fetchLowStockCountFromLegacyDB() int {
    // La logique pour interroger la base de données héritée va ici
    return 42
}

Dans cet exemple, nous définissons un collecteur personnalisé qui implémente les méthodes Describe et Collect. La méthode Collect est l'endroit où vous interagissez avec le système hérité. En exposant cela sur /metrics, Prometheus peut extraire les données sans avoir besoin de modifier l'application héritée.

Gérer l'authentification et la sécurité

Les systèmes hérités manquent souvent de mécanismes d'authentification modernes. Cependant, l'exportateur lui-même doit être sécurisé. Puisque l'exportateur est un service distinct, vous pouvez le placer derrière un proxy inverse comme Nginx ou Apache, en ajoutant une authentification de base ou mTLS. Cela garantit que même si l'interface héritée n'est pas sécurisée, le point de terminaison des métriques reste protégé contre tout accès non autorisé.

Conclusion

Étendre l'observabilité aux applications héritées n'est pas seulement une nécessité technique ; c'est un impératif commercial. En construisant des exportateurs Prometheus personnalisés, vous gagnez en visibilité sur des systèmes qui resteraient autrement des boîtes noires. Que vous choisissiez Go pour la performance ou Python pour la simplicité, l'essentiel est de garder l'exportateur léger et focalisé. Cette approche vous permet de moderniser progressivement votre pile de surveillance tout en maintenant la stabilité de votre infrastructure critique héritée. Commencez petit, exposez une métrique, et développez à partir de là.

Share: