Aller au contenu
Conteneurs & Orchestration medium

CNI, CSI et CRI, Les interfaces d'extension de Kubernetes

21 min de lecture

Kubernetes ne gère pas directement le réseau, le stockage ou l'exécution des conteneurs. Il délègue ces responsabilités à des plugins externes via trois interfaces standardisées : CNI (réseau), CSI (stockage) et CRI (runtime). Comprendre ces interfaces est essentiel pour la certification CKA (domaine Cluster Architecture, 25%).

Ce guide explique le rôle de chaque interface et comment les diagnostiquer.

  • CNI : comment Kubernetes configure le réseau des Pods
  • CSI : comment Kubernetes accède au stockage externe
  • CRI : comment le kubelet communique avec le runtime de conteneurs
  • Les commandes de diagnostic pour chaque interface

Les trois interfaces répondent à la même logique : Kubernetes définit un contrat, et n'importe quel fournisseur peut écrire un plugin qui le respecte. Le schéma montre qui appelle quoi. Retenez surtout que le kubelet est le point de départ pour le runtime et le stockage, alors que le réseau est configuré par le runtime lui-même au moment où il crée le Pod.

┌─────────────────────────────────────────────────────────────────────────┐
│ KUBERNETES │
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ kubelet │ │
│ └───────────┬─────────────────────┬─────────────────────┬─────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ CRI │ │ CNI │ │ CSI │ │
│ │ Runtime │ │ Réseau │ │ Stockage │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │
└────────────┼─────────────────────┼─────────────────────┼────────────────┘
│ │ │
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ containerd │ │ Calico │ │ AWS EBS │
│ CRI-O │ │ Cilium │ │ Ceph CSI │
│ etc. │ │ Flannel │ │ NFS CSI │
└────────────┘ └────────────┘ └────────────┘
InterfaceAcronymeRôleExemple de plugins
CRIContainer Runtime InterfaceCréer/gérer les conteneurscontainerd, CRI-O
CNIContainer Network InterfaceConfigurer le réseau des PodsCalico, Cilium, Flannel
CSIContainer Storage InterfaceProvisionner le stockageAWS EBS, Ceph, NFS

C'est l'interface la plus proche du système : sans elle, aucun conteneur ne démarre sur le nœud. Elle définit un contrat gRPC entre le kubelet, qui sait ce qu'il faut lancer, et le runtime, qui sait comment le lancer. Un problème à ce niveau se manifeste toujours de la même façon, le nœud passe en NotReady et aucun Pod ne démarre.

Le CRI est l'interface gRPC entre le kubelet et le runtime de conteneurs. Il permet au kubelet de créer, démarrer, arrêter et supprimer des conteneurs sans connaître les détails d'implémentation du runtime.

Avant le CRI (Kubernetes < 1.5), le kubelet était couplé à Docker. Le CRI a permis de supporter d'autres runtimes comme containerd ou CRI-O.

Deux implémentations dominent aujourd'hui et se valent en production ; le choix est généralement dicté par la distribution Kubernetes que vous installez, pas par une préférence technique.

RuntimeDescriptionCas d'usage
containerdRuntime léger, standard de factoClusters kubeadm, cloud providers
CRI-OOptimisé pour KubernetesOpenShift, clusters minimalistes

La colonne CONTAINER-RUNTIME donne à la fois le runtime et sa version, nœud par nœud. Un cluster où cette colonne n'est pas homogène mérite un examen : c'est souvent le signe d'un nœud ajouté avec une autre procédure d'installation.

Fenêtre de terminal
# Voir le runtime utilisé par le kubelet
kubectl get nodes -o wide
NAME STATUS ROLES VERSION CONTAINER-RUNTIME
master1 Ready control-plane v1.36.0 containerd://2.2.3
worker1 Ready <none> v1.36.0 containerd://2.2.3
Fenêtre de terminal
# Détails du socket CRI
kubectl get node <node-name> -o jsonpath='{.status.nodeInfo.containerRuntimeVersion}'

Le kubelet se connecte au runtime via un socket Unix. C'est le paramètre clé de la configuration CRI :

Fenêtre de terminal
# Socket containerd (défaut sur la plupart des distributions)
--container-runtime-endpoint=unix:///run/containerd/containerd.sock
# Socket CRI-O
--container-runtime-endpoint=unix:///var/run/crio/crio.sock

La configuration exacte varie selon les distributions. Sur un nœud kubeadm, vous pouvez vérifier :

Fenêtre de terminal
# Voir l'endpoint configuré
ps aux | grep kubelet | grep container-runtime-endpoint
# Ou dans la config kubelet (selon distribution)
cat /var/lib/kubelet/kubeadm-flags.env

Ces commandes s'exécutent sur le nœud, en SSH, et fonctionnent même quand l'API server est injoignable : crictl parle directement au socket du runtime, sans passer par le control plane.

Fenêtre de terminal
# Vérifier que le socket existe
ls -la /run/containerd/containerd.sock
# Tester la connexion avec crictl
crictl info
# Lister les conteneurs via CRI
crictl ps
# Lister les images
crictl images

Kubernetes impose un modèle réseau (chaque Pod a sa propre IP, joignable depuis tous les autres Pods sans NAT) mais ne fournit aucune implémentation. C'est le rôle du plugin CNI, choisi à l'installation du cluster. Tant qu'aucun plugin n'est installé, les Pods restent bloqués en ContainerCreating et les nœuds en NotReady.

Le CNI est la spécification qui définit comment configurer le réseau des conteneurs. Quand un Pod est créé, le runtime appelle les plugins CNI pour :

  1. Créer une interface réseau dans le Pod
  2. Assigner une adresse IP
  3. Configurer les routes

L'ordre des étapes explique un comportement déroutant : le conteneur existe avant d'avoir une adresse. Si le plugin CNI échoue à l'étape 4, le Pod reste créé mais sans réseau, d'où le statut ContainerCreating qui ne se résout jamais.

1. kubelet demande la création d'un Pod au runtime (CRI)
2. Le runtime crée le conteneur et son namespace réseau
3. Le runtime appelle les plugins CNI configurés
4. CNI assigne une IP et configure le réseau
5. Le Pod est accessible sur le réseau du cluster

Le mode réseau détermine comment un paquet voyage d'un nœud à l'autre : VXLAN encapsule le trafic dans un tunnel, ce qui fonctionne partout mais ajoute de la latence ; BGP annonce les routes des Pods au réseau sous-jacent, ce qui est plus rapide mais suppose un réseau coopératif ; eBPF traite les paquets directement dans le noyau. Ce choix est structurant, changer de plugin CNI sur un cluster en production est une opération lourde.

PluginMode réseauForces
CalicoBGP / VXLAN / IP-in-IPNetwork Policies, performance
CiliumeBPFObservabilité, sécurité avancée
FlannelVXLAN / host-gwSimplicité, idéal pour débuter
CanalCalico + FlannelCombine les deux

Les plugins CNI sont configurés dans /etc/cni/net.d/ :

Fenêtre de terminal
# Lister les configurations CNI
ls /etc/cni/net.d/
10-calico.conflist

Exemple de configuration Calico :

{
"name": "k8s-pod-network",
"cniVersion": "1.0.0",
"plugins": [
{
"type": "calico",
"datastore_type": "kubernetes",
"ipam": {
"type": "calico-ipam"
},
"policy": {
"type": "k8s"
}
},
{
"type": "portmap",
"capabilities": {"portMappings": true}
}
]
}

Les binaires des plugins sont dans /opt/cni/bin/ :

Fenêtre de terminal
ls /opt/cni/bin/
bandwidth bridge calico calico-ipam flannel host-local loopback portmap ...

Le diagnostic part toujours du même constat : un Pod n'a pas d'adresse ou n'en joint pas un autre. Ces commandes vérifient successivement que le plugin tourne, que l'IP a été attribuée, et que la plage d'adresses du nœud correspond bien au CIDR du cluster.

Fenêtre de terminal
# Vérifier le plugin CNI installé
kubectl get pods -n kube-system | grep -E 'calico|cilium|flannel|weave'
# Voir l'IP attribuée à un Pod
kubectl get pod <pod-name> -o wide
# Vérifier le CIDR du cluster
kubectl cluster-info dump | grep -m 1 cluster-cidr
# Voir le CIDR alloué à chaque nœud
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'

Trois symptômes couvrent la grande majorité des incidents réseau sur un cluster neuf. Ils se distinguent par le moment où la panne apparaît : à la création du Pod, à l'attribution de l'adresse, ou seulement lors des échanges entre Pods.

SymptômeCause probableSolution
Pod en ContainerCreatingPlugin CNI manquantInstaller un CNI (Calico, Flannel...)
Pod sans IPErreur IPAMVérifier logs du plugin CNI
Pods ne communiquent pasNetwork Policy ou erreur pluginVérifier les Network Policies

Le stockage est le domaine où les fournisseurs sont les plus nombreux : baies NAS, disques cloud, systèmes distribués. Plutôt que d'intégrer leur code dans Kubernetes, le CSI leur donne une interface commune, implémentée par un driver déployé comme n'importe quelle application du cluster. C'est aussi la seule des trois interfaces qui met en jeu des données persistantes, donc la seule où une erreur peut avoir des conséquences irréversibles.

Le CSI est l'interface standard pour provisionner et attacher du stockage aux conteneurs. Il remplace les plugins de stockage "in-tree" (intégrés au code de Kubernetes).

Avant CSI, chaque type de stockage (AWS EBS, GCE PD, Ceph...) nécessitait du code dans le core Kubernetes. Avec CSI :

  • Les drivers sont développés indépendamment de Kubernetes
  • Les mises à jour de drivers n'impactent pas le cycle de release Kubernetes
  • N'importe quel vendor peut créer un driver CSI

Kubernetes redirige automatiquement les appels aux plugins in-tree vers les drivers CSI correspondants :

Plugin in-tree (déprécié)Driver CSI
awsElasticBlockStoreebs.csi.aws.com
gcePersistentDiskpd.csi.storage.gke.io
azureDiskdisk.csi.azure.com
cinder (OpenStack)cinder.csi.openstack.org
vsphereVolumecsi.vsphere.vmware.com

La chaîne se lit de gauche à droite : l'utilisateur crée un PVC, celui-ci désigne une StorageClass, qui indique quel driver contacter. Le driver dialogue ensuite avec le système de stockage pour créer le volume et le rendre disponible sur le nœud où le Pod est planifié.

┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ PVC │───▶│ StorageClass │───▶│ CSI Driver │ │
│ │ (claim) │ │ (provisioner)│ │ (controller) │ │
│ └──────────────┘ └──────────────┘ └──────┬───────┘ │
│ │ │
└──────────────────────────────────────────────────┼───────────────┘
┌──────────────┐
│ Stockage │
│ externe │
└──────────────┘

Un driver CSI se compose de plusieurs pods :

ComposantRôleDéploiement typique
ControllerProvisionne/supprime les volumesDeployment dans kube-system
NodeMonte/démonte les volumesDaemonSet sur chaque nœud
CSI Sidecarsexternal-provisioner, external-attacher...Avec le controller

Un driver absent de cette liste ne sera jamais utilisé, quelle que soit la StorageClass déclarée. La colonne ATTACHREQUIRED indique si le volume doit être rattaché au nœud avant montage, ce qui est le cas des disques bloc et non des partages réseau.

Fenêtre de terminal
# Lister les CSI Drivers installés
kubectl get csidrivers
NAME ATTACHREQUIRED PODINFOONMOUNT ...
ebs.csi.aws.com true false
efs.csi.aws.com false false
Fenêtre de terminal
# Détails d'un driver
kubectl describe csidriver ebs.csi.aws.com

Le champ provisioner fait le lien avec le driver CSI, les parameters étant propres à chaque fournisseur. Deux options méritent d'être connues : volumeBindingMode: WaitForFirstConsumer retarde la création du volume jusqu'à ce qu'un Pod soit planifié, ce qui évite de provisionner un disque dans la mauvaise zone, et allowVolumeExpansion autorise l'agrandissement d'un volume existant.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.aws.com
parameters:
type: gp3
fsType: ext4
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true

Un PVC qui reste en Pending ne dit pas pourquoi : la raison se trouve dans ses événements ou dans les logs du sidecar csi-provisioner, qui est le composant chargé de traduire la demande en appel au fournisseur de stockage.

Fenêtre de terminal
# Vérifier les pods CSI
kubectl get pods -n kube-system | grep csi
# Logs du controller CSI
kubectl logs -n kube-system -l app=ebs-csi-controller -c csi-provisioner
# Vérifier les PV créés via CSI
kubectl get pv -o custom-columns=NAME:.metadata.name,DRIVER:.spec.csi.driver
# Événements de PVC
kubectl describe pvc <pvc-name>

La ligne la plus utile est « Appelé par » : elle explique pourquoi une panne CRI bloque tout le nœud, alors qu'une panne CSI n'affecte que les Pods qui réclament un volume. Gardez aussi en tête l'emplacement de la configuration, c'est la première chose à vérifier en dépannage.

AspectCRICNICSI
RôleExécuter les conteneursConfigurer le réseauProvisionner le stockage
Appelé parkubeletContainer runtimekubelet + sidecars + controller
ConfigSocket runtime/etc/cni/net.d/StorageClass
Exemplescontainerd, CRI-OCalico, CiliumAWS EBS, Ceph
Diagnosticcrictlkubectl get pods -n kube-systemkubectl get csidrivers

Structurez votre diagnostic par interface :

Symptômes : kubelet ne lance pas les Pods, erreurs "container runtime is down"

Fenêtre de terminal
# Vérifier que le socket existe
ls -la /run/containerd/containerd.sock
# Vérifier l'état du service
systemctl status containerd
journalctl -u containerd -n 50
# Tester la connexion
crictl info

Symptômes : Pods bloqués en ContainerCreating, pas d'IP assignée

Fenêtre de terminal
# Vérifier qu'un plugin CNI est installé
ls /etc/cni/net.d/
ls /opt/cni/bin/
# Vérifier les Pods CNI
kubectl get pods -n kube-system | grep -E 'calico|cilium|flannel'
# Logs du plugin CNI
kubectl logs -n kube-system -l k8s-app=calico-node

Symptômes : PVC en Pending, volume qui ne se monte pas

Fenêtre de terminal
# Vérifier le driver CSI
kubectl get csidrivers
# Vérifier les événements du PVC
kubectl describe pvc <name>
# Logs du controller CSI
kubectl logs -n kube-system -l app=ebs-csi-controller -c csi-provisioner

Ce bloc regroupe les commandes à connaître pour l'examen, classées par interface. Les deux premières de chaque groupe suffisent généralement à identifier le composant fautif ; les suivantes servent à confirmer l'hypothèse.

Fenêtre de terminal
# === CRI ===
# Vérifier le runtime
kubectl get nodes -o wide
crictl info
crictl ps
# === CNI ===
# Voir le plugin CNI
ls /etc/cni/net.d/
kubectl get pods -n kube-system | grep -E 'calico|cilium|flannel'
# Voir les CIDR par nœud
kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.podCIDR}{"\n"}{end}'
# === CSI ===
# Lister les drivers CSI
kubectl get csidrivers
# Vérifier les StorageClasses
kubectl get storageclasses
# Debug un PVC bloqué
kubectl describe pvc <name>
  1. CRI = interface kubelet ↔ container runtime (containerd, CRI-O)
  2. CNI = interface pour configurer le réseau des Pods
  3. CSI = interface pour provisionner du stockage externe
  4. Les plugins in-tree sont dépréciés, utilisez CSI pour le stockage
  5. crictl pour diagnostiquer le runtime
  6. Config CNI dans /etc/cni/net.d/, binaires dans /opt/cni/bin/
  7. StorageClass définit quel driver CSI utiliser

Dix questions pour vérifier que vous savez attribuer chaque symptôme à la bonne interface, un réflexe directement évalué par le domaine Cluster Architecture de la CKA.

Contrôle de connaissances

Validez vos connaissances avec ce quiz interactif

10 questions
8 min.
70% 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

Ce site vous est utile ?

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

Je maintiens +700 guides gratuits, sans pub ni tracking. 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