Aller au contenu
medium

02 — Prometheus : métriques et PromQL

38 min de lecture

Ce module est le cœur de la formation. Prometheus est le standard de facto pour les métriques sur Kubernetes. Vous allez l’installer, comprendre son fonctionnement en profondeur, et surtout maîtriser PromQL — le langage de requête qui fait toute la puissance de Prometheus.

Pourquoi ce module est-il le plus long ? Parce que Prometheus est la fondation de tout le reste. Sans une bonne compréhension de Prometheus et PromQL, vous ne pourrez pas créer des dashboards efficaces dans Grafana, ni des alertes pertinentes avec Alertmanager.

À la fin de ce module, vous saurez :

  1. Expliquer comment Prometheus collecte et stocke les métriques (architecture pull)
  2. Installer Prometheus sur Kubernetes avec Helm
  3. Configurer le scraping automatique des pods et services
  4. Distinguer les 4 types de métriques (counter, gauge, histogram, summary)
  5. Écrire des requêtes PromQL de base à intermédiaires
  6. Créer des recording rules pour optimiser les performances
  7. Diagnostiquer les problèmes courants (targets down, high cardinality)

Avant de continuer, vérifiez que vous avez terminé les modules précédents :

  1. Le cluster Minikube tourne

    Ouvrez un terminal et tapez :

    Fenêtre de terminal
    minikube status

    Ce que vous devez voir :

    minikube
    type: Control Plane
    host: Running
    kubelet: Running
    apiserver: Running
    kubeconfig: Configured

    Si ce n’est pas le cas, démarrez Minikube :

    Fenêtre de terminal
    minikube start --memory=10240 --cpus=4
  2. L’application OpenTelemetry Demo est déployée

    Fenêtre de terminal
    kubectl get pods -n otel-demo

    Ce que vous devez voir : de nombreux pods (~25) en status Running.

    Si ce n’est pas le cas, retournez au module 01.

  3. Le namespace observability existe

    Fenêtre de terminal
    kubectl get ns observability

    Si le namespace n’existe pas :

    Fenêtre de terminal
    kubectl create namespace observability
  4. Le repo Helm prometheus-community est ajouté

    Fenêtre de terminal
    helm repo list | grep prometheus

    Ce que vous devez voir : une ligne contenant prometheus-community.

    Si ce n’est pas le cas :

    Fenêtre de terminal
    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
    helm repo update

Avant d’installer quoi que ce soit, comprenons pourquoi Prometheus fonctionne comme il fonctionne. Cette compréhension vous évitera beaucoup de confusion plus tard.

Le modèle “Pull” — une différence fondamentale

Section intitulée « Le modèle “Pull” — une différence fondamentale »

La plupart des systèmes de monitoring traditionnels (Graphite, StatsD, InfluxDB) fonctionnent en mode push : vos applications envoient leurs métriques vers le serveur de monitoring.

Prometheus fait l’inverse. Il fonctionne en mode pull : c’est Prometheus qui va chercher les métriques sur vos applications.

Pourquoi ce choix ?

Push (traditionnel)Pull (Prometheus)
L’application doit connaître l’adresse du serveurL’application expose juste un endpoint, elle ne sait rien de Prometheus
Si le serveur est down, les métriques sont perduesSi Prometheus est down, il reprendra le scraping au redémarrage
Difficile de tester localementFacile de tester : curl http://localhost:8080/metrics
Nécessite une configuration côté applicationConfiguration centralisée dans Prometheus

Analogie : Imaginez un journal papier. En mode push, chaque journaliste enverrait son article par courrier à l’imprimerie. En mode pull, un coursier (Prometheus) passe régulièrement chez chaque journaliste pour récupérer les articles. Si un journaliste est absent, le coursier réessaiera plus tard.

L’endpoint /metrics — ce que Prometheus collecte

Section intitulée « L’endpoint /metrics — ce que Prometheus collecte »

Chaque application que Prometheus surveille doit exposer un endpoint HTTP /metrics qui retourne du texte dans un format spécifique.

Voyons un exemple concret. Prometheus lui-même expose ses propres métriques. Une fois installé, vous pourrez les consulter :

Fenêtre de terminal
# Port-forward vers Prometheus
kubectl port-forward svc/prometheus-server 9090:80 -n observability

Dans un autre terminal :

Fenêtre de terminal
curl http://localhost:9090/metrics 2>/dev/null | head -30

Ce que vous devez voir — quelque chose comme :

# HELP prometheus_engine_query_duration_seconds Query timings
# TYPE prometheus_engine_query_duration_seconds summary
prometheus_engine_query_duration_seconds{slice="inner_eval",quantile="0.5"} 0.000012
prometheus_engine_query_duration_seconds{slice="inner_eval",quantile="0.9"} 0.000025
# HELP prometheus_tsdb_head_chunks Total number of chunks in the head block.
# TYPE prometheus_tsdb_head_chunks gauge
prometheus_tsdb_head_chunks 1234

Décortiquons ce format :

ÉlémentSignification
# HELP ...Documentation humaine de la métrique
# TYPE ...Type de métrique (counter, gauge, histogram, summary)
prometheus_tsdb_head_chunksNom de la métrique
{slice="inner_eval",...}Labels (dimensions)
1234Valeur actuelle

Fermez le port-forward (Ctrl+C) avant de continuer.

Maintenant que vous comprenez le modèle pull et le format des métriques, voici l’architecture complète :

Architecture de Prometheus

Les composants expliqués :

ComposantCe qu’il faitAnalogie
RetrievalVa chercher les métriques sur chaque target toutes les 15 secondesLe coursier qui passe régulièrement
Service DiscoveryDécouvre automatiquement les nouveaux pods/services dans KubernetesLe GPS du coursier
TSDBStocke les séries temporelles de manière efficace sur disqueL’archive où tous les articles sont classés
HTTP ServerPermet d’interroger les données via l’interface web et l’APILa salle de lecture de l’archive
Rule EvaluationÉvalue les règles d’alerte et les recording rulesLe rédacteur en chef qui vérifie si quelque chose d’anormal se passe

Maintenant que vous comprenez comment Prometheus fonctionne, installons-le.

  1. Positionnez-vous dans le répertoire du lab

    Fenêtre de terminal
    cd ~/lab-observability
  2. Examinez la configuration Helm

    Avant d’installer, regardons ce qu’on va déployer :

    Fenêtre de terminal
    cat 02-prometheus/helm-values/prometheus-minimal.yaml

    Ce que vous voyez — les points importants :

    server:
    retention: "7d" # Garder les données 7 jours
    persistentVolume:
    size: 8Gi # 8 Go de stockage
    service:
    type: NodePort
    nodePort: 30090 # Accessible sur ce port
    # Activer les métriques Kubernetes
    kubeStateMetrics:
    enabled: true # Métriques sur l'état des objets K8s
    nodeExporter:
    enabled: true # Métriques système des nodes
    # Scraper l'OpenTelemetry Collector (installé dans otel-demo au module 01)
    extraScrapeConfigs: |
    - job_name: 'otel-collector'
    metrics_path: /metrics
    static_configs:
    - targets: ['otel-collector.otel-demo.svc.cluster.local:8889']

    Cette configuration :

    • Installe Prometheus avec 7 jours de rétention
    • Active Node Exporter (métriques CPU, RAM, disque des nodes)
    • Active kube-state-metrics (métriques sur les pods, deployments, etc.)
    • Scrape l’OpenTelemetry Collector (namespace otel-demo) pour récupérer les métriques otel_* de l’application
  3. Installez Prometheus

    Fenêtre de terminal
    helm upgrade --install prometheus prometheus-community/prometheus \
    -n observability \
    -f 02-prometheus/helm-values/prometheus-minimal.yaml \
    --wait

    Ce que vous devez voir :

    Release "prometheus" does not exist. Installing it now.
    NAME: prometheus
    LAST DEPLOYED: ...
    NAMESPACE: observability
    STATUS: deployed
    ...

    L’option --wait fait que Helm attend que tous les pods soient prêts avant de rendre la main. Cela peut prendre 1-2 minutes.

  4. Vérifiez que tout tourne

    Fenêtre de terminal
    kubectl get pods -n observability | grep -E 'prometheus-server|kube-state-metrics|node-exporter'

    Ce que vous devez voir :

    prometheus-kube-state-metrics-xxx 1/1 Running 0 2m
    prometheus-prometheus-node-exporter-xxx 1/1 Running 0 2m
    prometheus-server-xxxxxxxxxx-xxxxx 2/2 Running 0 2m

    Tous les pods doivent être en Running.

    Si le pod n’est pas ready après 3 minutes, consultez les logs :

    Fenêtre de terminal
    kubectl logs -n observability -l app.kubernetes.io/name=prometheus -c prometheus-server --tail=50
  5. Accédez à l’interface Prometheus

    Il y a deux méthodes :

    Méthode 1 — NodePort (recommandée pour Minikube) :

    Fenêtre de terminal
    minikube service prometheus-server -n observability --url

    Copiez l’URL affichée et ouvrez-la dans votre navigateur.

    Méthode 2 — Port-forward :

    Fenêtre de terminal
    kubectl port-forward svc/prometheus-server 9090:80 -n observability

    Puis ouvrez http://localhost:9090

Vous devez maintenant voir l’interface web de Prometheus — une page avec un champ de requête en haut et plusieurs onglets (Graph, Alerts, Status…).

Avant d’écrire des requêtes, faisons le tour de l’interface pour comprendre ce que Prometheus nous montre.

Interface de Prometheus

Cliquez sur Status dans le menu du haut, puis Targets.

Cette page est la plus importante pour le dépannage. Elle montre toutes les cibles que Prometheus scrape, avec leur état.

Ce que vous devez voir :

JobTargetsÉtat attendu
kubernetes-apiservers1🟢 UP
kubernetes-nodes1 (Minikube n’a qu’un node)🟢 UP
kubernetes-nodes-cadvisor1🟢 UP
kubernetes-service-endpointsVariable🟢 UP (la plupart)
prometheus1🟢 UP
otel-collector1🟢 UP

Comment lire cette page :

  • 🟢 UP (vert) : Prometheus scrape avec succès
  • 🔴 DOWN (rouge) : Le scraping échoue
  • Last Scrape : Quand le dernier scrape a eu lieu
  • Scrape Duration : Combien de temps le scrape a pris
  • Error : Si DOWN, le message d’erreur

Cliquez sur Status → Configuration.

Vous voyez la configuration YAML complète de Prometheus. C’est utile pour vérifier que vos scrape configs ont bien été appliqués.

Cherchez la section scrape_configs et vérifiez les jobs présents (kubernetes-nodes, kubernetes-service-endpoints, prometheus…).

Cliquez sur Graph.

C’est ici que vous passerez le plus de temps. Le champ en haut permet d’écrire des requêtes PromQL.

Première requête — testez que tout fonctionne :

Tapez dans le champ de requête :

up

Cliquez sur Execute.

Ce que vous devez voir :

Une liste de lignes, chacune avec :

  • Des labels entre {} (job, instance, namespace…)
  • Une valeur : 1 (UP) ou 0 (DOWN)

Cette métrique spéciale up est créée automatiquement par Prometheus pour chaque target. Elle vaut 1 si le dernier scrape a réussi, 0 sinon.

Passez en vue graphique :

Cliquez sur l’onglet Graph (sous le champ de requête, pas dans le menu).

Vous voyez maintenant l’évolution de la métrique dans le temps. Comme up vaut généralement 1, vous verrez des lignes horizontales.

Les 4 types de métriques — comprendre avant de requêter

Section intitulée « Les 4 types de métriques — comprendre avant de requêter »

Avant d’apprendre PromQL, vous devez absolument comprendre les 4 types de métriques. Chaque type s’utilise différemment, et confondre les types est l’erreur n°1 des débutants.

Un counter est une valeur qui ne fait qu’augmenter (ou redémarre à 0 quand l’application redémarre).

Exemples concrets :

  • Nombre total de requêtes HTTP reçues
  • Nombre total d’erreurs
  • Nombre total de bytes transférés
  • Nombre total de connexions ouvertes (cumulatif)

Analogie : C’est comme le compteur kilométrique de votre voiture. Il augmente toujours, il ne diminue jamais. Si vous voulez savoir à quelle vitesse vous roulez, vous ne regardez pas le compteur brut — vous calculez la différence sur une période.

Erreur classique — utiliser un counter brut :

# ❌ MAUVAIS — la valeur brute n'est pas interprétable
http_requests_total
# Cette requête retourne par exemple 123456, 123789, 124012...
# Ces nombres ne vous disent rien d'utile !

La bonne façon — utiliser rate() :

# ✅ BON — taux de requêtes par seconde sur les 5 dernières minutes
rate(http_requests_total[5m])
# Cette requête retourne par exemple 12.5, 13.2, 11.8...
# = 12.5 requêtes par seconde, bien plus utile !

Exercice pratique — exécutez ces requêtes dans Prometheus :

# 1. Valeur brute (regardez, c'est un nombre qui augmente)
prometheus_http_requests_total
# 2. Taux par seconde (maintenant c'est exploitable)
rate(prometheus_http_requests_total[5m])
# 3. Augmentation totale sur la dernière heure
increase(prometheus_http_requests_total[1h])

Un gauge est une valeur qui peut monter et descendre librement.

Exemples concrets :

  • Mémoire actuellement utilisée
  • Température actuelle
  • Nombre de connexions actuellement ouvertes
  • Nombre de tâches dans une file d’attente

Analogie : C’est comme le thermomètre ou la jauge d’essence de votre voiture. La valeur fluctue en fonction de l’état actuel.

Utilisation — la valeur brute est directement exploitable :

# ✅ Mémoire disponible sur les nodes (en bytes)
node_memory_MemAvailable_bytes
# ✅ Convertir en GB pour plus de lisibilité
node_memory_MemAvailable_bytes / 1024 / 1024 / 1024
# ✅ Pourcentage de mémoire utilisée
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

Exercice pratique — exécutez ces requêtes :

# 1. Mémoire disponible
node_memory_MemAvailable_bytes
# 2. En gigabytes (plus lisible)
node_memory_MemAvailable_bytes / 1024 / 1024 / 1024
# 3. Pourcentage de mémoire utilisée (le calcul complet)
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100

Ce que vous devez voir : Un pourcentage entre 0 et 100. Sur Minikube, c’est probablement entre 30% et 70%.

Histogram — pour les distributions et percentiles

Section intitulée « Histogram — pour les distributions et percentiles »

Un histogram mesure la distribution d’une valeur, typiquement des durées (latence).

Pourquoi un histogram et pas un simple moyenne ?

Imaginez un service web. La moyenne de latence est 100ms. Ça semble bien. Mais si 99% des requêtes prennent 10ms et 1% prennent 10 secondes, la moyenne cache un gros problème — 1% de vos utilisateurs ont une expérience horrible.

Les histograms permettent de calculer des percentiles :

  • P50 (médiane) : 50% des requêtes sont plus rapides que cette valeur
  • P90 : 90% des requêtes sont plus rapides
  • P99 : 99% des requêtes sont plus rapides (important pour détecter les outliers)

Comment ça fonctionne ?

Un histogram stocke les valeurs dans des “buckets” (tranches) :

# Requêtes avec durée <= 5ms : 100
# Requêtes avec durée <= 10ms : 250
# Requêtes avec durée <= 25ms : 400
# Requêtes avec durée <= 50ms : 450
# Requêtes avec durée <= 100ms : 480
# Requêtes avec durée <= +Inf : 500

Prometheus peut alors calculer : “99% des requêtes (495) ont pris moins de X ms”.

Utilisation — calculer un percentile :

# P99 de la latence des requêtes HTTP Prometheus (99% des requêtes sont plus rapides que cette valeur)
histogram_quantile(
0.99,
rate(prometheus_http_request_duration_seconds_bucket[5m])
)

Décortiquons cette requête :

  1. prometheus_http_request_duration_seconds_bucket : les données brutes du histogram
  2. rate(...[5m]) : on calcule le taux par seconde (obligatoire pour les histograms)
  3. histogram_quantile(0.99, ...) : on calcule le percentile 99

Exercice pratique :

# P50 (médiane) — la moitié des requêtes sont plus rapides
histogram_quantile(
0.50,
rate(prometheus_http_request_duration_seconds_bucket[5m])
)
# P90 — 90% des requêtes sont plus rapides
histogram_quantile(
0.90,
rate(prometheus_http_request_duration_seconds_bucket[5m])
)
# P99 — 99% des requêtes sont plus rapides (détecte les outliers)
histogram_quantile(
0.99,
rate(prometheus_http_request_duration_seconds_bucket[5m])
)

Ce que vous devez voir : Des valeurs en secondes. Le P99 devrait être plus élevé que le P50.

Summary — percentiles pré-calculés (à éviter)

Section intitulée « Summary — percentiles pré-calculés (à éviter) »

Un summary ressemble à un histogram mais les percentiles sont calculés côté application, pas par Prometheus.

Différences avec les histograms :

AspectHistogramSummary
Calcul des percentilesPar Prometheus (flexible)Par l’application (fixe)
Agrégation possibleOuiNon (les percentiles ne s’additionnent pas)
Recommandation✅ Préféré⚠️ À éviter si possible

Pourquoi éviter les summaries ?

Si vous avez 10 pods et que chacun calcule son P99, vous ne pouvez pas calculer le P99 global correct. Les percentiles ne s’additionnent pas mathématiquement.

Avec les histograms, Prometheus peut calculer le P99 global à partir des buckets agrégés.

Exemple de summary (juste pour reconnaître le format) :

http_request_duration_seconds{quantile="0.99"}
http_request_duration_seconds{quantile="0.5"}

Maintenant que vous comprenez les types de métriques, apprenons PromQL en pratiquant.

L’unité de base en PromQL est le sélecteur. Il permet de récupérer des séries temporelles.

Sélecteur simple — toutes les séries d’une métrique :

prometheus_http_requests_total

Exécutez cette requête. Vous voyez toutes les séries avec cette métrique, chacune avec ses labels (code, handler, job…).

Filtrer par label (égalité) :

prometheus_http_requests_total{code="200"}

Maintenant vous ne voyez que les requêtes avec un code 200.

Filtrer par label (regex) :

# Seulement les handlers qui commencent par /api
prometheus_http_requests_total{handler=~"/api.*"}
# Tout sauf les 200
prometheus_http_requests_total{code!="200"}
# Tous les codes 5xx (regex)
prometheus_http_requests_total{code=~"5.."}

Combiner des filtres :

prometheus_http_requests_total{handler="/metrics", code="200"}

Résumé des opérateurs de matching :

OpérateurSignificationExemple
=Égalcode="200"
!=Différentcode!="200"
=~Correspond au regexcode=~"5.."
!~Ne correspond pas au regexhandler!~"/health.*"

Voici les fonctions que vous utiliserez 80% du temps :

# Requêtes HTTP par seconde (sur les 5 dernières minutes)
rate(prometheus_http_requests_total[5m])

Le [5m] est une “range vector”. Il dit à Prometheus de regarder les 5 dernières minutes de données pour calculer le taux.

Quelle fenêtre choisir ?

FenêtreUsage
[1m]Très réactif, peut être bruité
[5m]Bon compromis (le plus courant)
[15m]Lissé, masque les pics courts
[1h]Vue très lissée

Exercice — comparez les résultats avec différentes fenêtres :

rate(prometheus_http_requests_total[1m])
rate(prometheus_http_requests_total[5m])
rate(prometheus_http_requests_total[15m])

Passez en vue Graph et observez : la courbe avec [1m] est plus “nerveuse”, celle avec [15m] est plus lisse.

Sans agrégation, rate() retourne une série par combinaison de labels. C’est souvent trop détaillé.

# AVANT — une série par handler, par code...
rate(prometheus_http_requests_total[5m])
# APRÈS — une seule valeur : le total de toutes les requêtes
sum(rate(prometheus_http_requests_total[5m]))

Agréger par certains labels — avec by :

# Total par code HTTP
sum by (code) (rate(prometheus_http_requests_total[5m]))
# Total par handler
sum by (handler) (rate(prometheus_http_requests_total[5m]))
# Total par code ET par handler
sum by (code, handler) (rate(prometheus_http_requests_total[5m]))

Exclure certains labels — avec without :

# Tout sauf le label "instance" (utile quand vous avez plusieurs pods)
sum without (instance) (rate(prometheus_http_requests_total[5m]))
# Moyenne de l'utilisation mémoire par node
avg by (instance) (node_memory_MemAvailable_bytes)
# Maximum de la latence P99
max(histogram_quantile(0.99, rate(prometheus_http_request_duration_seconds_bucket[5m])))
# Minimum par handler
min by (handler) (rate(prometheus_http_requests_total[5m]))
# Combien de targets sont surveillés ?
count(up)
# Combien de targets sont UP ?
count(up == 1)
# Combien de pods dans le namespace observability ?
count(kube_pod_info{namespace="observability"})
# Les 5 handlers avec le plus de requêtes
topk(5, sum by (handler) (rate(prometheus_http_requests_total[5m])))
# Les 3 handlers avec le moins de requêtes
bottomk(3, sum by (handler) (rate(prometheus_http_requests_total[5m])))

Arithmétique — pour calculer des ratios, des pourcentages :

# Mémoire utilisée (total - disponible)
node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes
# Pourcentage de mémoire utilisée
(node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes * 100
# Taux d'erreur en pourcentage
sum(rate(prometheus_http_requests_total{code=~"5.."}[5m]))
/
sum(rate(prometheus_http_requests_total[5m]))
* 100

Comparaison — pour filtrer les résultats :

# Seulement les targets DOWN
up == 0
# Handlers avec plus de 0.1 req/s
sum by (handler) (rate(prometheus_http_requests_total[5m])) > 0.1
# Utilisation mémoire > 80%
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.8

Ces exercices vous permettent de valider votre compréhension. Faites-les dans l’ordre.

Objectif : Vérifier l’état de santé de votre infrastructure.

  1. Comptez tous les targets

    count(up)

    Ce que vous devez voir : Un nombre (probablement entre 10 et 20).

  2. Comptez les targets UP

    count(up == 1)
  3. Comptez les targets DOWN

    count(up == 0)

    Ce que vous devez voir : Idéalement 0. Si ce n’est pas 0, notez quels targets sont DOWN.

  4. Listez les targets DOWN

    up == 0

    Cette requête retourne les séries avec leurs labels, vous pouvez identifier quel service pose problème.

Objectif : Comprendre comment calculer l’utilisation CPU.

  1. Affichez le temps CPU idle

    node_cpu_seconds_total{mode="idle"}

    C’est un counter : le nombre total de secondes passées en idle.

  2. Calculez le taux de temps idle par seconde

    rate(node_cpu_seconds_total{mode="idle"}[5m])

    Cela retourne une valeur proche de 1 (1 seconde d’idle par seconde = 100% idle).

  3. Moyennez sur tous les cores

    avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))
  4. Convertissez en pourcentage d’utilisation

    100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

    Ce que vous devez voir : Un pourcentage entre 0 et 100. C’est l’utilisation CPU de votre node Minikube.

Objectif : Mesurer le trafic HTTP de Prometheus.

  1. Total de requêtes par seconde

    sum(rate(prometheus_http_requests_total[5m]))

    Ce que vous devez voir : Un nombre (ex: 0.5 = 0.5 requêtes par seconde sur l’API Prometheus).

  2. Requêtes par handler

    sum by (handler) (rate(prometheus_http_requests_total[5m]))

    Passez en vue Graph. Vous voyez quels endpoints Prometheus sont les plus sollicités.

  3. Requêtes par code de statut HTTP

    sum by (code) (rate(prometheus_http_requests_total[5m]))

    Idéalement, la majorité devrait être en 200.

  4. Pourcentage d’erreurs (5xx)

    sum(rate(prometheus_http_requests_total{code=~"5.."}[5m]))
    /
    sum(rate(prometheus_http_requests_total[5m]))
    * 100

    Ce que vous devez voir : Un pourcentage. Si c’est supérieur à 1%, vous avez un problème.

Objectif : Calculer les percentiles de latence.

  1. P50 global (médiane)

    histogram_quantile(
    0.50,
    sum(rate(prometheus_http_request_duration_seconds_bucket[5m])) by (le)
    )

    Note : by (le) est obligatoire car histogram_quantile a besoin des buckets.

  2. P99 global

    histogram_quantile(
    0.99,
    sum(rate(prometheus_http_request_duration_seconds_bucket[5m])) by (le)
    )
  3. P99 par handler

    histogram_quantile(
    0.99,
    sum by (handler, le) (rate(prometheus_http_request_duration_seconds_bucket[5m]))
    )

    Ce que vous devez voir : Une latence en secondes pour chaque handler.

  4. Identifiez le handler le plus lent

    topk(1,
    histogram_quantile(
    0.99,
    sum by (handler, le) (rate(prometheus_http_request_duration_seconds_bucket[5m]))
    )
    )

Objectif : Créer un indicateur de niveau de service (SLI) simple.

Un SLI courant : “Pourcentage de requêtes réussies avec une latence acceptable”.

  1. Définissez “latence acceptable” = moins de 500ms

    On compte les requêtes dans le bucket <= 0.5s :

    sum(rate(prometheus_http_request_duration_seconds_bucket{le="0.5"}[5m]))
  2. Comparez au total des requêtes

    sum(rate(prometheus_http_request_duration_seconds_bucket{le="0.5"}[5m]))
    /
    sum(rate(prometheus_http_request_duration_seconds_count[5m]))
    * 100

    Ce que vous devez voir : Un pourcentage. “X% des requêtes ont une latence < 500ms”.

  3. Ajoutez le critère “pas d’erreur”

    (
    sum(rate(prometheus_http_request_duration_seconds_bucket{le="0.5", code!~"5.."}[5m]))
    /
    sum(rate(prometheus_http_request_duration_seconds_count[5m]))
    ) * 100

    C’est votre SLI : ”% de requêtes réussies en moins de 500ms”.

Configuration du scraping — comment Prometheus découvre les targets

Section intitulée « Configuration du scraping — comment Prometheus découvre les targets »

Vous vous demandez peut-être comment Prometheus sait quels pods scraper. C’est le Service Discovery Kubernetes.

Le mécanisme d’annotations (culture générale)

Section intitulée « Le mécanisme d’annotations (culture générale) »

Dans certains clusters Kubernetes, Prometheus peut scraper automatiquement les pods via des annotations. C’est un pattern courant hors de ce cours :

# Ce que notre configuration fait automatiquement
# Pour chaque pod avec l'annotation prometheus.io/scrape: "true"
# Prometheus va scraper l'endpoint /metrics

Pour qu’un pod soit scrapé automatiquement via annotations, il doit avoir :

apiVersion: v1
kind: Pod
metadata:
name: mon-app
annotations:
prometheus.io/scrape: "true" # Active le scraping
prometheus.io/port: "8080" # Port de l'endpoint /metrics
prometheus.io/path: "/metrics" # Chemin (par défaut /metrics)
SourceMétriquesComment
Node Exporternode_* (CPU, RAM, disque)Via service discovery Kubernetes
kube-state-metricskube_* (pods, deployments)Via service discovery Kubernetes
cAdvisorcontainer_* (conteneurs)Via kubelet
OTel Collectorotel_* (métriques applicatives)Via job statique otel-collector

Si vous voulez scraper un service qui n’a pas les annotations, vous pouvez ajouter un job statique :

Éditez 02-prometheus/helm-values/prometheus-minimal.yaml et ajoutez :

extraScrapeConfigs: |
# Job pour l'OpenTelemetry Collector (métriques OTel Demo)
- job_name: 'otel-collector'
static_configs:
- targets: ['otel-collector.observability.svc.cluster.local:8889']
# NOUVEAU — job personnalisé pour un service externe
- job_name: 'mon-service-externe'
static_configs:
- targets: ['mon-service.example.com:9090']

Puis appliquez :

Fenêtre de terminal
helm upgrade prometheus prometheus-community/prometheus \
-n observability \
-f 02-prometheus/helm-values/prometheus-minimal.yaml

Attendez 1 minute et vérifiez dans Status → Targets que le nouveau job apparaît.

Les recording rules permettent de pré-calculer des requêtes complexes. Au lieu de calculer une requête à chaque affichage de dashboard, Prometheus calcule le résultat régulièrement et le stocke comme une nouvelle métrique.

Sans recording ruleAvec recording rule
Calcul à chaque requêteCalcul périodique (ex: toutes les 30s)
Lent si la requête est complexeRapide (résultat pré-calculé)
Consomme du CPU à chaque affichageConsomme du CPU une fois

Créez le fichier 02-prometheus/recording-rules.yaml :

groups:
- name: http_recording_rules
interval: 30s # Calculer toutes les 30 secondes
rules:
# Requêtes par seconde par handler
- record: job:http_requests_per_second:rate5m
expr: sum by (handler) (rate(prometheus_http_requests_total[5m]))
# Erreurs par seconde par handler
- record: job:http_errors_per_second:rate5m
expr: sum by (handler) (rate(prometheus_http_requests_total{code=~"5.."}[5m]))
# Taux d'erreur par handler
- record: job:http_error_rate:ratio
expr: |
job:http_errors_per_second:rate5m
/
job:http_requests_per_second:rate5m
# Latence P99 par handler
- record: job:http_latency_p99:seconds
expr: |
histogram_quantile(0.99,
sum by (handler, le) (rate(prometheus_http_request_duration_seconds_bucket[5m]))
)

Convention de nommage :

  • Format : level:metric:operation
  • level : niveau d’agrégation (job, instance, cluster…)
  • metric : ce que ça mesure
  • operation : l’opération appliquée (rate5m, ratio, seconds…)

Exercice : Une fois les rules appliquées, vous pouvez utiliser job:http_error_rate:ratio au lieu de la requête complète. C’est plus lisible et plus rapide.

Par défaut dans notre configuration : 7 jours. Après, les données sont supprimées automatiquement.

Vous pouvez modifier ça dans les values :

server:
retention: "30d" # Garder 30 jours

Règle approximative : 1-2 bytes par sample après compression.

Calcul :

Espace = nb_séries × samples_par_jour × jours × 2 bytes

Exemple : 10 000 séries, scrape toutes les 15s, rétention 30 jours :

10000 × (86400 ÷ 15) × 30 × 2 = ~3.5 GB
# Nombre de séries actives
prometheus_tsdb_head_series
# Taille du stockage
prometheus_tsdb_storage_blocks_bytes

Symptôme : Un target est rouge (DOWN) dans Status → Targets.

Diagnostic étape par étape :

  1. Notez le message d’erreur dans la colonne Error

  2. Vérifiez que le pod tourne

    Fenêtre de terminal
    kubectl get pods -n <namespace>
  3. Testez l’endpoint manuellement

    Fenêtre de terminal
    kubectl port-forward pod/<nom-du-pod> 8080:<port-metrics>
    curl http://localhost:8080/metrics

    Si ça fonctionne : le problème est probablement réseau entre Prometheus et le pod.

    Si ça échoue : le pod n’expose pas correctement ses métriques.

  4. Vérifiez les annotations

    Fenêtre de terminal
    kubectl get pod <nom-du-pod> -o yaml | grep -A5 annotations

Symptôme : Prometheus consomme beaucoup de mémoire, les requêtes sont lentes.

Cause probable : Trop de séries temporelles (high cardinality).

Diagnostic :

# Top 10 des métriques par nombre de séries
topk(10, count by (__name__) ({__name__!=""}))

Ce que vous devez voir : Si une métrique a des dizaines de milliers de séries, c’est probablement le problème.

Causes fréquentes :

  • Label user_id ou request_id (une série par utilisateur/requête !)
  • Label path avec des IDs variables (/users/123, /users/456…)
  • Label timestamp (erreur classique)

Solutions :

  1. Corriger l’instrumentation côté application (supprimer les labels problématiques)
  2. Utiliser metric_relabel_configs pour supprimer les labels au niveau Prometheus

Symptôme : Le pod Prometheus redémarre régulièrement.

Diagnostic :

Fenêtre de terminal
kubectl describe pod prometheus-server-xxx -n observability | grep -A10 "Last State"

Si vous voyez OOMKilled : Prometheus manque de mémoire.

Solutions :

  1. Augmentez les limites de ressources :
server:
resources:
requests:
memory: "1Gi"
limits:
memory: "2Gi"
  1. Réduisez la rétention ou le nombre de séries

Avant de passer au module suivant, vérifiez que tout fonctionne.

  1. Prometheus est accessible

    Fenêtre de terminal
    curl -s http://localhost:9090/api/v1/status/config | jq .status

    Résultat attendu : "success"

  2. Les targets sont UP

    Fenêtre de terminal
    curl -s http://localhost:9090/api/v1/targets | jq '.data.activeTargets | map(select(.health=="up")) | length'

    Résultat attendu : Un nombre > 0 (idéalement tous vos targets)

  3. Les métriques système sont présentes

    Fenêtre de terminal
    curl -s 'http://localhost:9090/api/v1/query?query=node_memory_MemAvailable_bytes' | jq '.data.result | length'

    Résultat attendu : Un nombre > 0 (les métriques node_exporter)

  4. Vous savez écrire des requêtes PromQL

    Testez cette requête dans l’interface :

    topk(3, sum by (handler) (rate(prometheus_http_requests_total[5m])))

    Résultat attendu : Les 3 handlers Prometheus avec le plus de requêtes par seconde.

Récapitulons les concepts clés de ce module :

  1. Architecture pull : Prometheus va chercher les métriques sur les endpoints /metrics
  2. 4 types de métriques :
    • Counter : toujours utiliser rate() ou increase()
    • Gauge : valeur directement utilisable
    • Histogram : pour les percentiles avec histogram_quantile()
    • Summary : à éviter si possible
  3. PromQL :
    • Sélecteurs avec labels : {method="GET", status=~"2.."}
    • Fonctions : rate(), sum(), avg(), histogram_quantile()
    • Agrégation : by (label), without (label)
  4. Service Discovery : Prometheus découvre les pods Kubernetes automatiquement
  5. Recording rules : pré-calcul pour de meilleures performances

Vous avez maintenant Prometheus qui collecte les métriques. Mais l’interface de Prometheus est… basique. Dans le prochain module, nous installons Grafana pour créer de vrais dashboards exploitables.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.