Une référence concise des modèles d'architecture évalués par l'examen CKA. Lisez de haut en bas ou sautez à une section.
Architecture, installation et configuration du cluster
Exigence d'effectuer une sauvegarde de reprise après sinistre de l'état du cluster.
Utiliser `etcdctl snapshot save` avec les certificats TLS appropriés (`--cacert`, `--cert`, `--key`) et le point de terminaison.
Pourquoi: etcd stocke l'état complet du cluster. La prise de snapshot directe est la méthode canonique pour le sauvegarder. Dans un cluster kubeadm, TLS est activé, donc les certificats sont obligatoires pour l'authentification de `etcdctl`.
Restaurer un cluster à partir d'une sauvegarde de reprise après sinistre.
Utiliser `etcdctl snapshot restore` vers un nouveau répertoire de données. Ensuite, mettre à jour le manifest du Pod statique `etcd.yaml` pour que son volume mount `--data-dir` pointe vers le nouvel emplacement et redémarrer le kubelet.
Pourquoi: La restauration crée un nouveau répertoire de données. Le manifest du Pod statique doit être mis à jour pour utiliser ces nouvelles données, sinon etcd démarrera avec l'ancien (ou vide) répertoire de données.
Effectuer une mise à niveau de version pour un cluster géré par kubeadm.
1. Sur le plan de contrôle : mettre à niveau `kubeadm`, exécuter `kubeadm upgrade plan`, puis `kubeadm upgrade apply`. 2. Sur chaque nœud worker : `kubectl drain`, mettre à niveau `kubelet`, redémarrer le service kubelet, `kubectl uncordon`.
Pourquoi: Le processus est multi-étapes et séquentiel. `kubeadm` ne met à niveau que les composants du plan de contrôle ; `kubelet` doit être mis à niveau manuellement sur chaque nœud. Le vidage des nœuds garantit que les charges de travail sont évacuées en toute sécurité avant la maintenance.
Les certificats du cluster expirent et doivent être vérifiés ou renouvelés.
Utiliser `kubeadm certs check-expiration` pour visualiser les dates d'expiration. Utiliser `kubeadm certs renew all` (ou pour des composants spécifiques) pour les renouveler. Redémarrer les Pods du plan de contrôle après le renouvellement.
Pourquoi: Les certificats générés par kubeadm ont une validité d'un an. Le renouvellement est une tâche de maintenance courante. Les composants du plan de contrôle doivent être redémarrés pour charger les nouveaux certificats.
Un composant du plan de contrôle (par exemple, le serveur API) doit être configuré ou redémarré.
Modifier le manifest du composant dans `/etc/kubernetes/manifests/`. Le kubelet sur le nœud détectera automatiquement le changement et redémarrera le Pod.
Pourquoi: Les composants du plan de contrôle dans kubeadm s'exécutent en tant que Pods statiques, gérés directement par le kubelet, et non par le serveur API. Toute la gestion s'effectue via les fichiers manifest dans le répertoire surveillé.
Définir les contrôles d'accès pour les utilisateurs ou les applications.
Utiliser un `Role` et un `RoleBinding` pour les permissions spécifiques à un namespace. Utiliser un `ClusterRole` et un `ClusterRoleBinding` pour les permissions à l'échelle du cluster.
Pourquoi: C'est la séparation fondamentale dans RBAC. Un `Role` est toujours lié à un namespace, tandis qu'un `ClusterRole` peut accorder l'accès à des ressources non namespacées (comme les nœuds) ou à des ressources à travers tous les namespaces.
Un ServiceAccount doit accéder à des ressources dans tous les namespaces.
Créer un `ClusterRole` définissant les permissions. Créer un `ClusterRoleBinding` pour accorder ce ClusterRole au `ServiceAccount` spécifique.
Pourquoi: Même si un ServiceAccount est namespacé, un ClusterRoleBinding peut lui accorder des permissions à l'échelle du cluster. Un `RoleBinding` n'accorderait les permissions qu'au sein du namespace du RoleBinding.
Services et réseau
Exposer une application au trafic externe sans un équilibreur de charge cloud.
Utiliser un Service de `type: NodePort`. Cela expose le service sur un port statique (plage par défaut : 30000-32767) sur l'adresse IP de chaque nœud.
Pourquoi: NodePort est un moyen simple d'acheminer le trafic externe vers le cluster. Il est moins coûteux et agnostique à la plateforme par rapport au `type: LoadBalancer`, mais il exige que les clients connaissent une IP de nœud.
Exposer plusieurs services HTTP/S sous une seule adresse IP, avec un routage basé sur l'hôte ou le chemin.
Déployer un contrôleur Ingress (par exemple, NGINX). Créer des ressources `Ingress` qui définissent les règles de routage des hôtes/chemins vers les `Services` backend.
Pourquoi: Ingress est la ressource Kubernetes standard pour le routage L7. Il nécessite un contrôleur séparé pour implémenter réellement la logique de routage. Cela découple les règles de routage de l'implémentation du proxy.
Sécuriser un namespace en refusant tout trafic entrant par défaut.
Créer une `NetworkPolicy` qui sélectionne tous les Pods (`podSelector: {}`) et spécifie une règle d'ingress vide (`ingress: []`).
Pourquoi: Une fois qu'un Pod est sélectionné par une NetworkPolicy, tout le trafic non explicitement autorisé est refusé. Une politique sélectionnant tous les Pods avec une règle d'ingress vide crée effectivement un pare-feu "tout-refusé" pour le namespace.
Permettre aux Pods d'un namespace "frontend" d'accéder aux Pods d'un namespace "backend".
Dans le namespace "backend", créer une NetworkPolicy. Dans la règle `ingress.from`, utiliser un `namespaceSelector` pour faire correspondre les labels sur la ressource `Namespace` "frontend".
Pourquoi: `podSelector` ne fonctionne qu'au sein du namespace de la politique. Pour autoriser le trafic provenant d'autres namespaces, vous devez utiliser un `namespaceSelector`. Cela nécessite d'étiqueter les objets `Namespace` eux-mêmes.
Une application doit se connecter à un autre service au sein du cluster.
Utiliser le nom DNS interne du service : `<nom-du-service>.<namespace>.svc.cluster.local`. Si dans le même namespace, `<nom-du-service>` est suffisant.
Pourquoi: Kubernetes fournit une découverte de service stable basée sur DNS via CoreDNS. Cela découple les applications des IP spécifiques des Pods, qui sont éphémères.
Une application stateful (par exemple, un ensemble de répliques de base de données) nécessite une identité réseau directe pour chaque Pod.
Créer un `Service` headless (`clusterIP: None`) pour le `StatefulSet`. Cela fournit des enregistrements DNS A uniques pour chaque Pod (par exemple, `pod-0.mon-service.mon-ns...`).
Pourquoi: Un service headless ne fait pas d'équilibrage de charge. Au lieu de cela, il fournit des enregistrements DNS pour chaque Pod, permettant aux clients de se connecter à des instances spécifiques, ce qui est crucial pour l'élection de leader ou la découverte de pairs dans les systèmes stateful.
Un service externe doit voir l'adresse IP d'origine du client pour la journalisation ou le filtrage basé sur l'IP.
Définir `externalTrafficPolicy: Local` sur le Service `NodePort` ou `LoadBalancer`.
Pourquoi: La politique `Cluster` par défaut masque l'IP du client via SNAT. `Local` évite ce saut réseau supplémentaire en acheminant le trafic uniquement vers les Pods du nœud qui a reçu le trafic, préservant ainsi l'IP source.
Charges de travail et ordonnancement
Co-localiser ou disperser les Pods pour des raisons de performance ou de haute disponibilité.
Utiliser `podAffinity` pour ordonnancer les Pods sur le même nœud/zone que d'autres Pods spécifiques. Utiliser `podAntiAffinity` pour éviter de les ordonnancer ensemble.
Pourquoi: Cela offre un contrôle d'ordonnancement plus avancé que l'affinité au niveau du nœud. L'anti-affinité avec `requiredDuringScheduling...` est essentielle pour répartir les répliques d'un service sur les nœuds ou les zones pour la HA.
Dédier des nœuds à des charges de travail spécifiques ou empêcher certaines charges de travail de s'exécuter sur eux.
Appliquer un `taint` à un nœud (par exemple, `gpu=true:NoSchedule`). Ajouter une `toleration` correspondante aux Pods qui devraient être autorisés à s'exécuter sur ce nœud.
Pourquoi: Les Taints repoussent les Pods, tandis que les Tolerations les autorisent. C'est le mécanisme principal pour dédier des nœuds. L'effet `NoExecute` expulsera les Pods déjà en cours d'exécution qui n'ont pas la Toleration.
Déployer un agent de surveillance ou de journalisation sur chaque nœud du cluster.
Utiliser un `DaemonSet`. Il garantit qu'une copie du Pod s'exécute sur chaque nœud qui correspond à ses critères d'ordonnancement.
Pourquoi: Le DaemonSet est conçu à cet effet précis. Il se déploie automatiquement sur les nouveaux nœuds et gère la gestion des Pods au niveau du nœud, ce qui serait difficile avec un Deployment.
Exécuter une tâche batch unique ou une tâche planifiée récurrente.
Utiliser un `Job` pour une tâche qui s'exécute une seule fois jusqu'à son achèvement. Utiliser un `CronJob` pour créer des Jobs selon un calendrier répétitif (par exemple, des sauvegardes nocturnes).
Pourquoi: Les Jobs garantissent que les Pods s'exécutent jusqu'à un nombre spécifié d'achèvements. Les CronJobs sont un contrôleur de niveau supérieur qui gère les Jobs en fonction d'un calendrier cron.
Mettre à jour une application vers une nouvelle version sans interruption de service.
Utiliser un `Deployment` avec la stratégie `RollingUpdate` par défaut. Configurer `maxSurge` et `maxUnavailable` pour contrôler la vitesse de mise à jour et la disponibilité.
Pourquoi: Les Rolling Updates remplacent progressivement les anciens Pods par de nouveaux, garantissant la disponibilité du service. `maxUnavailable` garantit qu'un nombre minimum de Pods sont en cours d'exécution, tandis que `maxSurge` permet de dépasser le nombre de répliques souhaité pour accélérer le déploiement.
S'assurer que les Pods obtiennent des ressources garanties et ne consomment pas de ressources excessives sur un nœud.
Définir `resources.requests` (CPU/mémoire) pour garantir un minimum pour l'ordonnancement. Définir `resources.limits` pour empêcher un conteneur de dépasser une certaine quantité.
Pourquoi: Les Requests sont utilisées par l'ordonnanceur pour le placement et garantissent les ressources. Les Limits sont appliquées par le kubelet et le runtime des conteneurs ; le dépassement de la limite de mémoire entraîne un OOMKill.
Déployer une application stateful qui nécessite des identifiants réseau stables et uniques et un stockage persistant par réplique.
Utiliser un `StatefulSet` avec un `volumeClaimTemplate`. Cela crée un `PersistentVolumeClaim` unique pour chaque Pod, garantissant que les données sont rattachées à la même identité de Pod lors du redémarrage.
Pourquoi: Les StatefulSets fournissent des noms de Pods stables (par exemple, `web-0`, `web-1`) et un PVC unique et persistant pour chacun. C'est essentiel pour les applications qui reposent sur une identité et un stockage stables.
Stockage
Fournir un stockage persistant pour une application sans pré-approvisionnement de volumes.
Créer une `StorageClass` qui définit un provisionneur de stockage. Ensuite, créer un `PersistentVolumeClaim` (PVC) qui demande du stockage à partir de cette classe. Un `PersistentVolume` (PV) sera provisionné dynamiquement.
Pourquoi: Cela découple les applications de l'infrastructure de stockage sous-jacente. Les développeurs demandent du stockage via des PVCs, et l'administrateur du cluster définit la manière dont ce stockage est provisionné via des StorageClasses.
Contrôler ce qui arrive à un volume persistant après la suppression de sa revendication.
Définir `persistentVolumeReclaimPolicy` sur le PV ou la StorageClass. `Delete` supprime automatiquement le stockage sous-jacent. `Retain` laisse le volume et les données intacts, nécessitant un nettoyage manuel.
Pourquoi: `Retain` est l'option la plus sûre pour les données de production, car elle empêche la perte accidentelle de données. `Delete` est pratique pour les environnements éphémères ou de développement. La valeur par défaut dépend du provisionneur.
Définir comment un volume peut être monté par les Pods.
Utiliser `accessModes` : `ReadWriteOnce` (RWO) pour une lecture-écriture sur un seul nœud, `ReadOnlyMany` (ROX) pour une lecture seule sur plusieurs nœuds, `ReadWriteMany` (RWX) pour une lecture-écriture sur plusieurs nœuds.
Pourquoi: Le mode d'accès doit être pris en charge par le fournisseur de stockage sous-jacent. Une inadéquation entre les besoins de l'application (par exemple, nécessitant RWX) et les capacités de stockage (ne supportant que RWO) est une cause fréquente de PVCs en attente (Pending).
Injecter des fichiers de configuration ou des données sensibles dans un Pod.
Monter un `ConfigMap` ou un `Secret` en tant que volume. Chaque clé de l'objet de données devient un fichier dans le chemin de montage.
Pourquoi: C'est la manière standard de fournir la configuration aux Pods. Cela permet de gérer la configuration comme un objet Kubernetes et de la mettre à jour indépendamment de l'image du Pod.
Une application a besoin de plus d'espace de stockage dans son volume persistant existant.
S'assurer que la `StorageClass` a `allowVolumeExpansion: true`. Modifier le `PVC` pour demander une taille plus grande dans `spec.resources.requests.storage`.
Pourquoi: L'expansion de volume est une fonctionnalité opt-in. La StorageClass doit l'autoriser explicitement, et le pilote CSI sous-jacent doit la prendre en charge. Le Pod peut avoir besoin d'être redémarré pour que le système de fichiers soit redimensionné.
Dépannage
Un Pod est bloqué à l'état `Pending` et n'est pas ordonnancé.
Exécuter `kubectl describe pod <nom-du-pod>`. Vérifier la section `Events` pour les messages de l'ordonnanceur.
Pourquoi: La commande `describe` est l'outil principal pour cela. Elle affichera des raisons comme "CPU/mémoire insuffisants", "le(s) nœud(s) avait(aient) des taints que le Pod n'a pas tolérés", ou "ne correspondait pas au sélecteur de nœud".
Un Pod démarre et échoue de manière répétée, avec un statut `CrashLoopBackOff`.
1. `kubectl logs <nom-du-pod> --previous` pour voir les journaux du conteneur en panne. 2. `kubectl describe pod <nom-du-pod>` pour vérifier le code de sortie et la raison.
Pourquoi: `CrashLoopBackOff` signifie que l'application à l'intérieur du conteneur s'arrête. Les journaux de l'instance précédente (`--previous`) sont cruciaux, car le conteneur actuel n'a peut-être encore rien enregistré d'utile. Le code de sortie peut également indiquer le type d'erreur.
Un Pod ne parvient pas à démarrer avec le statut `ImagePullBackOff` ou `ErrImagePull`.
`kubectl describe pod <nom-du-pod>` pour voir le message de l'événement. Vérifier que le nom et le tag de l'image sont corrects. Pour les registres privés, s'assurer qu'un `imagePullSecrets` est configuré et que le secret est valide.
Pourquoi: Il s'agit d'un problème de registre ou de nom d'image, et non d'un problème d'application. Les causes courantes sont les fautes de frappe, les tags incorrects ou l'échec d'authentification avec un registre privé.
Un nœud a un statut `NotReady`.
Se connecter en SSH au nœud affecté. Vérifier le statut du service kubelet avec `systemctl status kubelet`. Consulter ses journaux avec `journalctl -u kubelet`.
Pourquoi: Le `kubelet` est l'agent responsable du rapport de santé du nœud. S'il est en panne ou ne peut pas communiquer avec le serveur API, le nœud sera marqué NotReady. Ses journaux sont le premier endroit où chercher.
Un service existe, mais le trafic n'atteint pas les Pods backend.
1. `kubectl describe svc <nom-du-service>` et vérifier que le `Selector` correspond aux labels des Pods. 2. `kubectl get endpoints <nom-du-service>` et s'assurer qu'il liste les bonnes IP des Pods. Si ce n'est pas le cas, les labels ne correspondent pas.
Pourquoi: Le lien entre un Service et ses Pods est le sélecteur de labels. Si le sélecteur est incorrect ou si les Pods n'ont pas les bons labels, l'objet Endpoints sera vide et le service n'aura aucun endroit où acheminer le trafic.
Les Pods sont incapables de résoudre les noms de service ou les noms d'hôtes externes.
1. Vérifier si les Pods CoreDNS sont en cours d'exécution dans `kube-system`. 2. Vérifier les journaux de CoreDNS. 3. Exécuter un Pod de débogage (par exemple, `busybox`) et utiliser `nslookup` pour tester la résolution depuis l'intérieur du cluster.
Pourquoi: Le DNS est une dépendance critique du cluster. Les échecs remontent généralement au déploiement de CoreDNS lui-même, à sa configuration (dans un ConfigMap), ou aux NetworkPolicies bloquant le trafic DNS sur le port UDP/TCP 53.
Un nœud doit être mis hors ligne pour maintenance.
D'abord, `kubectl cordon <nom-du-nœud>` pour le marquer comme non-ordonnançable. Ensuite, `kubectl drain <nom-du-nœud> --ignore-daemonsets` pour évacuer en toute sécurité tous les Pods utilisateur.
Pourquoi: `cordon` empêche l'ordonnancement de nouveaux Pods. `drain` respecte les PodDisruptionBudgets et évacue les Pods en douceur. `--ignore-daemonsets` est nécessaire car les Pods DaemonSet ne peuvent pas être évacués.
Identifier quels Pods ou nœuds consomment le plus de CPU ou de mémoire.
Utiliser `kubectl top pods` et `kubectl top nodes`. Cela nécessite que le `metrics-server` soit déployé dans le cluster.
Pourquoi: `kubectl top` fournit une vue rapide et en temps réel de la consommation des ressources, essentielle pour identifier les applications gourmandes en ressources ou la pression sur les ressources des nœuds.
Un Pod est resté à l'état `Terminating` pendant une longue période et n'est pas supprimé.
Forcer la suppression du Pod avec `kubectl delete pod <nom-du-pod> --grace-period=0 --force`.
Pourquoi: Cela peut se produire si un finalizer est bloqué ou si le kubelet ne peut pas nettoyer les ressources. La suppression forcée retire immédiatement le Pod du serveur API, mais doit être utilisée en dernier recours car elle peut laisser des ressources orphelines sur le nœud.