Aller au contenu principal

Exposer les métriques Prometheus de vos pods Kubernetes vers Mimir

Vous voulez monitorer votre application et vous ne voulez pas gérer un Prometheus. Bonne nouvelle : sur Kubernetes France Nuage, Alloy, Mimir et Grafana sont déjà là. Vous ajoutez trois annotations sur votre pod, et vos métriques remontent automatiquement dans Mimir. Pas d'Helm chart à installer, pas de scraper à configurer, pas de tenant à créer.

Ce qu'il vous faut

  • Un namespace sur votre cluster Kubernetes France Nuage
  • Une instance Grafana France Nuage (voir le guide Stack Grafana)
  • Une application qui expose — ou peut exposer — un endpoint /metrics au format Prometheus

C'est tout. Aucun composant d'observabilité à déployer de votre côté.

Prometheus, Mimir : c'est quoi la différence ?

Prometheus est le standard pour collecter et stocker des métriques. Il est fantastique pour une instance unique, mais il devient compliqué à l'échelle : rétention longue, haute disponibilité, multi-tenant, ça demande du travail.

Mimir est la version scalable de Prometheus. Même langage de requête (PromQL), même format de métriques, mais pensé pour le long terme, la haute disponibilité et le multi-tenant. Vos dashboards et vos alertes continuent de fonctionner à l'identique — Mimir ressemble à Prometheus côté client. Pour plus de détails, lisez le guide Mimir.

Sur Kubernetes France Nuage, on exécute :

  • Grafana Alloy comme collecteur : il découvre automatiquement les pods à scraper via les annotations
  • Mimir comme backend de stockage : un tenant par namespace, isolation garantie
  • Grafana : déjà branché sur Mimir avec votre tenant pré-configuré

Étape 1 : exposer un endpoint /metrics

Si votre application expose déjà /metrics, sautez à l'étape 2.

Sinon, voici un exemple minimal avec Node.js et prom-client :

npm install express prom-client
// server.js
const express = require('express');
const client = require('prom-client');

const register = new client.Registry();
register.setDefaultLabels({ app: 'mon-service' });
client.collectDefaultMetrics({ register });

const httpRequests = new client.Counter({
name: 'http_requests_total',
help: 'Total des requêtes HTTP reçues',
labelNames: ['method', 'status'],
});
register.registerMetric(httpRequests);

const app = express();

app.get('/', (req, res) => {
httpRequests.inc({ method: 'GET', status: '200' });
res.send('hello');
});

app.get('/metrics', (req, res) => {
register.metrics().then((metrics) => {
res.set('Content-Type', register.contentType);
res.end(metrics);
});
});

app.listen(9090, () => console.log('listening on :9090'));

Vous avez maintenant une app qui écoute sur le port 9090 et expose ses métriques sur /metrics. Vous pouvez tester localement :

curl http://localhost:9090/metrics

Vous devriez voir une série de métriques par défaut (process_cpu_seconds_total, nodejs_heap_size_used_bytes, etc.) suivies de votre http_requests_total.

Étape 2 : ajouter les annotations sur votre Pod

C'est le cœur du tutoriel. Alloy scrute le cluster en continu et scrape tous les pods qui portent ces annotations :

metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090" # port du /metrics
prometheus.io/path: "/metrics" # optionnel, /metrics par défaut

Attention : ces annotations doivent être sur le Pod, pas sur le Deployment ou le Service. Concrètement, elles vont dans spec.template.metadata.annotations d'un Deployment :

apiVersion: apps/v1
kind: Deployment
metadata:
name: mon-service
namespace: mon-app
spec:
replicas: 2
selector:
matchLabels:
app: mon-service
template:
metadata:
labels:
app: mon-service
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
containers:
- name: app
image: registry.gitlab.com/mon-groupe/mon-service:latest
ports:
- name: http
containerPort: 9090

Appliquez :

kubectl apply -f deployment.yaml -n mon-app

Si vous déployez via un pipeline CI/CD, jetez un œil au tutoriel Déployer sur Kubernetes depuis GitLab CI pour câbler helm upgrade à chaque push.

Alloy détecte le nouveau pod, commence à scraper /metrics toutes les 15 secondes, et pousse les points vers Mimir avec le header X-Scope-OrgID: mon-app. Le tenant Mimir est dérivé du nom de votre namespace — vous n'avez rien à configurer.

Étape 3 : interroger vos métriques dans Grafana

Ouvrez votre instance Grafana France Nuage. La datasource Mimir est déjà configurée et branchée sur votre tenant.

  1. Allez dans Explore
  2. Sélectionnez la datasource Mimir
  3. Tapez une requête PromQL, par exemple :
http_requests_total{app="mon-service"}

Ou pour voir le taux de requêtes sur 5 minutes :

sum(rate(http_requests_total{app="mon-service"}[5m])) by (status)

Vous pouvez aussi vérifier que le scrape fonctionne en cherchant la métrique up :

up{namespace="mon-app"}

Une valeur à 1 signifie que le scrape est réussi. Une valeur à 0 indique qu'Alloy n'arrive pas à joindre votre endpoint — passez à la section dépannage.

Dépannage

La métrique up renvoie 0

Alloy voit votre pod mais n'arrive pas à scraper l'endpoint. Vérifiez dans l'ordre :

  1. Le port est correct : l'annotation prometheus.io/port doit pointer vers le port d'écoute réel du container, pas le port du Service
  2. Le path est correct : si votre endpoint n'est pas /metrics, ajoutez prometheus.io/path: "/votre-path"
  3. Le container écoute sur toutes les interfaces : 0.0.0.0:9090, pas 127.0.0.1:9090, sinon Alloy ne peut pas l'atteindre depuis l'extérieur du pod

La métrique up n'apparaît pas du tout

Alloy ne voit même pas votre pod. C'est presque toujours un problème d'annotations :

  • Les annotations sont sur le Pod (spec.template.metadata.annotations), pas sur le Deployment lui-même
  • Les valeurs sont des strings : "true", "9090", pas true ou 9090
  • L'annotation prometheus.io/scrape vaut bien "true" (pas "1" ni "yes")

Vérifiez avec :

kubectl get pod -n mon-app -l app=mon-service -o jsonpath='{.items[0].metadata.annotations}'

Mes métriques n'apparaissent pas dans Grafana

Si up fonctionne mais que vos métriques custom ne sortent pas :

  • Vérifiez que vous êtes sur la bonne datasource (Mimir, pas une Prometheus locale)
  • Enlevez les filtres trop restrictifs de votre requête PromQL
  • Patientez 15-30 secondes : c'est l'intervalle de scrape

ERR cardinality limit exceeded

Mimir protège le tenant contre l'explosion de cardinalité. Si vous voyez cette erreur, une de vos métriques a trop de combinaisons de labels distinctes. Passez à la section suivante.

Bonnes pratiques

Maîtrisez la cardinalité des labels

C'est le piège numéro un avec Prometheus et Mimir. Chaque combinaison unique de labels crée une série temporelle distincte, et chaque série consomme de la mémoire.

À éviter absolument :

  • user_id, request_id, trace_id comme labels : cardinalité infinie, votre tenant va exploser
  • url brute : /user/42, /user/43... transformez-la en template /user/:id
  • timestamp ou toute valeur dérivée du temps

À préférer :

  • Labels à cardinalité bornée : method, status, endpoint (templaté), env
  • Un app et un env cohérents sur toutes vos métriques pour faciliter les requêtes

Nommez vos métriques selon les conventions Prometheus

  • Suffixe _total pour les counters
  • Suffixe _seconds pour les durées (pas _ms)
  • Suffixe _bytes pour les tailles
  • Nom en snake_case, pas de majuscules

Une app, un port, un endpoint

Exposer /metrics sur le même port que votre app principale est plus simple à configurer qu'un port dédié. Si vous avez une raison de les séparer (sécurité, pare-feu), pensez à ouvrir un second port dans votre container et à ajuster prometheus.io/port.

Aller plus loin

Des questions ? support@france-nuage.fr