Aller au contenu
English
Conteneurs & Orchestration medium

DaemonSets Kubernetes : garantir un Pod sur chaque nœud éligible

75 min de lecture

logo Kubernetes

Un DaemonSet garantit qu'un Pod s'exécute sur chaque nœud éligible de votre cluster Kubernetes. Contrairement à un Deployment qui répartit un nombre variable de répliques, le DaemonSet assure exactement un Pod par nœud correspondant aux critères de sélection.

Ce guide couvre la création, le ciblage de nœuds spécifiques avec nodeSelector et tolerations, les stratégies de mise à jour, et le dépannage, tout ce qu'il faut pour la certification CKAD.

  • Créer un DaemonSet et observer son déploiement automatique sur tous les nœuds
  • Cibler des nœuds spécifiques avec nodeSelector et affinity
  • Gérer les nœuds taintés avec tolerations (control-plane, GPU, etc.)
  • Mettre à jour un DaemonSet avec les stratégies RollingUpdate et OnDelete
  • Diagnostiquer pourquoi un Pod ne s'exécute pas sur un nœud

Un DaemonSet est un contrôleur Kubernetes qui garantit qu'un Pod spécifique tourne sur tous les nœuds éligibles d'un cluster, ou sur un sous-ensemble défini par des règles de sélection.

Un DaemonSet ne garantit pas un Pod sur absolument tous les nœuds sans nuance. Il garantit un Pod sur tous les nœuds qui correspondent à :

  • nodeSelector : labels requis sur le nœud
  • affinity : règles d'affinité plus avancées
  • tolerations : tolérance aux taints du nœud
  • Contraintes de ressources : CPU/mémoire disponibles

Si un nœud ne satisfait pas ces critères, aucun Pod du DaemonSet n'y sera schedulé.

La force du DaemonSet est qu'il réagit seul aux changements de topologie du cluster, sans que vous touchiez au nombre de répliques. Le tableau liste les trois événements qui déclenchent une action du contrôleur. Le premier est le plus utile au quotidien : ajoutez un nœud, un Pod de l'agent y apparaît automatiquement, ce qui garantit qu'aucune machine ne reste sans surveillance.

ÉvénementAction du DaemonSet
Nouveau nœud rejoint le clusterUn Pod est automatiquement créé sur ce nœud
Nœud supprimé du clusterLe Pod correspondant est automatiquement supprimé
Nœud devient inéligible (nouveau taint)Le Pod est évicté si pas de toleration

Les DaemonSets sont essentiels pour les agents système qui doivent tourner partout :

CatégorieExemples
MonitoringPrometheus Node Exporter, Datadog Agent, Telegraf
Collecte de logsFluentd, Fluent Bit, Filebeat, Vector
Réseau (CNI)Calico, Cilium, Flannel, Weave Net
Stockage (CSI)NFS CSI Node Plugin, Longhorn, OpenEBS
SécuritéFalco, Sysdig, Trivy Operator

Voici un DaemonSet minimal qui exécute un conteneur busybox affichant un message toutes les 10 secondes :

daemonset-basic.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
labels:
app: daemon-example
spec:
selector:
matchLabels:
app: daemon-example
template:
metadata:
labels:
app: daemon-example
spec:
containers:
- name: busybox
image: busybox:1.37@sha256:9db7b59979c38555a39def84a31fb98b5296952f9e3afd4f6f11f05b07adfab0
command: ["sh", "-c", "while true; do echo 'DaemonSet actif sur $(hostname)'; sleep 10; done"]
resources:
requests:
cpu: 10m
memory: 16Mi
limits:
cpu: 50m
memory: 32Mi

Appliquer le DaemonSet :

Fenêtre de terminal
kubectl apply -f daemonset-basic.yaml

Vérifier le déploiement :

Fenêtre de terminal
kubectl get ds my-daemonset
# NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
# my-daemonset 3 3 3 3 3 <none> 45s

Les colonnes importantes :

ColonneSignification
DESIREDNombre de nœuds éligibles
CURRENTNombre de Pods créés
READYNombre de Pods en état Ready
UP-TO-DATEPods avec la spec à jour
NODE SELECTORSélecteur de nœuds (si défini)

Voir sur quels nœuds les Pods tournent :

Fenêtre de terminal
kubectl get pods -l app=daemon-example -o wide
# NAME READY STATUS NODE
# my-daemonset-7x2km 1/1 Running node-worker-1
# my-daemonset-9f4np 1/1 Running node-worker-2
# my-daemonset-kj8rt 1/1 Running node-control-plane

Un DaemonSet peut être limité à un sous-ensemble de nœuds avec nodeSelector ou affinity. C'est utile pour :

  • Déployer uniquement sur les nœuds Linux (kubernetes.io/os: linux)
  • Cibler un pool spécifique (GPU, infra, edge)
  • Exclure les nœuds de développement

La méthode la plus simple. Le DaemonSet ne crée des Pods que sur les nœuds ayant tous les labels spécifiés.

daemonset-nodeselector.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: infra-agent
spec:
selector:
matchLabels:
app: infra-agent
template:
metadata:
labels:
app: infra-agent
spec:
nodeSelector:
kubernetes.io/os: linux
nodepool: infra
containers:
- name: agent
image: busybox:1.37@sha256:9db7b59979c38555a39def84a31fb98b5296952f9e3afd4f6f11f05b07adfab0
command: ["sh", "-c", "echo 'Agent infra'; sleep infinity"]

Vérifier les labels d'un nœud :

Fenêtre de terminal
kubectl get node node-worker-1 --show-labels

Ajouter un label à un nœud :

Fenêtre de terminal
kubectl label node node-worker-1 nodepool=infra

Pour des règles plus complexes (opérateurs In, NotIn, Exists) :

spec:
template:
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- arm64

Par défaut, les Pods ne sont pas schedulés sur les nœuds portant un taint NoSchedule. Pour qu'un DaemonSet s'exécute sur ces nœuds (par exemple les control-plane), vous devez ajouter des tolerations.

Les nœuds control-plane portent généralement le taint node-role.kubernetes.io/control-plane:NoSchedule. Pour y déployer un agent de monitoring :

daemonset-controlplane.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: monitoring-agent
spec:
selector:
matchLabels:
app: monitoring-agent
template:
metadata:
labels:
app: monitoring-agent
spec:
tolerations:
- key: "node-role.kubernetes.io/control-plane"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: node-exporter
image: prom/node-exporter:v1.10.2@sha256:3ac34ce007accad95afed72149e0d2b927b7e42fd1c866149b945b84737c62c3
ports:
- containerPort: 9100
name: metrics

Pour les agents système qui doivent absolument tourner partout (y compris sur des nœuds avec n'importe quel taint) :

tolerations:
- operator: "Exists"

Cette tolérance universelle a une portée qu'il faut mesurer : elle autorise le Pod à rester même sur un nœud marqué NoExecute pour une maintenance en cours, donc précisément sur un nœud qu'on cherche à vider. Réservez-la aux agents dont l'absence casserait le nœud, un CNI ou un collecteur de journaux, et pas à un exportateur de métriques qu'on peut perdre dix minutes.

L'effet d'une tolérance se mesure d'ailleurs directement sur DESIRED. Sur un cluster à deux nœuds dont un control plane tainté, un DaemonSet sans tolérance annonce 1. La même ressource, avec une tolérance sur node-role.kubernetes.io/control-plane, annonce 2 et place un Pod sur chaque nœud. La colonne ne compte pas les machines, elle compte les portes ouvertes.

Avant d'écrire une toleration, il faut connaître le taint exact que porte le nœud : sa clé, sa valeur et son effet (NoSchedule, NoExecute). La commande ci-dessous extrait cette ligne du describe, et c'est elle que vous recopiez ensuite champ par champ dans la toleration. Une faute de frappe sur la clé suffit à laisser le Pod bloqué en Pending.

Fenêtre de terminal
kubectl describe node node-control-plane | grep -A 5 Taints
# Taints: node-role.kubernetes.io/control-plane:NoSchedule

Ces commandes sont essentielles pour le dépannage et l'examen CKAD.

Ces cinq commandes couvrent le suivi complet d'un DaemonSet, de la vue synthétique au détail. Commencez toujours par kubectl get ds : si la colonne DESIRED diffère de READY, vous savez qu'un nœud pose problème et vous enchaînez avec describe pour lire les événements. Les commandes de rollout ne servent que pendant une mise à jour en cours.

Fenêtre de terminal
# Vue d'ensemble des DaemonSets
kubectl get ds
# Détails complets (événements, sélecteur, stratégie)
kubectl describe ds my-daemonset
# Pods du DaemonSet avec leurs nœuds
kubectl get pods -l app=daemon-example -o wide
# État du rollout en cours
kubectl rollout status ds/my-daemonset
# Historique des révisions
kubectl rollout history ds/my-daemonset
Fenêtre de terminal
kubectl get ds
Sortie
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
agent 1 1 1 1 1 <none> 12s

DESIRED n'est pas le nombre de nœuds du cluster, c'est le nombre de nœuds que le contrôleur juge éligibles. Sur un cluster à deux nœuds dont le control plane est tainté, un DaemonSet sans toleration affiche donc DESIRED 1, et tout va bien. La colonne NODE SELECTOR vous rappelle la contrainte que vous avez posée, ce qui évite de chercher ailleurs.

Les valeurs par défaut, relevées sur l'objet créé

Section intitulée « Les valeurs par défaut, relevées sur l'objet créé »
ChampDéfaut
updateStrategy.typeRollingUpdate
rollingUpdate.maxUnavailable1
rollingUpdate.maxSurge0
revisionHistoryLimit10

Le maxSurge: 0 est la différence de fond avec un Deployment : sur un nœud, il n'y a de la place que pour un Pod du DaemonSet. Kubernetes doit donc supprimer l'ancien avant de créer le nouveau, et la mise à jour d'un agent implique par construction une courte interruption sur chaque nœud.

Fenêtre de terminal
kubectl describe ds my-daemonset
Sortie, entête
Name: agent
Namespace: lab-ds
Selector: app=agent
Node-Selector: <none>
Desired Number of Nodes Scheduled: 1
Current Number of Nodes Scheduled: 1
Number of Nodes Scheduled with Up-to-date Pods: 1
Number of Nodes Scheduled with Available Pods: 1
Number of Nodes Misscheduled: 0
Pods Status: 1 Running / 0 Waiting / 0 Succeeded / 0 Failed

Number of Nodes Misscheduled mérite un regard : il compte les nœuds qui portent un Pod du DaemonSet alors qu'ils ne devraient plus, typiquement après un changement de nodeSelector. Une valeur non nulle signale un ménage en cours, pas une panne.

Kubernetes propose deux stratégies de mise à jour pour les DaemonSets.

C'est la stratégie par défaut depuis l'API apps/v1. Kubernetes remplace les Pods progressivement, un par un, en respectant les contraintes configurées.

daemonset-rollingupdate.yaml
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: my-daemonset
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1 # Max de Pods indisponibles pendant la MAJ
maxSurge: 0 # Pas de Pod supplémentaire créé avant suppression
selector:
matchLabels:
app: daemon-example
template:
metadata:
labels:
app: daemon-example
spec:
containers:
- name: busybox
image: busybox:1.37@sha256:9db7b59979c38555a39def84a31fb98b5296952f9e3afd4f6f11f05b07adfab0 # Changez cette image pour déclencher un rollout

Paramètres de contrôle :

ParamètreDescriptionValeur par défaut
maxUnavailableNombre max de Pods indisponibles pendant la mise à jour1
maxSurgeNombre de Pods supplémentaires créés avant suppression (K8s 1.22+)0
minReadySecondsDélai avant de considérer un Pod comme Ready0

Appliquer une mise à jour :

Fenêtre de terminal
kubectl apply -f daemonset-rollingupdate.yaml

Suivre la progression :

Fenêtre de terminal
kubectl rollout status ds/my-daemonset
# Waiting for daemon set "my-daemonset" rollout to finish: 1 out of 3 new pods have been updated...
# daemon set "my-daemonset" successfully rolled out

Annuler en cas de problème :

Fenêtre de terminal
kubectl rollout undo ds/my-daemonset

Avec OnDelete, Kubernetes ne met pas à jour automatiquement les Pods existants. Vous devez les supprimer manuellement pour qu'ils soient recréés avec la nouvelle spec.

spec:
updateStrategy:
type: OnDelete

Workflow :

  1. Modifier la spec du DaemonSet

    Fenêtre de terminal
    kubectl apply -f daemonset-updated.yaml
  2. Les Pods existants ne changent pas (vérifiez avec kubectl get pods)

  3. Supprimer manuellement un Pod pour déclencher sa recréation

    Fenêtre de terminal
    kubectl delete pod my-daemonset-7x2km
  4. Le nouveau Pod est créé avec la nouvelle spec

Cas d'usage de OnDelete :

  • Mise à jour contrôlée nœud par nœud
  • Validation manuelle avant chaque remplacement
  • Environnements critiques avec approbation requise

Le dépannage d'un DaemonSet se fait sur une colonne : DESIRED. Elle ne compte pas les nœuds du cluster, mais les nœuds éligibles, c'est-à-dire ceux que le nodeSelector retient et dont les taints sont tolérés. Un DESIRED plus petit que le nombre de nœuds n'est donc pas une anomalie, c'est une réponse : il vous dit combien de nœuds acceptent votre Pod.

Le piège, développé plus bas, est qu'un DESIRED à zéro n'a rien d'alarmant en apparence, puisqu'il est alors égal à CURRENT.

La panne la plus fréquente d'un DaemonSet n'est pas un Pod qui plante, c'est un Pod jamais créé. Et elle est difficile pour une raison précise : elle ne produit aucun signal.

Le contrôleur ne signale pas les nœuds qu'il ignore

Section intitulée « Le contrôleur ne signale pas les nœuds qu'il ignore »

Un nodeSelector que personne ne satisfait ne fait pas diverger DESIRED et CURRENT. Mesuré :

NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR
agent-gpu 0 0 0 0 0 materiel=gpu

Les deux colonnes valent 0, donc elles sont égales, donc tout a l'air cohérent. Et kubectl describe ds rend :

Events: <none>

Aucun FailedCreate, aucun avertissement. DESIRED compte les nœuds éligibles, pas les nœuds du cluster : le contrôleur n'a rien tenté, donc il n'a rien à signaler.

Le symptôme n'est donc pas DESIREDCURRENT, c'est DESIRED inférieur au nombre de nœuds que vous attendiez. Il ne se voit qu'en comparant :

Fenêtre de terminal
kubectl get nodes --no-headers | wc -l
kubectl get ds agent-gpu

Posez le libellé manquant sur un nœud et DESIRED passe à 1 dans la seconde, sans qu'aucune commande n'ait à être rejouée.

SymptômeCause probableDiagnosticSolution
DESIRED < nombre de nœudsNœud tainté ou nodeSelector non satisfaitComparer get nodes et get ds, puis get nodes --show-labelsAjouter une toleration ou le libellé manquant
Pod PendingPas de nœud éligiblekubectl describe podVérifier labels/taints des nœuds
ImagePullBackOffImage introuvable ou registre inaccessiblekubectl logs <pod>Vérifier le nom de l'image et les credentials
CrashLoopBackOffApplication qui plante en bouclekubectl logs <pod> --previousCorriger l'application ou sa configuration
Pod non créé sur un nœudNodeSelector ou affinity non satisfaitskubectl get node --show-labelsAjouter les labels requis au nœud

Quand DESIRED ne correspond pas au nombre de Pods, la méthode consiste à comparer la liste des nœuds à la liste des Pods pour repérer la machine orpheline. Les commandes ci-dessous font exactement cela : elles comptent d'un côté les nœuds, de l'autre les Pods du DaemonSet, puis inspectent le nœud suspect pour y lire ses taints et ses conditions.

Fenêtre de terminal
# Voir pourquoi un DaemonSet n'a pas le bon nombre de Pods
kubectl describe ds my-daemonset
# Identifier les nœuds sans Pod du DaemonSet
kubectl get nodes -o wide
kubectl get pods -l app=daemon-example -o wide
# Comparer nœuds et Pods
kubectl get nodes --no-headers | wc -l # Nombre de nœuds
kubectl get pods -l app=daemon-example --no-headers | wc -l # Nombre de Pods
# Vérifier un nœud spécifique
kubectl describe node node-worker-2 | grep -E "Taints|Conditions" -A 3

Exemple de résolution : Pod manquant sur un nœud tainté

Section intitulée « Exemple de résolution : Pod manquant sur un nœud tainté »

Symptôme : le cluster a 3 nœuds, le DaemonSet en annonce 2.

Fenêtre de terminal
kubectl get nodes --no-headers | wc -l
kubectl get ds my-daemonset
Sortie
3
NAME DESIRED CURRENT READY NODE SELECTOR
my-daemonset 2 2 2 <none>

Notez bien : DESIRED et CURRENT sont égaux, et describe ne montre aucun événement. Rien n'indique un problème, sinon l'écart avec le nombre de nœuds.

Diagnostic : puisque le contrôleur ne parle pas, c'est aux nœuds qu'il faut demander lequel est écarté, et pourquoi.

Fenêtre de terminal
kubectl get nodes -o custom-columns=NOM:.metadata.name,TAINTS:.spec.taints[*].key
Sortie
NOM TAINTS
doc-k8s-control-plane node-role.kubernetes.io/control-plane
doc-k8s-worker <none>
noeud-gpu gpu

Solution :

tolerations:
- key: "gpu"
operator: "Equal"
value: "true"
effect: "NoSchedule"

Choisir la bonne ressource est essentiel pour la CKAD. Voici un comparatif :

CritèreDaemonSetDeploymentStatefulSet
Nombre de Pods1 par nœud éligibleN répliques (variable)N répliques ordonnées
Identité des PodsAnonymeAnonymeStable (pod-0, pod-1...)
StockageGénéralement local/hostPathPVC partagé ou sans étatPVC dédié par Pod
Cas d'usageAgents système, CNI, logsApplications stateless, APIsBases de données, queues
ScalingAutomatique (suit les nœuds)kubectl scale ou HPAkubectl scale
Mise à jourRollingUpdate ou OnDeleteRollingUpdateRollingUpdate ou OnDelete

Le critère de décision tient en une question : le nombre de Pods doit-il suivre le nombre de nœuds ? Si oui, le DaemonSet est le bon choix. Ces trois signaux confirment le besoin, ils tournent tous autour d'un accès aux ressources locales du nœud (fichiers de logs, interfaces réseau, métriques matérielles) qu'un Pod ordinaire ne peut pas garantir sur chaque machine.

  • Vous avez besoin d'un agent sur chaque nœud (ou sous-ensemble)
  • L'application doit accéder aux ressources locales du nœud (logs, métriques, réseau)
  • Le nombre de répliques doit suivre automatiquement le nombre de nœuds

À l'inverse, forcer un DaemonSet là où il n'a pas sa place gaspille des ressources et complique le scaling. Chaque ligne ci-dessous renvoie vers la ressource réellement adaptée : un Deployment pour une application sans dépendance au nœud, un StatefulSet dès qu'il faut une identité stable et du stockage persistant par Pod.

  • Votre application ne dépend pas du nœud → Deployment
  • Vous avez besoin d'identités stables et de stockage persistant → StatefulSet
  • Vous voulez scaler indépendamment du nombre de nœuds → Deployment + HPA
  1. Un DaemonSet garantit un Pod sur chaque nœud éligible, pas sur tous les nœuds sans distinction
  2. L'éligibilité dépend des nodeSelector, affinity, tolerations et des ressources disponibles
  3. La stratégie de mise à jour par défaut est RollingUpdate (pas OnDelete)
  4. Utilisez maxUnavailable pour contrôler le rythme des mises à jour
  5. Les tolerations sont nécessaires pour les nœuds control-plane ou taintés
  6. kubectl describe ds est votre meilleur ami pour diagnostiquer les problèmes
  7. Choisissez DaemonSet pour les agents système, Deployment pour les applications scalables

Sept questions sur la seule notion qui compte vraiment ici, celle de nœud éligible, et sur la façon dont un DaemonSet le dit sans avoir l'air de signaler quoi que ce soit.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

7 questions
5 min.
80% requis

Informations

  • Le chronomètre démarre au clic sur Démarrer
  • Questions à choix multiples, vrai/faux et réponses courtes
  • Vous pouvez naviguer entre les questions
  • Les résultats détaillés sont affichés à la fin

Lance le quiz et démarre le chronomètre

Un DaemonSet qui oublie le control plane passe inaperçu jusqu'au jour où il manque une métrique. Ce lab vous fait déployer un agent sur tous les nœuds, taint du control plane compris, puis compte un Pod par nœud, vérifie que le taint est toujours en place et lit les logs de l'agent pour prouver qu'il travaille.

Ce site vous est utile ?

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

Je maintiens ce site gratuitement, sans publicité, sans profilage et sans compte à créer. Un soutien, même symbolique, m'aide à couvrir l'hébergement et à garder ces ressources gratuites. Merci pour votre appui.

Le formulaire ne s'affiche pas ? Ouvrir Ko-fi dans un onglet.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn