Gestion des ressources et affectation des pods
Requests et Limits
Dans Kubernetes, chaque container peut définir des requests (ressources demandées) et des limits (ressources maximales). Ces paramètres sont essentiels pour :
- Garantir que les pods ont les ressources nécessaires
- Éviter qu'un pod consomme toutes les ressources d'un nœud
- Permettre au scheduler de placer les pods intelligemment
Concepts clés
| Paramètre | Description | Impact |
|---|---|---|
| requests.cpu | CPU minimum garanti | Utilisé par le scheduler pour placer le pod |
| requests.memory | Mémoire minimum garantie | Utilisé par le scheduler pour placer le pod |
| limits.cpu | CPU maximum autorisé | Le container sera throttlé s'il dépasse |
| limits.memory | Mémoire maximum autorisée | Le container sera OOMKilled s'il dépasse |
Unités
CPU :
1= 1 vCPU/Core500m= 0.5 CPU (500 millicores)100m= 0.1 CPU
Mémoire :
128Mi= 128 Mebibytes1Gi= 1 Gibibyte256M= 256 Megabytes (base 10)
Exemple complet
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: app
image: nginx
resources:
requests:
memory: "128Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"Comportement du scheduler
Le scheduler utilise les requests pour décider où placer un pod :
Ressources disponibles sur le nœud = Capacité - Somme des requests des pods existantsSi un pod demande requests.cpu: 500m et qu'aucun nœud n'a 500m de CPU disponible, le pod restera en Pending.
Que se passe-t-il en cas de dépassement ?
-> Dépassement CPU (limits.cpu)
Le container est throttlé (ralenti). Il ne sera pas tué, mais ses performances seront dégradées.
-> Dépassement mémoire (limits.memory)
Le container est OOMKilled (Out Of Memory Killed). Kubernetes le redémarrera selon la restartPolicy.
Mise en pratique
-> Créez un pod avec des ressources définies
# resource-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: resource-test
spec:
containers:
- name: stress
image: polinux/stress
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]
resources:
requests:
memory: "100Mi"
cpu: "100m"
limits:
memory: "200Mi"
cpu: "200m"-> Appliquez et observez
kubectl apply -f resource-pod.yaml
kubectl describe pod resource-test
# Regardez la section "Requests" et "Limits"
kubectl top pod resource-test
# Affiche la consommation réelle (nécessite metrics-server)-> Testez un dépassement mémoire
# oom-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: oom-test
spec:
containers:
- name: stress
image: polinux/stress
command: ["stress"]
args: ["--vm", "1", "--vm-bytes", "300M", "--vm-hang", "1"]
resources:
limits:
memory: "100Mi"kubectl apply -f oom-pod.yaml
kubectl get pods -w
# Le pod sera OOMKilled et redémarrera en boucleBonnes pratiques
- Toujours définir des requests ET des limits pour éviter les surprises
- Requests ≈ consommation moyenne de l'application
- Limits = requests × 1.5 à 2 pour absorber les pics
- Ne pas mettre limits.cpu trop bas car le throttling dégrade les performances
- Monitorer la consommation réelle avant de fixer les valeurs définitives
Quality of Service (QoS)
Kubernetes assigne une classe QoS à chaque pod en fonction de ses requests/limits :
| Classe | Condition | Priorité en cas de pression |
|---|---|---|
| Guaranteed | requests = limits (pour tous les containers) | Derniers à être évincés |
| Burstable | requests < limits ou partiellement définis | Évincés avant Guaranteed |
| BestEffort | Aucun request ni limit défini | Premiers à être évincés |
kubectl describe pod <pod-name> | grep "QoS Class"nodeSelector
Le nodeSelector est le moyen le plus simple d'affecter un pod à un nœud spécifique basé sur des labels.
Labelliser un nœud
# Ajouter un label
kubectl label nodes worker-1 disktype=ssd
kubectl label nodes worker-2 disktype=hdd
kubectl label nodes worker-3 gpu=nvidia
# Voir les labels
kubectl get nodes --show-labelsUtiliser nodeSelector dans un pod
apiVersion: v1
kind: Pod
metadata:
name: ssd-pod
spec:
nodeSelector:
disktype: ssd
containers:
- name: nginx
image: nginxCe pod ne sera schedulé que sur les nœuds ayant le label disktype=ssd.
Cas d'usage
- Pods nécessitant un GPU →
gpu: nvidia - Pods nécessitant des SSD →
disktype: ssd - Pods dans une zone géographique spécifique →
topology.kubernetes.io/zone: eu-west-1a
Node Affinity
L'affinity offre plus de flexibilité que nodeSelector avec des règles "required" ou "preferred".
Types d'affinity
| Type | Comportement |
|---|---|
requiredDuringSchedulingIgnoredDuringExecution | Obligatoire : le pod ne sera pas schedulé si la condition n'est pas remplie |
preferredDuringSchedulingIgnoredDuringExecution | Préférentiel : le scheduler essaiera de respecter la condition, mais ce n'est pas obligatoire |
Exemple : Required Affinity
Le pod doit être sur un nœud avec un SSD :
apiVersion: v1
kind: Pod
metadata:
name: required-affinity-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginxExemple : Preferred Affinity
Le pod préfère être sur un nœud avec un SSD, mais peut aller ailleurs :
apiVersion: v1
kind: Pod
metadata:
name: preferred-affinity-pod
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
- weight: 20
preference:
matchExpressions:
- key: disktype
operator: In
values:
- hdd
containers:
- name: nginx
image: nginxLe weight (1-100) indique la priorité de chaque préférence.
Opérateurs disponibles
| Opérateur | Description |
|---|---|
In | La valeur du label est dans la liste |
NotIn | La valeur du label n'est pas dans la liste |
Exists | Le label existe (peu importe sa valeur) |
DoesNotExist | Le label n'existe pas |
Gt | Greater than (pour valeurs numériques) |
Lt | Less than (pour valeurs numériques) |
Pod Affinity et Anti-Affinity
Au-delà des nœuds, on peut aussi définir des règles basées sur la présence d'autres pods.
Pod Affinity : Colocate des pods ensemble
Exemple : placer les pods frontend sur le même nœud que les pods backend (pour réduire la latence réseau) :
apiVersion: v1
kind: Pod
metadata:
name: frontend
labels:
app: frontend
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- backend
topologyKey: kubernetes.io/hostname
containers:
- name: nginx
image: nginxPod Anti-Affinity : Séparer des pods
Exemple : s'assurer que les réplicas d'un même deployment sont sur des nœuds différents (haute disponibilité) :
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 3
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- redis
topologyKey: kubernetes.io/hostname
containers:
- name: redis
image: redisAvec cette configuration, chaque pod Redis sera sur un nœud différent.
topologyKey
Le topologyKey définit le "domaine" de l'affinity :
| topologyKey | Signification |
|---|---|
kubernetes.io/hostname | Même nœud |
topology.kubernetes.io/zone | Même zone (cloud) |
topology.kubernetes.io/region | Même région (cloud) |
Taints et Tolerations
Les taints sont l'inverse du nodeSelector : elles repoussent les pods plutôt que de les attirer.
Ajouter une taint à un nœud
# Syntax: kubectl taint nodes <node> <key>=<value>:<effect>
kubectl taint nodes worker-3 gpu=true:NoScheduleEffects disponibles
| Effect | Comportement |
|---|---|
NoSchedule | Les nouveaux pods sans toleration ne seront pas schedulés |
PreferNoSchedule | Le scheduler évitera ce nœud, mais ce n'est pas garanti |
NoExecute | Les pods existants sans toleration seront évincés |
Tolerations dans un pod
Pour qu'un pod puisse être schedulé sur un nœud avec une taint :
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"
containers:
- name: cuda
image: nvidia/cudaCas d'usage
- Nœuds dédiés : taint pour réserver des nœuds à certains workloads
- Nœuds GPU : seuls les pods GPU peuvent y aller
- Maintenance : taint
NoExecutepour vider un nœud avant maintenance
Supprimer une taint
kubectl taint nodes worker-3 gpu=true:NoSchedule-
# Le "-" à la fin supprime la taintRécapitulatif
| Mécanisme | Usage | Direction |
|---|---|---|
| nodeSelector | Affecter à un nœud par label (simple) | Pod → Node |
| Node Affinity | Affecter à un nœud par label (avancé) | Pod → Node |
| Pod Affinity | Colocate avec d'autres pods | Pod → Pod |
| Pod Anti-Affinity | Séparer des autres pods | Pod ↔ Pod |
| Taints | Repousser les pods d'un nœud | Node → Pod |
| Tolerations | Permettre à un pod d'aller sur un nœud tainté | Pod → Node |