Aller au contenu
Outils medium

Prometheus sur Kubernetes

14 min de lecture

Ce guide couvre le déploiement de Prometheus sur Kubernetes avec kube-prometheus-stack. Vous apprendrez le pattern Operator, les ServiceMonitors, et comment monitorer vos applications en 5 minutes.

Pourquoi un Operator (et pas juste un Deployment) ?

Section intitulée « Pourquoi un Operator (et pas juste un Deployment) ? »

Sur Kubernetes, on pourrait déployer Prometheus “classiquement” (Deployment + ConfigMap). Mais ça pose des problèmes :

ProblèmeAvec ConfigMapAvec Operator
Ajouter une cibleÉditer ConfigMap + reloadCréer un ServiceMonitor
Multi-équipeConflits sur le même fichierChaque équipe gère ses CRDs
ValidationAucune (YAML brut)Schéma Kubernetes
DécouverteManuelleAutomatique (labels)

Le pattern Operator : au lieu de modifier un fichier de config central, chaque équipe déclare un ServiceMonitor (CRD Kubernetes). L’Operator génère automatiquement la config Prometheus.

ComposantRôle
Prometheus OperatorSurveille les CRDs, génère la config
PrometheusCollecte et stockage (TSDB)
AlertmanagerRouting des alertes
GrafanaDashboards préconfigurés
Node ExporterMétriques système des nodes
kube-state-metricsÉtat des objets K8s (pods, deployments…)

Architecture kube-prometheus-stack : Operator, Prometheus, Alertmanager, Grafana, Node Exporter et kube-state-metrics

  1. Ajouter le repository Helm

    Fenêtre de terminal
    helm repo add prometheus-community \
    https://prometheus-community.github.io/helm-charts
    helm repo update
  2. Installer la stack (version pinnée)

    Fenêtre de terminal
    helm install prometheus prometheus-community/kube-prometheus-stack \
    --namespace monitoring \
    --create-namespace \
    --version 69.8.2
  3. Vérifier le déploiement (tous les pods Running)

    Fenêtre de terminal
    kubectl get pods -n monitoring -w

    Attendez ~2-3 minutes. Tous les pods doivent être Running :

    NAME READY STATUS
    alertmanager-prometheus-kube-prometheus-alertmanager-0 2/2 Running
    prometheus-grafana-xxx 3/3 Running
    prometheus-kube-prometheus-operator-xxx 1/1 Running
    prometheus-kube-state-metrics-xxx 1/1 Running
    prometheus-prometheus-kube-prometheus-prometheus-0 2/2 Running
    prometheus-prometheus-node-exporter-xxx 1/1 Running
  4. Vérification rapide : Prometheus fonctionne

    Fenêtre de terminal
    kubectl port-forward -n monitoring svc/prometheus-kube-prometheus-prometheus 9090:9090 &
    curl -s localhost:9090/api/v1/targets | jq '.data.activeTargets | length'
    # Attendu : un nombre > 10 (les targets K8s)
Fenêtre de terminal
# Prometheus
kubectl port-forward -n monitoring svc/prometheus-kube-prometheus-prometheus 9090:9090
# Grafana (mot de passe par défaut: prom-operator)
kubectl port-forward -n monitoring svc/prometheus-grafana 3000:80
# Alertmanager
kubectl port-forward -n monitoring svc/prometheus-kube-prometheus-alertmanager 9093:9093

L’Operator surveille ces Custom Resource Definitions :

CRDRôleQui le crée
ServiceMonitor”Scrappe ce Service”Équipe app
PodMonitor”Scrappe ces Pods” (sans Service)Équipe app
PrometheusRuleAlertes et recording rulesÉquipe app/SRE
PrometheusInstance PrometheusOps/Platform
AlertmanagerInstance AlertmanagerOps/Platform

Workflow typique :

  1. L’équipe platform installe kube-prometheus-stack
  2. Chaque équipe app crée ses ServiceMonitors + PrometheusRules
  3. L’Operator génère la config automatiquement

Créons un ServiceMonitor pour une application qui expose /metrics.

app-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
namespace: default
labels:
app: my-app
spec:
replicas: 2
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:latest
ports:
- containerPort: 8080
name: http
- containerPort: 9090
name: metrics
---
apiVersion: v1
kind: Service
metadata:
name: my-app
namespace: default
labels:
app: my-app
spec:
ports:
- port: 8080
name: http
- port: 9090
name: metrics
selector:
app: my-app
servicemonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
namespace: default # Peut être dans le namespace de l'app
labels:
release: prometheus # ⚠️ OBLIGATOIRE - voir ci-dessous
spec:
selector:
matchLabels:
app: my-app # Matche le label du Service
endpoints:
- port: metrics # Nom du port dans le Service
interval: 15s
path: /metrics
Fenêtre de terminal
# ServiceMonitor créé ?
kubectl get servicemonitor -A
# Visible dans Prometheus Targets ?
kubectl port-forward -n monitoring svc/prometheus-kube-prometheus-prometheus 9090:9090
# Puis : Status → Targets → cherchez "my-app"

Pour les pods éphémères (Jobs, CronJobs) ou sans Service :

podmonitor.yaml
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: batch-jobs
namespace: monitoring
labels:
release: prometheus
spec:
selector:
matchLabels:
type: batch-job
namespaceSelector:
any: true # Tous les namespaces
podMetricsEndpoints:
- port: metrics
interval: 30s

Les alertes sont aussi des CRDs :

prometheusrule.yaml
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: my-app-alerts
namespace: monitoring
labels:
release: prometheus # ⚠️ Même piège que ServiceMonitor
spec:
groups:
- name: my-app
rules:
- alert: MyAppDown
expr: up{job="my-app"} == 0
for: 2m
labels:
severity: critical
team: backend
annotations:
summary: "{{ $labels.instance }} is down"
runbook_url: "https://wiki/runbooks/my-app-down"
- alert: MyAppHighErrorRate
expr: |
sum(rate(http_requests_total{job="my-app", status=~"5.."}[5m]))
/ sum(rate(http_requests_total{job="my-app"}[5m])) > 0.05
for: 3m
labels:
severity: warning
team: backend
annotations:
summary: "Error rate > 5%"
values.yaml
# Prometheus
prometheus:
prometheusSpec:
retention: 15d
retentionSize: 50GB
replicas: 2 # HA
storageSpec:
volumeClaimTemplate:
spec:
storageClassName: gp3
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
# IMPORTANT : scraper tous les ServiceMonitors (pas seulement release=prometheus)
serviceMonitorSelectorNilUsesHelmValues: false
podMonitorSelectorNilUsesHelmValues: false
ruleSelectorNilUsesHelmValues: false
# Alertmanager
alertmanager:
alertmanagerSpec:
replicas: 3
storage:
volumeClaimTemplate:
spec:
storageClassName: gp3
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 10Gi
config:
global:
resolve_timeout: 5m
route:
receiver: 'slack-default'
group_by: ['alertname', 'namespace', 'service']
routes:
- matchers:
- severity="critical"
receiver: 'pagerduty'
receivers:
- name: 'slack-default'
slack_configs:
- api_url: 'https://hooks.slack.com/services/...'
channel: '#alerts'
- name: 'pagerduty'
pagerduty_configs:
- routing_key: '$PAGERDUTY_KEY'
# Grafana
grafana:
adminPassword: 'VotreMotDePasseSecurise'
persistence:
enabled: true
size: 10Gi
# Node Exporter sur TOUS les nodes (y compris taints)
prometheus-node-exporter:
tolerations:
- operator: Exists
# kube-state-metrics : labels custom sur les pods
kube-state-metrics:
metricLabelsAllowlist:
- pods=[app,version,team]
- deployments=[app,version]
Fenêtre de terminal
helm upgrade prometheus prometheus-community/kube-prometheus-stack \
-n monitoring \
-f values.yaml \
--version 69.8.2

kube-prometheus-stack collecte automatiquement :

MétriqueDescription
kube_pod_status_phasePhase du pod (Pending, Running…)
kube_pod_container_status_restarts_totalRestarts
kube_deployment_status_replicas_availableReplicas ready
kube_node_status_conditionÉtat des nodes
MétriqueDescription
container_cpu_usage_seconds_totalCPU par container
container_memory_usage_bytesMémoire par container
container_network_receive_bytes_totalRéseau
# Pods en CrashLoopBackOff
kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} > 0
# CPU par pod (cores)
sum(rate(container_cpu_usage_seconds_total{container!=""}[5m])) by (pod, namespace)
# Mémoire par namespace (GB)
sum(container_memory_usage_bytes{container!=""}) by (namespace) / 1e9
# Deployments avec replicas manquants
kube_deployment_status_replicas_available < kube_deployment_spec_replicas
# Nodes NotReady
kube_node_status_condition{condition="Ready", status="true"} == 0

kube-prometheus-stack inclut des règles d’alerte préconfigurées :

AlerteSévéritéDescription
KubeNodeNotReadyWarningNode non prêt
KubePodCrashLoopingWarningPod en crash loop
KubeDeploymentReplicasMismatchWarningReplicas manquants
KubePersistentVolumeFillingUpCriticalPV bientôt plein
PrometheusNotConnectedToAlertmanagersWarningPrometheus → Alertmanager cassé
TargetDownWarningTarget non scrapable
Fenêtre de terminal
# Lister toutes les règles
kubectl get prometheusrules -n monitoring
# Voir le détail
kubectl get prometheusrules -n monitoring \
prometheus-kube-prometheus-kubernetes-apps -o yaml

Pour monitorer des services hors Kubernetes :

external-targets.yaml
apiVersion: v1
kind: Secret
metadata:
name: additional-scrape-configs
namespace: monitoring
stringData:
additional-scrape-configs.yaml: |
- job_name: 'external-nodes'
static_configs:
- targets:
- 'external-db.example.com:9104'
- 'legacy-server.example.com:9100'

Référencez dans values.yaml :

prometheus:
prometheusSpec:
additionalScrapeConfigsSecret:
enabled: true
name: additional-scrape-configs
key: additional-scrape-configs.yaml
PiègeSymptômeSolution
Label release manquantServiceMonitor ignoréAjouter release: prometheus
Namespace non surveilléTarget absentVérifier namespaceSelector
Port name incorrectScrape timeoutMatcher le nom du port Service
Selector trop largeExplosion targetsÊtre plus spécifique
Pas de PVCDonnées perdues au restartConfigurer storageSpec
SymptômeCommande de debug
ServiceMonitor pas scrapékubectl get servicemonitor -A -o yaml | grep -A3 labels
Prometheus OOMkubectl top pod -n monitoring + réduire cardinalité
Config généréeVoir ci-dessous
Alertes pas envoyéeskubectl logs -n monitoring alertmanager-...

Voir la config Prometheus générée :

Fenêtre de terminal
kubectl get secret -n monitoring \
prometheus-prometheus-kube-prometheus-prometheus \
-o jsonpath='{.data.prometheus\.yaml\.gz}' | base64 -d | gunzip | head -100

Logs utiles :

Fenêtre de terminal
# Operator (génère la config)
kubectl logs -n monitoring deploy/prometheus-kube-prometheus-operator
# Prometheus
kubectl logs -n monitoring prometheus-prometheus-kube-prometheus-prometheus-0 -c prometheus
# Alertmanager
kubectl logs -n monitoring alertmanager-prometheus-kube-prometheus-alertmanager-0
  • Operator pattern : les CRDs remplacent les fichiers de config
  • ServiceMonitor : déclare un Service à scraper
  • Label release: prometheus : obligatoire par défaut (le piège #1)
  • Dashboards inclus : observabilité K8s prête à l’emploi
  • HA : replicas: 2 pour Prometheus, replicas: 3 pour Alertmanager
  • Stockage : toujours configurer storageSpec en production

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.