Dans l’article précédent, j’ai présenté en détail le concept de Pods, le plus important du projet Kubernetes. Dans cet article, je vais partager plus de détails sur les objets Pod.
Pods vs Machines virtuelles
À ce stade, vous devez être très clair : c’est le Pod, et non le conteneur, qui est la plus petite unité d’orchestration dans le projet Kubernetes. Cette conception se reflète dans les objets API, où le conteneur devient simplement un champ ordinaire dans les attributs du Pod. Naturellement, la question se pose : quels attributs appartiennent à l’objet Pod, et lesquels appartiennent au Conteneur ?
Le Pod joue le rôle d’une « machine virtuelle » dans les environnements de déploiement traditionnels. Cette conception vise à rendre la transition des environnements traditionnels (environnements de machines virtuelles) vers Kubernetes (environnements de conteneurs) plus fluide.
Si nous considérons le Pod comme la « machine » dans un environnement traditionnel, et le conteneur comme le « programme utilisateur » s’exécutant sur cette « machine », alors de nombreux aspects de la conception de l’objet Pod deviennent beaucoup plus faciles à comprendre.
Par exemple, les attributs liés à l’ordonnancement, au réseau, au stockage et à la sécurité se situent essentiellement au niveau du Pod. Leur caractéristique commune est qu’ils décrivent la « machine » dans son ensemble, et non les « programmes » qui s’exécutent à l’intérieur.
Ainsi, configurer la carte réseau de la « machine » (c’est-à-dire la définition réseau du Pod), configurer le disque de la « machine » (c’est-à-dire la définition de stockage du Pod), et configurer le pare-feu de la « machine » (c’est-à-dire la définition de sécurité du Pod). Sans oublier sur quel serveur cette « machine » s’exécute (c’est-à-dire l’ordonnancement du Pod).
YAML Kubernetes
Dans Kubernetes, nous définissons les ressources Pod via des fichiers déclaratifs.
NodeSelector : C’est un champ qui permet à l’utilisateur de lier un Pod à un Node, comme illustré ci-dessous :
apiVersion: v1
kind: Pod
...
spec:
nodeSelector:
disktype: ssd
Une telle configuration signifie que ce Pod ne peut s’exécuter que sur un nœud ayant le label disktype: ssd ; sinon, l’ordonnancement échouera.
NodeName : Une fois ce champ d’un Pod assigné, le projet Kubernetes considère que le Pod a été ordonnancé, et le résultat de l’ordonnancement est le nom du nœud assigné. Par conséquent, ce champ est généralement défini par l’ordonnanceur, mais les utilisateurs peuvent aussi le définir pour « tromper » l’ordonnanceur, bien que cette pratique ne soit généralement utilisée que lors de tests ou de débogage.
HostAliases : Définit le contenu du fichier hosts du Pod (par exemple, /etc/hosts), comme ci-dessous :
apiVersion: v1
kind: Pod
...
spec:
hostAliases:
- ip: "10.1.2.3"
hostnames:
- "foo.remote"
- "bar.remote"
...
Il est à noter que dans le projet Kubernetes, si vous souhaitez définir le contenu du fichier hosts, vous devez le faire via cette méthode. Sinon, si vous modifiez directement le fichier hosts, kubelet écrasera automatiquement le contenu modifié après la suppression et la recréation du Pod.
Outre les configurations liées à la « machine » ci-dessus, vous pouvez également constater que tous les attributs relatifs au Linux Namespace du conteneur se situent également au niveau du Pod. Ceci est également facile à comprendre : la conception du Pod vise à permettre aux conteneurs qu’il contient de partager autant de Linux Namespaces que possible, en ne conservant que les capacités d’isolation et de restriction nécessaires. De cette façon, l’effet simulé par le Pod est très similaire à la relation entre les programmes dans une machine virtuelle.
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: nginx
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/usr/sbin/nginx","-s","quit"]
Ceci est un fichier YAML Pod provenant de la documentation officielle de Kubernetes. Il est en fait très simple : il définit simplement un conteneur avec l’image nginx. Cependant, dans la section containers de ce fichier YAML, vous verrez que le conteneur a défini les paramètres postStart et preStop.
Que cela signifie-t-il ?
Commençons par postStart, qui fait référence à une opération exécutée immédiatement après le démarrage du conteneur. Il faut comprendre que l’opération définie par postStart est exécutée après l’ENTRYPOINT du conteneur Docker, mais elle ne garantit pas strictement l’ordre. C’est-à-dire que lorsque postStart démarre, l’ENTRYPOINT peut ne pas être encore terminé.
Bien sûr, si l’exécution de postStart expire ou rencontre une erreur, Kubernetes signalera un message d’erreur indiquant que le conteneur n’a pas démarré dans les Events de ce Pod, ce qui mettra le Pod dans un état d’échec.
De même, le moment de preStop se produit avant que le conteneur soit tué (par exemple, lorsqu’il reçoit un signal SIGKILL). Il est important de préciser que l’exécution de l’opération preStop est synchrone. Par conséquent, elle bloque le processus de terminaison du conteneur en cours jusqu’à ce que l’opération définie soit terminée, ce qui est différent de postStart.
Ainsi, dans cet exemple, après le démarrage réussi du conteneur, il écrit un « message de salutation » dans /usr/share/message (c’est-à-dire l’opération définie par postStart). Et avant que ce conteneur ne soit supprimé, nous appelons d’abord la commande de sortie de nginx (c’est-à-dire l’opération définie par preStop), réalisant ainsi un « arrêt gracieux » du conteneur.
Après vous être familiarisé avec les principaux champs du Pod et de sa section Container, je vais partager le cycle de vie d’un tel objet Pod dans Kubernetes.
Les changements dans le cycle de vie du Pod se reflètent principalement dans la partie Status de l’objet API Pod, qui est son troisième champ important après Metadata et Spec. Parmi eux, pod.status.phase représente l’état actuel du Pod, avec les conditions possibles suivantes :
-
Pending. Cet état signifie que le fichier YAML du Pod a été soumis à Kubernetes, que l’objet API a été créé et sauvegardé dans Etcd. Cependant, certains conteneurs de ce Pod ne peuvent pas être créés correctement pour une raison quelconque. Par exemple, un échec d’ordonnancement.
-
Running. Dans cet état, le Pod a été ordonnancé avec succès et est lié à un nœud spécifique. Tous les conteneurs qu’il contient ont été créés avec succès, et au moins l’un d’eux est actuellement en cours d’exécution.
-
Succeeded. Cet état signifie que tous les conteneurs du Pod sont arrivés à leur terme et ont quitté. Cette situation est la plus courante lors de l’exécution de tâches ponctuelles.
-
Failed. Dans cet état, au moins un conteneur du Pod a quitté de manière anormale (un code de retour non nul). L’apparition de cet état signifie que vous devez comprendre comment déboguer l’application dans le conteneur, par exemple en vérifiant les Events et les logs du Pod.
-
Unknown. C’est un état anormal, indiquant que l’état du Pod n’a pas pu être rapporté de manière continue par kubelet au kube-apiserver, probablement à cause d’un problème de communication entre le master et le Kubelet.
De plus, le champ Status de l’objet Pod peut être décomposé en un ensemble de Conditions. Ces valeurs d’état détaillées incluent : PodScheduled, Ready, Initialized et Unschedulable. Elles sont principalement utilisées pour décrire les raisons spécifiques du Status actuel.
Par exemple, si le Status actuel du Pod est Pending, et que la Condition correspondante est Unschedulable, cela signifie qu’il y a un problème avec son ordonnancement.
Parmi elles, la sous-condition Ready mérite particulièrement notre attention : elle signifie que le Pod non seulement a démarré normalement (dans l’état Running), mais qu’il est également prêt à fournir des services à l’extérieur. Il y a une différence entre ces deux états (Running et Ready), alors vous voudrez peut-être y réfléchir attentivement.
Ces messages d’état du Pod sont un critère important pour juger de la condition d’exécution de l’application, en particulier lorsque le Pod entre dans un état autre que « Running » : vous devez être capable de réagir rapidement, de commencer à suivre et à localiser en fonction de la situation anormale représentée, plutôt que de consulter frénétiquement la documentation.
Résumé
Dans cet article, j’ai expliqué en détail l’objet API Pod, présenté les méthodes d’utilisation principales des Pods, et analysé les similitudes et différences entre les Pods et les Conteneurs en termes de champs. J’espère que ces explications vous aideront à mieux comprendre et mémoriser les champs essentiels du YAML Pod ainsi que leurs significations précises.
En réalité, l’objet API Pod est le concept le plus central de tout le système Kubernetes, et il est également utilisé dans les contrôleurs que j’expliquerai plus tard.
