Runbook: NodeMemoryHigh¶
Alerte : NodeMemoryHigh (PrometheusRule, severity warning à 85%, critical à 95%)
Symptôme :
Node
<node>a moins de 15% de RAM libre. Risque d'OOM kill imminent.
Severity : 🟡 warning à 85%, 🔴 critical à 95%
Diagnostic¶
1. État de la RAM sur le node¶
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
kubectl top node
# Ou sur le node directement :
ssh root@<node> 'free -h && cat /proc/meminfo | head -5'
2. Top pods consommateurs mémoire¶
kubectl top pod -A --sort-by=memory | head -20
kubectl get pod -A -o wide --field-selector spec.nodeName=<node>
3. Détecter les OOM récents (kernel)¶
4. Dashboards "Memory usage per pod"¶
Causes fréquentes + fix¶
| Cause | Symptôme | Fix |
|---|---|---|
| OpenMetadata + OpenSearch | Consomment ~3G ensemble | OK en prod, sous-dim si node < 8G total |
| Ollama + gros modèle | 4-7 GB par modèle chargé | Config Ollama OLLAMA_KEEP_ALIVE=-1 consomme la RAM en continu |
| Memory leak Airflow scheduler | Croissance lente sur plusieurs jours | Rolling restart : kubectl rollout restart deploy/airflow-scheduler |
| Trino cache query results | Forte charge SQL concurrente | Baisser query.max-memory et query.max-memory-per-node |
| Spark driver/executor oversized | Grosses tables Iceberg | Tune spark.driver.memory + spark.executor.memory |
| Node packaging trop serré | Beaucoup de pods sur un node | Ajouter des pod anti-affinity pour spread |
Fix d'urgence (< 10 min)¶
1. Evict les pods low-priority pour faire de la place¶
# Lister les pods avec QoS BestEffort (pas de requests)
kubectl get pod -A --field-selector=spec.nodeName=<node> -o json | \
jq -r '.items[] | select(.status.qosClass=="BestEffort") | "\(.metadata.namespace) \(.metadata.name)"'
# Kill manuellement (ils seront rescheduled)
kubectl delete pod -n <ns> <pod>
2. Drain partiel du node¶
kubectl cordon <node>
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data \
--pod-selector='!app.kubernetes.io/component=critical'
3. Restart les deployments gourmands¶
# Rolling restart libère la mémoire leak
kubectl rollout restart deploy/openmetadata -n akko
kubectl rollout restart deploy/airflow-scheduler -n akko
Fix pérenne (R02)¶
Bump resource limits ou ajouter un node¶
# Exemple: réduire l'empreinte OpenSearch
openmetadata:
opensearch:
config:
opensearch.yml: |
...
resources:
limits:
memory: 1Gi # was 2Gi si besoin
Configurer Ollama keep-alive¶
# helm/akko/charts/akko-ollama/values.yaml
env:
- name: OLLAMA_KEEP_ALIVE
value: "5m" # au lieu de "-1" (infini)
- name: OLLAMA_MAX_LOADED_MODELS
value: "1"
Pod anti-affinity¶
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values: ["trino", "spark", "jupyterhub"]
topologyKey: kubernetes.io/hostname
Prévention¶
- HPA avec
targetMemoryUtilizationPercentage: 75pour les services stateless - ResourceQuota par namespace pour éviter qu'un service consomme tout
- Node-problem-detector pour détecter les OOM noyau et pressure
- Capacity planning review + graph de croissance mémoire par service
Lessons learned¶
- Ollama en mode
keep_alive=-1consomme la RAM à vie, même modèle non-utilisé. En dev c'est OK, en prod préférer5mavec HPA.