Un workload (charge de travail) est une application fonctionnant sur Kubernetes. Que votre workload soit un composant unique ou un agrégat de composants, sur Kubernetes celui-ci fonctionnera dans une série de pods. Dans Kubernetes, un Pod represente un ensemble de conteneur (containers) en fonctionnement sur votre cluster.
Les pods Kubernetes ont un cycle de vie définit (defined lifecycle). Par exemple, quand un pod est en fonction sur votre cluster et qu’une panne critique survient sur le noeud (node) où se situe ce pod, tous les pods du noeud seront en échec. Kubernetes traite ce niveau d’échec comme un état final :
Vous devez créer un nouveau Pod pour retrouver l’état initial même si le noeud redevient sain.
Cependant, pour vous simplifier la vie, vous n’avez pas a gérer chaque Pod directement. Vous pouvez utiliser une ressource workload qui gère votre groupe de pods à votre place. Ces ressources configurent des controleurs (controllers) qui s’assurent que le bon nombre et le bon type de pod soit en fonction pour égaler l’état que vous avez spécifié.
Kubernetes fournit plusieurs ressources workload pré-faites :
Deployment et ReplicaSet
(qui remplacent l’ancienne ressource ReplicationController)).
Le Deployment (déploiement) est une bonne approche pour manager une application stateless sur votre cluster, tous les Pods d’un Deployment sont interchangeables et peuvent être remplacés si besoin.
Le StatefulSet vous permet de lancer un ou plusieurs Pods en relation qui garde plus ou moins la trace de leurs état.
Par exemple si votre workload enregistre des données de façon persistente, vous pouvez lancer un StatefulSet qui fera le lien entre les Pods et un volume persistent (PersistentVolume).
Votre code, présent dans les Pods du StatefulSet, peut répliquer des données dans les autres Pods qui sont dans le même StatefulSet,
pour améliorer la résilience global.
Le DaemonSet permet de définir les Pods qui effectuent des actions sur le noeud local.
Ceux-ci peuvent être fondamental aux opérations de votre cluster, comme un outil d’aide réseau, ou peuvent faire part d’un module complémentaire (add-on).
Pour chaque nouveau noeud ajouté au cluster, le controle plane organise l'ajout d'un Pod pour ce DaemonSet sur le nouveau noeud.
Les Job et CronJob sont des taches lancées jusqu’à accomplissement puis s’arrêtent. Les Jobs réprésentent une tâche ponctuelle, les CronJob sont des tâches récurrentes planifiés.
Dans l’écosystème étendu de Kubernetes, vous pouvez trouver des ressources workload de fournisseurs tiers qui offrent des fonctionnalités supplémentaires.
L’utilisation d’un CustomResourceDefinition permet d’ajouter une ressource workload d’un fournisseur tiers si vous souhaitez rajouter une fonctionnalité ou un comportement spécifique qui ne fait pas partie du noyau de Kubernetes.
Par exemple, si vous voulez lancer un groupe de Pods pour votre application mais que vous devez arrêter leurs fonctionnement tant qu’ils ne sont pas tous disponibles, alors vous pouvez implémenter ou installer une extension qui permet cette fonctionnalité.
A suivre
Vous pouvez continuer la lecture des ressources, vous pouvez aussi apprendre à connaitre les taches qui leurs sont liées :
Une fois que votre application est lancée, vous souhaitez peut etre la rendre disponible sur internet comme un Service ou comme une application web uniquement en utilsant un Ingress.
1 - Pods
1.1 - Aperçu du Pod
Pod Concept Kubernetes
Cette page fournit un aperçu du Pod, l'objet déployable le plus petit dans le modèle d'objets Kubernetes.
Comprendre les Pods
Un Pod est l'unité d'exécution de base d'une application Kubernetes--l'unité la plus petite et la plus simple dans le modèle d'objets de Kubernetes--que vous créez ou déployez. Un Pod représente des process en cours d'exécution dans votre cluster.
Un Pod encapsule un conteneur applicatif (ou, dans certains cas, plusieurs conteneurs), des ressources de stockage, une identité réseau (adresse IP) unique, ainsi que des options qui contrôlent comment le ou les conteneurs doivent s'exécuter. Un Pod représente une unité de déploiement : une instance unique d'une application dans Kubernetes, qui peut consister soit en un unique container soit en un petit nombre de conteneurs qui sont étroitement liés et qui partagent des ressources.
Docker est le runtime de conteneurs le plus courant utilisé dans un Pod Kubernetes, mais les Pods prennent également en charge d'autres runtimes de conteneurs.
Les Pods dans un cluster Kubernetes peuvent être utilisés de deux manières différentes :
les Pods exécutant un conteneur unique. Le modèle "un-conteneur-par-Pod" est le cas d'utilisation Kubernetes le plus courant ; dans ce cas, vous pouvez voir un Pod comme un wrapper autour d'un conteneur unique, et Kubernetes gère les Pods plutôt que directement les conteneurs.
les Pods exécutant plusieurs conteneurs devant travailler ensemble. Un Pod peut encapsuler une application composée de plusieurs conteneurs co-localisés qui sont étroitement liés et qui doivent partager des ressources. Ces conteneurs co-localisés pourraient former une unique unité de service cohésive--un conteneur servant des fichiers d'un volume partagé au public, alors qu'un conteneur "sidecar" séparé rafraîchit ou met à jour ces fichiers. Le Pod enveloppe ensemble ces conteneurs et ressources de stockage en une entité maniable de base.
Chaque Pod est destiné à exécuter une instance unique d'une application donnée. Si vous désirez mettre à l'échelle votre application horizontalement, (pour fournir plus de ressources au global en exécutant plus d'instances), vous devez utiliser plusieurs Pods, un pour chaque instance. Dans Kubernetes, on parle typiquement de réplication. Des Pods répliqués sont en général créés et gérés en tant que groupe par une ressource de charge de travail et son _contrôleur_. Voir Pods et contrôleurs pour plus d'informations.
Comment les Pods gèrent plusieurs conteneurs
Les Pods sont conçus pour supporter plusieurs process coopérants (sous forme de conteneurs) qui forment une unité de service cohésive. Les conteneurs d'un même Pod sont automatiquement co-localisés et co-programmés sur la même machine physique ou virtuelle dans le cluster. Ces conteneurs peuvent partager des ressources et dépendances, communiquer entre eux, et coordonner quand et comment ils sont arrêtés.
Notez que grouper plusieurs conteneurs co-localisés et co-gérés dans un unique Pod est un cas d'utilisation relativement avancé. Vous devez utiliser ce pattern seulement dans des instances spécifiques dans lesquelles vos conteneurs sont étroitement liés. Par exemple, vous pourriez avoir un conteneur qui agit comme un serveur web pour des fichiers contenus dans un volume partagé, et un conteneur "sidecar" séparé qui met à jour ces fichiers depuis une source externe, comme dans le diagramme suivant :
Certains Pods ont des init containers en plus d'app containers. Les Init containers s'exécutent et terminent avant que les conteneurs d'application soient démarrés.
Les Pods fournissent deux types de ressources partagées pour leurs conteneurs : réseau et stockage.
Réseau
Chaque Pod se voit assigner une adresse IP unique pour chaque famille d'adresses. Tous les conteneurs d'un Pod partagent le même namespace réseau, y compris l'adresse IP et les ports réseau. Les conteneurs à l'intérieur d'un Pod peuvent communiquer entre eux en utilisant localhost. Lorsque les conteneurs dans un Pod communiquent avec des entités en dehors du Pod, ils doivent coordonner comment ils utilisent les ressources réseau partagées (comme les ports).
Stockage
Un Pod peut spécifier un jeu de volumes de stockage partagés. Tous les conteneurs dans le Pod peuvent accéder aux volumes partagés, permettant à ces conteneurs de partager des données. Les volumes permettent aussi les données persistantes d'un Pod de survivre au cas où un des conteneurs doit être redémarré. Voir Volumes pour plus d'informations sur la façon dont Kubernetes implémente le stockage partagé dans un Pod.
Travailler avec des Pods
Vous aurez rarement à créer directement des Pods individuels dans Kubernetes--même des Pods à un seul conteneur. Ceci est dû au fait que les Pods sont conçus comme des entités relativement éphémères et jetables. Lorsqu'un Pod est créé (directement par vous ou indirectement par un _contrôleur_), il est programmé pour s'exécuter sur un Node dans votre cluster. Le Pod reste sur ce nœud jusqu'à ce que le process se termine, l'objet pod soit supprimé, le pod soit expulsé par manque de ressources, ou le nœud soit en échec.
Note: Redémarrer un conteneur dans un Pod ne doit pas être confondu avec redémarrer un Pod. Un Pod n'est pas un process, mais un environnement pour exécuter un conteneur. Un Pod persiste jusqu'à ce qu'il soit supprimé.
Les Pods ne se guérissent pas par eux-mêmes. Si un Pod est programmé sur un Nœud qui échoue, ou si l'opération de programmation elle-même échoue, le Pod est supprimé ; de plus, un Pod ne survivra pas à une expulsion due à un manque de ressources ou une mise en maintenance du Nœud. Kubernetes utilise une abstraction de plus haut niveau, appelée un contrôleur, qui s'occupe de gérer les instances de Pods relativement jetables. Ainsi, même s'il est possible d'utiliser des Pods directement, il est beaucoup plus courant dans Kubernetes de gérer vos Pods en utilisant un contrôleur.
Pods et contrôleurs
Vous pouvez utiliser des ressources de charges de travail pour créer et gérer plusieurs Pods pour vous. Un contrôleur pour la ressource gère la réplication,
le plan de déploiement et la guérison automatique en cas de problèmes du Pod. Par exemple, si un noeud est en échec, un contrôleur note que les Pods de ce noeud
ont arrêté de fonctionner et créent des Pods pour les remplacer. L'ordonnanceur place le Pod de remplacement sur un noeud en fonctionnement.
Voici quelques exemples de ressources de charges de travail qui gèrent un ou plusieurs Pods :
Les Templates de Pod sont des spécifications pour créer des Pods, et sont inclus dans les ressources de charges de travail comme
les Deployments, les Jobs et
les DaemonSets.
Chaque contrôleur pour une ressource de charges de travail utilise le template de pod à l'intérieur de l'objet pour créer les Pods. Le template de pod fait partie de l'état désiré de la ressource de charges de travail que vous avez utilisé pour exécuter votre application.
L'exemple ci-dessous est un manifest pour un Job simple avec un template qui démarre un conteneur. Le conteneur dans ce Pod affiche un message puis se met en pause.
apiVersion:batch/v1kind:Jobmetadata:name:hellospec:template:# Ceci est un template de podspec:containers:- name:helloimage:busyboxcommand:['sh','-c','echo "Hello, Kubernetes!" && sleep 3600']restartPolicy:OnFailure# Le template de pod se termine ici
Modifier le template de pod ou changer pour un nouvau template de pod n'a pas d'effet sur les pods déjà existants. Les Pods ne reçoivent pas une mise à jour
du template directement ; au lieu de cela, un nouveau Pod est créé pour correspondre au nouveau template de pod.
Par exemple, un contrôleur de Deployment s'assure que les Pods en cours d'exécution correspondent au template de pod en cours. Si le template est mis à jour,
le contrôleur doit supprimer les pods existants et créer de nouveaux Pods avec le nouveau template. Chaque contrôleur de charges de travail implémente ses propres
règles pour gérer les changements du template de Pod.
Sur les noeuds, le kubelet n'observe ou ne gère pas directement les détails concernant les templates de pods et leurs mises à jours ; ces détails sont abstraits. Cette abstraction et cette séparation des préoccupations simplifie la sémantique du système, et rend possible l'extension du comportement du cluster sans changer le code existant.
Les Pods sont les plus petites unités informatiques déployables
qui peuvent être créées et gérées dans Kubernetes.
Qu'est-ce qu'un pod ?
Un pod (terme anglo-saxon décrivant un groupe de baleines ou une gousse de pois) est un groupe d'un ou plusieurs conteneurs
(comme des conteneurs Docker), ayant du stockage/réseau partagé, et une spécification
sur la manière d'exécuter ces conteneurs. Les éléments d'un pod sont toujours co-localisés
et co-ordonnancés, et s'exécutent dans un contexte partagé. Un pod modélise un
"hôte logique" spécifique à une application - il contient un ou plusieurs conteneurs applicatifs
qui sont étroitement liés — dans un monde pré-conteneurs, être exécuté sur la même machine
physique ou virtuelle signifierait être exécuté sur le même hôte logique.
Bien que Kubernetes prenne en charge d'autres runtimes de conteneurs que Docker, Docker est le runtime
le plus connu, et cela aide à décrire des pods en termes Docker.
Le contexte partagé d'un pod est un ensemble de namespaces Linux, cgroups, et
potentiellement d'autres facettes d'isolation - les mêmes choses qui isolent un conteneur Docker.
Dans le contexte d'un pod, les applications individuelles peuvent se voir appliquer d'autres sous-isolations.
Les conteneurs d'un pod partagent une adresse IP et un espace de ports, et peuvent communiquer via localhost.
Ils peuvent aussi communiquer entre eux en utilisant des communications inter-process standard comme
les sémaphores SystemV ou la mémoire partagée POSIX. Les conteneurs appartenant à des pods distincts ont des adresses IP
distinctes et ne peuvent pas communiquer par IPC sans configuration spécifique. Ces conteneurs communiquent en général entre eux via les adresses IP de leurs pods.
Les applications à l'intérieur d'un pod ont aussi accès à des volumes partagés,
qui sont définis dans le cadre d'un pod et sont mis à disposition pour être montés
dans le système de fichiers de chaque application.
En terme de concepts Docker, un pod est modélisé par un groupe de conteneurs Docker
ayant des namespaces et des volumes partagés.
Tout comme des conteneurs applicatifs individuels, les pods sont considérés comme des entités relativement éphémères (plutôt que durables).
Comme discuté dans Cycle de vie d'un pod, les pods sont créés, des ID uniques (UID) leurs sont assignés,
et ils sont ordonnancés sur des nœuds où il restent jusqu'à leur arrêt (selon la politique de redémarrage) ou suppression.
Si un nœud meurt, les pods ordonnancés sur ce nœud sont programmés pour être terminés, après un délai d'attente. Un pod donné (défini par un UID)
n'est pas "re-ordonnancé" sur un nouveau nœud ; par contre, il peut être remplacé par un pod identique,
ayant le même nom si désiré, mais avec un nouvel UID (voir replication
controller pour plus de détails).
Lorsque quelque chose, comme un volume, a le même cycle de vie qu'un pod, il existe aussi longtemps
que le pod (avec l'UID donné) existe. Si ce pod est supprimé pour une quelconque raison, même si un remplaçant
identique est recréé, la chose liée (par ex. le volume) est aussi détruite et créée à nouveau.
Un pod multi-conteneurs contenant un extracteur de fichiers et un serveur web
utilisant un volume persistant comme espace de stockage partagé entre les conteneurs.
Intérêts des pods
Gestion
Les pods fournissent une unité de service cohérente afin d'avoir un modèle coopératif entre plusieurs processus.
Ils simplifient le déploiement et la gestion d'applications
en fournissant une abstraction de plus haut niveau que l'ensemble des applications les constituant.
Les pods servent d'unité de déploiement, de mise à l'échelle horizontale, et de réplication.
La co-localisation (co-ordonnancement), la fin partagée (par ex. l'arrêt),
la réplication coordonnée, le partage de ressources et la gestion des dépendances sont
traités automatiquement pour les conteneurs dans un pod.
Partage de ressources et communication
Les pods permettent le partage de ressources et la communication entre ses constituants.
Les applications dans un pod utilisent toutes le même réseau (même adresse IP et espace de ports)
et peuvent donc "se trouver" entre elles et communiquer en utilisant localhost.
À cause de cela, les applications dans un pod doivent coordonner leurs usages de ports.
Chaque pod a une adresse IP dans un réseau plat partagé ayant un accès complet
aux autres hôtes et pods à travers le réseau.
Le nom d'hôte est défini avec le nom du pod pour les conteneurs applicatifs à l'intérieur du pod.
Plus de détails sur le réseau.
En plus de définir les conteneurs applicatifs s'exécutant dans le pod, le pod spécifie
un ensemble de volumes de stockage partagés. Les volumes permettent aux données de survivre
aux redémarrages de conteneurs et d'être partagés entre les applications d'un même pod.
Cas d'utilisation de pods
Des pods peuvent être utilisés pour héberger verticalement des piles applicatives intégrées (par ex. LAMP),
mais leur principal intérêt est la mise en place de programmes auxiliaires co-localisés et co-gérés, comme :
systèmes de gestion de contenu, chargeurs de fichiers et de données, gestionnaires de cache local, etc.
sauvegarde de log et checkpoint, compression, rotation, prise d'instantanés, etc.
data change watchers, log tailers, adaptateurs de logs et monitoring, éditeurs d'événements, etc.
proxies, bridges et adaptateurs
contrôleurs, gestionnaires, configurateurs et gestionnaires de mise à jour
Des pods individuels ne sont pas destinés à exécuter plusieurs instances de la même application, en général.
Pourquoi ne pas simplement exécuter plusieurs programmes dans un unique conteneur (Docker) ?
Transparence. Rendre les conteneurs à l'intérieur du pod visibles par l'infrastucture
permet à l'infrastucture de fournir des services à ces conteneurs,
comme la gestion des processus et le monitoring des ressources. Ceci
apporte un certain nombre de facilités aux utilisateurs.
Découpler les dépendances logicielles. Les conteneurs individuels peuvent être
versionnés, reconstruits et redéployés de manière indépendante. Kubernetes pourrait
même un jour prendre en charge la mise à jour à chaud de conteneurs individuels.
Facilité d'utilisation. Les utilisateurs n'ont pas besoin d'exécuter leur propre gestionnaire
de processus, de se soucier de la propagation de signaux et de codes de sortie, etc.
Efficacité. L'infrastructure prenant plus de responsabilités, les conteneurs peuvent être plus légers.
Pourquoi ne pas prendre en charge le co-ordonnancement de conteneurs basé sur les affinités ?
Cette approche pourrait fournir la co-localisation, mais ne fournirait pas la plupart
des bénéfices des pods, comme le partage de ressources, IPC, la garantie d'une fin partagée et une gestion simplifiée.
Durabilité des pods (ou manque de)
Les pods ne doivent pas être considérés comme des entités durables. Ils ne survivent pas à des erreurs d'ordonnancement, à un nœud en échec
ou à d'autres expulsions, suite à un manque de ressources ou une mise en maintenance d'un nœud.
En général, les utilisateurs n'ont pas à créer directement des pods. Ils doivent presque toujours
utiliser des contrôleurs, même pour des singletons, comme par exemple des Deployments.
Les contrôleurs fournissent l'auto-guérison à l'échelle du cluster, ainsi que la réplication et la gestion des déploiements (rollout).
Les contrôleurs comme StatefulSet
peuvent aussi prendre en charge des pods avec état (stateful).
L'utilisation d'APIs collectives comme principale primitive exposée à l'utilisateur est courante dans les systèmes d'ordonnancement de clusters, comme Borg, Marathon, Aurora, et Tupperware.
Un Pod est exposé en tant que primitive afin de faciliter :
la connexion du scheduler et du contrôleur
la possibilité d'opérations au niveau du pod sans besoin de passer par des APIs au niveau du contrôleur
le découplage du cycle de fin d'un pod de celui d'un contrôleur, comme pour l'amorçage (bootstrapping)
le découplage des contrôleurs et des services — le contrôleur d'endpoints examine uniquement des pods
la composition claire des fonctionnalités niveau Kubelet et des fonctionnalités niveau cluster — concrètement, Kubelet est le "contrôleur de pods"
les applications hautement disponibles, qui attendront que les pods soient remplacés avant leur arrêt et au moins avant leur suppression, comme dans les cas d'éviction programmée ou de pré-chargement d'image.
Arrêt de pods
Les pods représentant des processus s'exécutant sur des nœuds d'un cluster, il est important de permettre à ces processus de se terminer proprement
lorsqu'ils ne sont plus nécessaires (plutôt que d'être violemment tués avec un signal KILL et n'avoir aucune chance de libérer ses ressources). Les
utilisateurs doivent pouvoir demander une suppression et savoir quand les processus se terminent, mais aussi être capable de s'assurer que la suppression
est réellement effective. Lorsqu'un utilisateur demande la suppression d'un pod, le système enregistre le délai de grâce prévu avant que le pod puisse
être tué de force, et qu'un signal TERM soit envoyé au processus principal de chaque conteneur. Une fois la période de grâce expirée, le signal KILL
est envoyé à ces processus, et le pod est alors supprimé de l'API server. Si Kubelet ou le gestionnaire de conteneurs est redémarré lors de l'attente de l'arrêt des processus, l'arrêt sera réessayé avec la période de grâce complète.
Un exemple de déroulement :
Un utilisateur envoie une commande pour supprimer un Pod, avec une période de grâce par défaut (30s)
Le Pod dans l'API server est mis à jour avec le temps au delà duquel le Pod est considéré "mort" ainsi que la période de grâce.
Le Pod est affiché comme "Terminating" dans les listes des commandes client
(en même temps que 3) Lorsque Kubelet voit qu'un Pod a été marqué "Terminating", le temps ayant été mis en 2, il commence le processus de suppression du pod.
Si un des conteneurs du Pod a défini un preStop hook, il est exécuté à l'intérieur du conteneur. Si le preStop hook est toujours en cours d'exécution à la fin de la période de grâce, l'étape 2 est invoquée avec une courte (2 secondes) période de grâce supplémentaire une seule fois. Vous devez modifier terminationGracePeriodSeconds si le hook preStop a besoin de plus de temps pour se terminer.
Le signal TERM est envoyé aux conteneurs. Notez que tous les conteneurs du Pod ne recevront pas le signal TERM en même temps et il peut être nécessaire de définir des preStop hook si l'ordre d'arrêt est important.
(en même temps que 3) Le Pod est supprimé des listes d'endpoints des services, et n'est plus considéré comme faisant partie des pods en cours d'exécution pour les contrôleurs de réplication. Les Pods s'arrêtant lentement ne peuvent pas continuer à servir du trafic, les load balancers (comme le service proxy) les supprimant de leurs rotations.
Lorsque la période de grâce expire, les processus s'exécutant toujours dans le Pod sont tués avec SIGKILL.
Kubelet va supprimer le Pod dans l'API server en indiquant une période de grâce de 0 (suppression immédiate). Le Pod disparaît de l'API et n'est plus visible par le client.
Par défaut, toutes les suppressions ont une période de grâce de 30 secondes. La commande kubectl delete prend en charge l'option --grace-period=<secondes> permettant à l'utilisateur de spécifier sa propre valeur. La valeur 0force la suppression du pod. Avec kubectl version >= 1.5, vous devez spécifier un flag supplémentaire --force avec --grace-period=0 pour pouvoir forcer la suppression.
Suppression forcée de pods
La suppression forcée d'un pod est définie comme la suppression immédiate d'un pod de l'état du cluster et d'etcd. Lorqu'une suppression forcée est effectuée, l'apiserver n'attend pas la confirmation de kubelet que le pod a été terminé sur le nœud sur lequel il s'exécutait. Il supprime le pod de l'API immédiatement pour qu'un nouveau pod puisse être créé avec le même nom. Sur le nœud, les pods devant se terminer immédiatement se verront donner une courte période de grâce avant d'être tués de force.
Les suppressions forcées peuvent être potentiellement dangereuses pour certains pods et doivent être effectuées avec précaution. Dans le cas de pods d'un StatefulSet, veuillez vous référer à la documentation pour supprimer des Pods d'un StatefulSet.
Mode privilégié pour les conteneurs d'un pod
Depuis Kubernetes v1.1, tout conteneur d'un pod peut activer le mode privilégié, en utilisant le flag privileged du SecurityContext de la spec du conteneur. Ceci est utile pour les conteneurs voulant utiliser les capacités de Linux comme manipuler la pile réseau ou accéder aux périphériques. Les processus dans un tel conteneur ont pratiquement les mêmes privilèges que les processus en dehors d'un conteneur. En mode privilégié, il doit être plus facile d'écrire des plugins réseau et volume en tant que pods séparés ne devant pas être compilés dans kubelet.
Si le master exécute Kubernetes v1.1 ou supérieur, et les nœuds exécutent une version antérieure à v1.1, les nouveaux pods privilégiés seront acceptés par l'api-server, mais ne seront pas lancés. Il resteront en état "pending".
Si l'utilisateur appelle kubectl describe pod FooPodName, l'utilisateur peut voir la raison pour laquelle le pod est en état "pending". La table d'événements dans la sortie de la commande "describe" indiquera :
Error validating pod "FooPodName"."FooPodNamespace" from api, ignoring: spec.containers[0].securityContext.privileged: forbidden '<*>(0xc2089d3248)true'
Si le master exécute une version antérieure à v1.1, les pods privilégiés ne peuvent alors pas être créés. Si l'utilisateur tente de créer un pod ayant un conteneur privilégié, l'utilisateur obtiendra l'erreur suivante :
The Pod "FooPodName" is invalid. spec.containers[0].securityContext.privileged: forbidden '<*>(0xc20b222db0)true'
Objet de l'API
Le Pod est une ressource au plus haut niveau dans l'API REST Kubernetes. Plus de détails sur l'objet de l'API peuvent être trouvés à :
Objet de l'API Pod.
Lorsque vous créez un manifest pour un objet Pod, soyez certain que le nom spécifié est un nom de sous-domaine DNS valide.
1.3 - Cycle de vie d'un Pod
Cette page décrit le cycle de vie d'un Pod.
Phase du Pod
Le champ status d'un Pod est un objet
PodStatus,
contenant un champ phase.
La phase d'un Pod est un résumé simple et de haut niveau de l'étape à laquelle le Pod se trouve
dans son cycle de vie.
La phase n'est pas faite pour être un cumul complet d'observations de l'état
du conteneur ou du Pod, ni pour être une machine à état compréhensible.
Le nombre et la signification des valeurs de phase d'un pod sont soigneusement gardés.
Hormis ce qui est documenté ici, rien ne doit être supposé sur des Pods
ayant une valeur de phase donnée.
Voici les valeurs possibles pour phase :
Valeur
Description
Pending
Le Pod a été accepté par Kubernetes, mais une ou plusieurs images de conteneurs n'ont pas encore été créées. Ceci inclut le temps avant d'être affecté ainsi que le temps à télécharger les images à travers le réseau, ce qui peut prendre un certain temps.
Running
Le pod a été affecté à un nœud et tous les conteneurs ont été créés. Au moins un conteneur est toujours en cours d'exécution, ou est en train de démarrer ou redémarrer.
Succeeded
Tous les conteneurs du pod ont terminé avec succès et ne seront pas redémarrés.
Failed
Tous les conteneurs d'un pod ont terminé, et au moins un conteneur a terminé en échec : soit le conteneur a terminé avec un status non zéro, soit il a été arrêté par le système.
Unknown
Pour quelque raison l'état du pod ne peut pas être obtenu, en général en cas d'erreur de communication avec l'hôte du Pod.
Conditions du Pod
Un Pod a un PodStatus, qui contient un tableau de
PodConditions
à travers lesquelles le Pod est ou non passé. Chaque élément
du tableau de PodCondition a six champs possibles :
Le champ lastProbeTime fournit un timestamp auquel la condition du Pod
a été sondée pour la dernière fois.
Le champ lastTransitionTime fournit un timestamp auquel le Pod a changé de statut
pour la dernière fois.
Le champ message est un message lisible indiquant les détails de la transition.
Le champ reason est une raison unique, en un seul mot et en CamelCase de la transition
vers la dernière condition.
Le champ status est une chaîne de caractères avec les valeurs possibles "True", "False", et "Unknown".
Le champ type est une chaîne de caractères ayant une des valeurs suivantes :
PodScheduled : le Pod a été affecté à un nœud ;
Ready : le Pod est prêt à servir des requêtes et doit être rajouté aux équilibreurs
de charge de tous les Services correspondants ;
Initialized : tous les init containers
ont démarré correctement ;
ContainersReady : tous les conteneurs du Pod sont prêts.
Sondes du Conteneur
Une Sonde (Probe) est un diagnostic
exécuté périodiquement par kubelet
sur un Conteneur. Pour exécuter un diagnostic, kubelet appelle un
Handler implémenté par
le Conteneur. Il existe trois types de handlers :
ExecAction:
Exécute la commande spécifiée à l'intérieur du Conteneur. Le diagnostic
est considéré réussi si la commande se termine avec un code de retour de 0.
TCPSocketAction:
Exécute un contrôle TCP sur l'adresse IP du Conteneur et sur un port spécifié.
Le diagnostic est considéré réussi si le port est ouvert.
HTTPGetAction:
Exécute une requête HTTP Get sur l'adresse IP du Conteneur et sur un port et
un chemin spécifiés. Le diagnostic est considéré réussi si la réponse a un code
de retour supérieur ou égal à 200 et inférieur à 400.
Chaque sonde a un résultat parmi ces trois :
Success: Le Conteneur a réussi le diagnostic.
Failure: Le Conteneur a échoué au diagnostic.
Unknown: L'exécution du diagnostic a échoué, et donc aucune action ne peut être prise.
kubelet peut optionnellement exécuter et réagir à trois types de sondes sur des conteneurs
en cours d'exécution :
livenessProbe : Indique si le Conteneur est en cours d'exécution. Si
la liveness probe échoue, kubelet tue le Conteneur et le Conteneur
est soumis à sa politique de redémarrage (restart policy).
Si un Conteneur ne fournit pas de liveness probe, l'état par défaut est Success.
readinessProbe : Indique si le Conteneur est prêt à servir des requêtes.
Si la readiness probe échoue, le contrôleur de points de terminaison (Endpoints)
retire l'adresse IP du Pod des points de terminaison de tous les Services
correspodant au Pod. L'état par défaut avant le délai initial est
Failure. Si le Conteneur ne fournit pas de readiness probe, l'état par
défaut est Success.
startupProbe: Indique si l'application à l'intérieur du conteneur a démarré.
Toutes les autres probes sont désactivées si une starup probe est fournie,
jusqu'à ce qu'elle réponde avec succès. Si la startup probe échoue, le kubelet
tue le conteneur, et le conteneur est assujetti à sa politique de redémarrage.
Si un conteneur ne fournit pas de startup probe, l'état par défaut est Success.
Quand devez-vous utiliser une liveness probe ?
Si le process de votre Conteneur est capable de crasher de lui-même lorsqu'il
rencontre un problème ou devient inopérant, vous n'avez pas forcément besoin
d'une liveness probe ; kubelet va automatiquement exécuter l'action correcte
en accord avec la politique de redémarrage (restartPolicy) du Pod.
Si vous désirez que votre Conteneur soit tué et redémarré si une sonde échoue, alors
spécifiez une liveness probe et indiquez une valeur pour restartPolicy à Always
ou OnFailure.
Quand devez-vous utiliser une readiness probe ?
FEATURE STATE:Kubernetes v1.0 [stable]
Si vous voulez commencer à envoyer du trafic à un Pod seulement lorsqu'une sonde
réussit, spécifiez une readiness probe. Dans ce cas, la readiness probe peut être
la même que la liveness probe, mais l'existence de la readiness probe dans la spec
veut dire que le Pod va démarrer sans recevoir aucun trafic et va commencer
à recevoir du trafic après que la sonde réussisse.
Si votre Conteneur doit charger une grande quantité de données, des fichiers de
configuration ou exécuter des migrations au démarrage, spécifiez une readiness probe.
Si vous désirez que le Conteneur soit capable de se mettre en maintenance tout seul, vous
pouvez spécifier une readiness probe qui vérifie un point de terminaison spécifique au
readiness et différent de la liveness probe.
Notez que si vous voulez uniquement être capable de dérouter les requêtes lorsque
le Pod est supprimé, vous n'avez pas forcément besoin d'une readiness probe; lors
de sa suppression, le Pod se met automatiquement dans un état non prêt, que la
readiness probe existe ou non.
Le Pod reste dans le statut non prêt le temps que les Conteneurs du Pod s'arrêtent.
Quand devez-vous utiliser une startup probe ?
FEATURE STATE:Kubernetes v1.16 [alpha]
Si votre conteneur démarre habituellement en plus de initialDelaySeconds + failureThreshold × periodSeconds,
vous devriez spécifier une startup probe qui vérifie le même point de terminaison que la liveness probe. La valeur par défaut pour periodSeconds est 30s.
Vous devriez alors mettre sa valeur failureThreshold suffisamment haute pour permettre au conteneur de démarrer, sans changer les valeurs par défaut de la liveness probe. Ceci aide à se protéger de deadlocks.
Pour des informations détaillées sur le statut d'un Pod et d'un Conteneur, voir
PodStatus
et
ContainerStatus.
Notez que l'information rapportée comme statut d'un Pod dépend du
ContainerState actuel.
États d'un Conteneur
Une fois que le Pod est assigné à un nœud par le scheduler, kubelet commence
à créer les conteneurs en utilisant le runtime de conteneurs. Il existe trois états possibles
pour les conteneurs : en attente (Waiting), en cours d'exécution (Running) et terminé (Terminated). Pour vérifier l'état d'un conteneur, vous pouvez utiliser kubectl describe pod [POD_NAME]. L'état est affiché pour chaque conteneur du Pod.
Waiting : état du conteneur par défaut. Si le conteneur n'est pas dans un état Running ou Terminated, il est dans l'état Waiting. Un conteneur dans l'état Waiting exécute
les opérations nécessaires, comme télécharger les images, appliquer des Secrets, etc. À côté
de cet état, un message et une raison sur l'état sont affichés pour vous fournir plus
d'informations.
...State:WaitingReason:ErrImagePull...
Running : Indique que le conteneur s'exécute sans problème. Le hook postStart (s'il existe) est exécuté avant que le conteneur entre dans l'état Running. Cet état affiche aussi le moment auquel le conteneur est entré dans l'état Running.
...State:RunningStarted:Wed, 30 Jan 2019 16:46:38 +0530...
Terminated: Indique que le conteneur a terminé son exécution et s'est arrêté.
Un conteneur entre dans cet état lorsqu'il s'est exécuté avec succès ou lorsqu'il a
échoué pour une raison quelconque. De plus, une raison et un code de retour sont affichés,
ainsi que les moments de démarrage et d'arrêt du conteneur. Avant qu'un conteneur entre
dans l'état Terminated, le hook preStop est exécuté (s'il existe).
...State:TerminatedReason:CompletedExit Code:0Started:Wed, 30 Jan 2019 11:45:26 +0530Finished:Wed, 30 Jan 2019 11:45:26 +0530...
Pod readiness
FEATURE STATE:Kubernetes v1.14 [stable]
Votre application peut injecter des données dans PodStatus.
Pod readiness. Pour utiliser cette fonctionnalité, remplissez readinessGates dans le PodSpec avec
une liste de conditions supplémentaires que le kubelet évalue pour la disponibilité du Pod.
Les Readiness gates sont déterminées par l'état courant des champs status.condition du Pod.
Si Kubernetes ne peut pas trouver une telle condition dans le champs status.conditions d'un Pod, the statut de la condition
est mise par défaut à "False".
Voici un exemple :
kind:Pod...spec:readinessGates:- conditionType:"www.example.com/feature-1"status:conditions:- type:Ready # une PodCondition intégréestatus:"False"lastProbeTime:nulllastTransitionTime:2018-01-01T00:00:00Z- type:"www.example.com/feature-1"# une PodCondition supplémentairestatus:"False"lastProbeTime:nulllastTransitionTime:2018-01-01T00:00:00ZcontainerStatuses:- containerID:docker://abcd...ready:true...
Les conditions du Pod que vous ajoutez doivent avoir des noms qui sont conformes au format des étiquettes de Kubernetes.
Statut de la disponibilité d'un Pod
La commande kubectl patch ne peut pas patcher le statut d'un objet.
Pour renseigner ces status.conditions pour le pod, les applications et
operators doivent utiliser l'action PATCH.
Vous pouvez utiliser une bibliothèque client Kubernetes pour
écrire du code qui renseigne les conditions particulières pour la disponibilité dun Pod.
Pour un Pod utilisant des conditions particulières, ce Pod est considéré prêt seulement
lorsque les deux déclarations ci-dessous sont vraies :
Tous les conteneurs du Pod sont prêts.
Toutes les conditions spécifiées dans ReadinessGates sont True.
Lorsque les conteneurs d'un Pod sont prêts mais qu'au moins une condition particulière
est manquante ou False, le kubelet renseigne la condition du Pod à ContainersReady.
Politique de redémarrage
La structure PodSpec a un champ restartPolicy avec comme valeur possible
Always, OnFailure et Never. La valeur par défaut est Always.
restartPolicy s'applique à tous les Conteneurs du Pod. restartPolicy s'applique
seulement aux redémarrages des Conteneurs par kubelet sur le même nœud. Des conteneurs
terminés qui sont redémarrés par kubelet sont redémarrés avec un délai exponentiel
(10s, 20s, 40s ...) plafonné à cinq minutes, qui est réinitialisé après dix minutes
d'exécution normale. Comme discuté dans le
document sur les Pods,
une fois attaché à un nœud, un Pod ne sera jamais rattaché à un autre nœud.
Durée de vie d'un Pod
En général, les Pods restent jusqu'à ce qu'un humain ou un process de
contrôleur les supprime explicitement.
Le plan de contrôle nettoie les Pods terminés (avec une phase à Succeeded ou
Failed), lorsque le nombre de Pods excède le seuil configuré
(determiné par terminated-pod-gc-threshold dans le kube-controller-manager).
Ceci empêche une fuite de ressources lorsque les Pods sont créés et supprimés au fil du temps.
Il y a différents types de ressources pour créer des Pods :
Utilisez un Job
pour les Pods qui sont censés se terminer une fois leur tâche accomplie. Les Jobs sont appropriés
seulement pour des Pods ayant restartPolicy égal à OnFailure ou Never.
Utilisez un DaemonSet
pour les Pods qui doivent s'exécuter sur chaque noeud éligible.
Toutes les ressources de charges de travail contiennent une PodSpec. Il est recommandé de créer
la ressource de charges de travail appropriée et laisser le contrôleur de la ressource créer les Pods
pour vous, plutôt que de créer directement les Pods vous-même.
Si un nœud meurt ou est déconnecté du reste du cluster, Kubernetes applique
une politique pour mettre la phase de tous les Pods du nœud perdu à Failed.
Exemples
Exemple avancé de liveness probe
Les Liveness probes sont exécutées par kubelet, toutes les requêtes sont donc faites
dans l'espace réseau de kubelet.
apiVersion:v1kind:Podmetadata:labels:test:livenessname:liveness-httpspec:containers:- args:- /serverimage:k8s.gcr.io/livenesslivenessProbe:httpGet:# lorsque "host" n'est pas défini, "PodIP" sera utilisé# host: my-host# lorsque "scheme" n'est pas défini, "HTTP" sera utilisé. "HTTP" et "HTTPS" sont les seules valeurs possibles# scheme: HTTPSpath:/healthzport:8080httpHeaders:- name:X-Custom-Headervalue:AwesomeinitialDelaySeconds:15timeoutSeconds:1name:liveness
Exemples d'états
Un Pod est en cours d'exécution et a un Conteneur. Le conteneur se termine avec succès.
Écriture d'un événement de complétion.
Si restartPolicy est :
Always : Redémarrage du Conteneur ; la phase du Pod reste à Running.
OnFailure : la phase du Pod passe à Succeeded.
Never : la phase du Pod passe à Succeeded.
Un Pod est en cours d'exécution et a un Conteneur. Le conteneur se termine en erreur.
Écriture d'un événement d'échec.
Si restartPolicy est :
Always : Redémarrage du Conteneur ; la phase du Pod reste à Running.
OnFailure : Redémarrage du Conteneur ; la phase du Pod reste à Running.
Never : la phase du Pod passe à Failed.
Un Pod est en cours d'exécution et a deux Conteneurs. Le conteneur 1 termine en erreur.
Écriture d'un événement d'échec.
Si restartPolicy est :
Always : Redémarrage du Conteneur ; la phase du Pod reste à Running.
OnFailure : Redémarrage du Conteneur ; la phase du Pod reste à Running.
Never : Le Conteneur n'est pas redémarré ; la phase du Pod reste à Running.
Si Container 1 est arrêté, et Conteneur 2 se termine :
Écriture d'un événement d'échec.
Si restartPolicy est :
Always : Redémarrage du Conteneur ; la phase du Pod reste à Running.
OnFailure : Redémarrage du Conteneur ; la phase du Pod reste à Running.
Never : la phase du Pod passe à Failed.
Un Pod est en cours d'exécution et a un Conteneur. Le Conteneur n'a plus assez de mémoire.
Le Conteneur se termine en erreur.
Écriture d'un événement OOM.
Si restartPolicy est :
Always : Redémarrage du Conteneur ; la phase du Pod reste à Running.
OnFailure : Redémarrage du Conteneur ; la phase du Pod reste à Running.
Never : Écriture d'un événement d'erreur ; la phase du Pod passe à Failed.
Le Pod est en cours d'exécution, et un disque meurt.
Tous les conteneurs sont tués.
Écriture d'un événement approprié.
La phase du Pod devient Failed.
Si le Pod s'exécute sous un contrôleur, le Pod est recréé ailleurs.
Le Pod est en cours d'exécution et son nœud est segmenté.
Le contrôleur de Nœud attend un certain temps.
Le contrôleur de Nœud passe la phase du Pod à Failed.
Si le Pod s'exécute sous un contrôleur, le Pod est recréé ailleurs.
1.4 - Contraintes de propagation de topologie pour les Pods
FEATURE STATE:Kubernetes v1.18 [beta]
Vous pouvez utiliser des contraintes de propagation de topologie pour contrôler comment les Pods sont propagés à travers votre cluster parmi les domaines de défaillance comme les régions, zones, noeuds et autres domaines de topologie définis par l'utilisateur. Ceci peut aider à mettre en place de la haute disponibilité et à utiliser efficacement les ressources.
Les contraintes de propagation de topologie reposent sur les labels de noeuds pour identifier le ou les domaines de topologie dans lesquels se trouve chacun des noeuds. Par exemple, un noeud pourrait avoir les labels: node=node1,zone=us-east-1a,region=us-east-1
Supposons que vous ayez un cluster de 4 noeuds ayant les labels suivants:
NAME STATUS ROLES AGE VERSION LABELS
node1 Ready <none> 4m26s v1.16.0 node=node1,zone=zoneA
node2 Ready <none> 3m58s v1.16.0 node=node2,zone=zoneA
node3 Ready <none> 3m17s v1.16.0 node=node3,zone=zoneB
node4 Ready <none> 2m43s v1.16.0 node=node4,zone=zoneB
Plutôt que d'appliquer des labels manuellement, vous pouvez aussi réutiliser les labels réputés qui sont créés et renseignés automatiquement dans la plupart des clusters.
Contraintes de propagation pour les Pods
API
Le champ pod.spec.topologySpreadConstraints est introduit dans 1.16 comme suit :
Vous pouvez définir une ou plusieurs topologySpreadConstraint pour indiquer au kube-scheduler comment placer chaque nouveau Pod par rapport aux Pods déjà existants dans votre cluster. Les champs sont :
maxSkew décrit le degré avec lequel les Pods peuvent être inégalement distribués. C'est la différence maximale permise entre le nombre de Pods correspondants entre deux quelconques domaines de topologie d'un type donné. Il doit être supérieur à zéro.
topologyKey est la clé des labels de noeuds. Si deux noeuds sont étiquettés avec cette clé et ont des valeurs égales pour ce label, le scheduler considère les deux noeuds dans la même topologie. Le scheduler essaie de placer un nombre équilibré de Pods dans chaque domaine de topologie.
whenUnsatisfiable indique comment traiter un Pod qui ne satisfait pas les contraintes de propagation :
DoNotSchedule (défaut) indique au scheduler de ne pas le programmer.
ScheduleAnyway indique au scheduler de le programmer, tout en priorisant les noeuds minimisant le biais (skew).
labelSelector est utilisé pour touver les Pods correspondants. Les Pods correspondants à ce sélecteur de labels sont comptés pour déterminer le nombre de Pods dans leurs domaines de topologie correspodants. Voir Sélecteurs de labels pour plus de détails.
Vous pouvez en savoir plus sur ces champ en exécutant kubectl explain Pod.spec.topologySpreadConstraints.
Exemple : Une TopologySpreadConstraint
Supposons que vous ayez un cluster de 4 noeuds où 3 Pods étiquettés foo:bar sont placés sur node1, node2 et node3 respectivement (P représente un Pod) :
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
| P | P | P | |
+-------+-------+-------+-------+
Si nous voulons qu'un nouveau Pod soit uniformément réparti avec les Pods existants à travers les zones, la spec peut être :
topologyKey: zone implique que la distribution uniforme sera uniquement appliquée pour les noeuds ayant le label "zone:<any value>" présent. whenUnsatisfiable: DoNotSchedule indique au scheduler de laisser le Pod dans l'état Pending si le Pod entrant ne peut pas satisfaire la contrainte.
Si le scheduler plaçait ce Pod entrant dans "zoneA", la distribution des Pods deviendrait [3, 1], et le biais serait de 2 (3 - 1) - ce qui va à l'encontre de maxSkew: 1. Dans cet exemple, le Pod entrant peut uniquement être placé dans "zoneB":
+---------------+---------------+ +---------------+---------------+
| zoneA | zoneB | | zoneA | zoneB |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
| node1 | node2 | node3 | node4 | OR | node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
| P | P | P | P | | P | P | P P | |
+-------+-------+-------+-------+ +-------+-------+-------+-------+
Vous pouvez ajuster la spec du Pod pour pour répondre à divers types d'exigences :
Changez maxSkew pour une valeur plus grande comme "2" pour que le Pod entrant puisse aussi être placé dans la "zoneA".
Changez topologyKey pour "node" pour distribuer les Pods uniformément à travers les noeuds et non plus les zones. Dans l'exemple ci-dessus, si maxSkew reste à "1", le Pod entrant peut être uniquement placé dans "node4".
Changez whenUnsatisfiable: DoNotSchedule en whenUnsatisfiable: ScheduleAnyway pour s'assurer que le Pod est toujours programmable (en supposant que les autres APIs de scheduling soient satisfaites). Cependant, il sera de préférence placé dans la topologie de domaine ayant le moins de Pods correspondants. (Prenez note que cette préférence est normalisée conjointement avec d'autres priorités de scheduling interne comme le ratio d'usage de ressources, etc.)
Example: Plusieurs TopologySpreadConstraints
Cela s'appuie sur l'exemple précédent. Supposons que vous ayez un cluster de 4 noeuds où 3 Pods étiquetés foo:bar sont placés sur node1, node2 et node3 respectivement (P représente un Pod):
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
| P | P | P | |
+-------+-------+-------+-------+
Vous pouvez utiliser 2 TopologySpreadConstraints pour contrôler la répartition des Pods aussi bien dans les zones que dans les noeuds :
Dans ce cas, pour satisfaire la première contrainte, le Pod entrant peut uniquement être placé dans "zoneB" ; alors que pour satisfaire la seconde contrainte, le Pod entrant peut uniquement être placé dans "node4". Le résultat étant l'intersection des résultats des 2 contraintes, l'unique option possible est de placer le Pod entrant dans "node4".
Plusieurs contraintes peuvent entraîner des conflits. Supposons que vous ayez un cluster de 3 noeuds couvrant 2 zones :
+---------------+-------+
| zoneA | zoneB |
+-------+-------+-------+
| node1 | node2 | node3 |
+-------+-------+-------+
| P P | P | P P |
+-------+-------+-------+
Si vous appliquez "two-constraints.yaml" à ce cluster, vous noterez que "mypod" reste dans l'état Pending. Cela parce que : pour satisfaire la première contrainte, "mypod" peut uniquement être placé dans "zoneB"; alors que pour satisfaire la seconde contrainte, "mypod" peut uniquement être placé sur "node2". Ainsi, le résultat de l'intersection entre "zoneB" et "node2" ne retourne rien.
Pour surmonter cette situation, vous pouvez soit augmenter maxSkew, soit modifier une des contraintes pour qu'elle utilise whenUnsatisfiable: ScheduleAnyway.
Conventions
Il existe quelques conventions implicites qu'il est intéressant de noter ici :
Seuls le Pods du même espace de noms que le Pod entrant peuvent être des candidats pour la correspondance.
Les noeuds sans label topologySpreadConstraints[*].topologyKey seront ignorés. Cela induit que :
les Pods localisés sur ces noeuds n'impactent pas le calcul de maxSkew - dans l'exemple ci-dessus, supposons que "node1" n'a pas de label "zone", alors les 2 Pods ne seront pas comptés, et le Pod entrant sera placé dans "zoneA".
le Pod entrant n'a aucune chance d'être programmé sur ce type de noeuds - dans l'exemple ci-dessus, supposons qu'un "node5" portant un label {zone-typo: zoneC} joigne le cluster ; il sera ignoré, en raison de l'absence de label "zone".
Faites attention à ce qui arrive lorsque le topologySpreadConstraints[*].labelSelector du Pod entrant ne correspond pas à ses propres labels. Dans l'exemple ci-dessus, si nous supprimons les labels du Pod entrant, il sera toujours placé dans "zoneB" car les contraintes sont toujours satisfaites. Cependant, après le placement, le degré de déséquilibre du cluster reste inchangé - zoneA contient toujours 2 Pods ayant le label {foo:bar}, et zoneB contient 1 Pod cayant le label {foo:bar}. Si ce n'est pas ce que vous attendez, nous recommandons que topologySpreadConstraints[*].labelSelector du workload corresponde à ses propres labels.
Si le Pod entrant a défini spec.nodeSelector ou spec.affinity.nodeAffinity, les noeuds non correspondants seront ignorés.
Supposons que vous ayez un cluster de 5 noeuds allant de zoneA à zoneC :
et vous savez que "zoneC" doit être exclue. Dans ce cas, vous pouvez écrire le yaml ci-dessous, pour que "mypod" soit placé dans "zoneB" plutôt que dans "zoneC". spec.nodeSelector est pris en compte de la même manière.
Il est possible de définir des contraintes de propagation de topologie par défaut pour un cluster. Les contraintes de propagation de topologie sont appliquées à un Pod si et seulement si :
Il ne définit aucune contrainte dans son .spec.topologySpreadConstraints.
Il appartient à un service, replication controller, replica set ou stateful set.
Les contraintes par défaut peuvent être définies comme arguments du plugin PodTopologySpread
dans un profil de scheduling.
Les contraintes sont spécifiées avec la même API ci-dessus, à l'exception que
labelSelector doit être vide. Les sélecteurs sont calculés à partir des services,
replication controllers, replica sets ou stateful sets auxquels le Pod appartient.
Un exemple de configuration pourrait ressembler à :
Note: Le score produit par les contraintes de scheduling par défaut peuvent rentrer en conflit avec le score
produit par le plugin DefaultPodTopologySpread.
Il est recommandé de désactiver ce plugin dans le profil de scheduling lorsque vous utilisez des contraintes
par défaut pour PodTopologySpread.
Comparaison avec PodAffinity/PodAntiAffinity
Dans Kubernetes, les directives relatives aux "Affinités" contrôlent comment les Pods sont
programmés - plus regroupés ou plus dispersés.
Pour PodAffinity, vous pouvez essayer de regrouper un certain nombre de Pods dans des domaines de topologie qualifiés,
Pour PodAntiAffinity, seulement un Pod peut être programmé dans un domaine de topologie unique.
La fonctionnalité "EvenPodsSpread" fournit des options flexibles pour distribuer des Pods uniformément sur différents domaines de topologie - pour mettre en place de la haute disponibilité ou réduire les coûts. Cela peut aussi aider
au rolling update des charges de travail et à la mise à l'échelle de réplicas. Voir Motivations pour plus de détails.
Limitations connues
En version 1.18, pour laquelle cette fonctionnalité est en Beta, il y a quelques limitations connues :
Réduire un Déploiement peut résulter en une distrubution désiquilibrée des Pods.
Les Pods correspondants sur des noeuds taintés sont respectés. Voir Issue 80921
1.5 - Init Containers
Cette page fournit une vue d'ensemble des conteneurs d'initialisation (init containers) : des conteneurs spécialisés qui s'exécutent avant les conteneurs d'application dans un Pod.
Les init containers peuvent contenir des utilitaires ou des scripts d'installation qui ne sont pas présents dans une image d'application.
Vous pouvez spécifier des init containers dans la spécification du Pod à côté du tableau containers (qui décrit les conteneurs d'application)
Comprendre les init containers
Un Pod peut avoir plusieurs conteneurs exécutant des applications mais peut aussi avoir un ou plusieurs init containers, qui sont exécutés avant que les conteneurs d'application ne démarrent.
Les init containers se comportent comme les conteneurs réguliers, avec quelques différences :
Les init containers s'exécutent toujours jusqu'à la complétion.
Chaque init container doit se terminer avec succès avant que le prochain ne démarre.
Si le init container d'un Pod échoue, Kubernetes redémarre le Pod à répétition jusqu'à ce que le init container se termine avec succès.
Cependant, si le Pod a une restartPolicy à "Never", Kubernetes ne redémarre pas le Pod.
Afin de spécifier un init container pour un Pod, il faut ajouter le champ initContainers dans la spécification du Pod, comme un
tableau d'objets de type Container, au même niveau que le tableau d'applications containers.
Le statut des init containers est retourné dans le champ .status.initContainerStatuses
comme un tableau des statuts du conteneur (comparable au champ .status.containerStatuses).
Différences avec les conteneurs réguliers
Les init containers supportent tous les champs et fonctionnalités des conteneurs d'application
incluant les limites de ressources, les volumes et les paramètres de sécurité.
Cependant, les demandes de ressources pour un init container sont gérées différemment des
limites de ressources, tel que documenté dans Ressources.
De plus, les init containers ne supportent pas les readiness probes parce que ces conteneurs
s'exécutent jusqu'au bout avant que le Pod soit prêt.
Si l'on spécifie plusieurs init containers pour un Pod, Kubelet exécute chaque
init container de manière séquentielle.
Chaque init container doit se terminer avec succès avant que le prochain ne puisse s'exécuter.
Lorsque tous les init containers se sont exécutés jusqu'au bout, Kubelet initialise
les conteneurs d'application pour le Pod et les exécute comme d'habitude.
Utiliser les init containers
Puisque les init containers ont des images séparées des conteneurs d'application,
ils apportent certains avantages pour du code de mise en route :
Les init containers peuvent contenir des utilitaires ou du code de configuration personnalisé
qui ne sont pas présents dans une image d'application.
Par exemple, il n'y a pas besoin de faire hériter une image d'une autre (FROM) seulement pour utiliser
un outil comme sed, awk, python, ou dig pendant l'installation.
Les init containers peuvent exécuter en toute sécurité des utilitaires qui rendraient moins sécurisée une image de conteneur d'application.
Les rôles "builder" et "deployer" d'une image d'application peuvent travailler indépendamment sans qu'il n'y ait besoin
de créer conjointement une seule image d'application.
Les init containers peuvent s'exécuter avec une vue du système de fichiers différente de celle des conteneurs d'application dans le même Pod. Par conséquent, on peut leur donner accès aux Secrets, auxquels les conteneurs d'application n'ont pas accès.
Puisque les init containers s'exécutent jusqu'à la complétion avant qu'un conteneur d'application ne démarre, les init containers
offrent un mécanisme pour bloquer ou retarder le démarrage d'un conteneur d'application tant qu'un ensemble de préconditions n'est pas respecté. Une fois que les préconditions sont respectées, tous les conteneurs d'application dans un Pod peuvent démarrer en parallèle.
Exemples
Voici plusieurs idées pour utiliser les init containers :
Attendre qu'un Service soit créé,
en utilisant une commande shell d'une ligne telle que :
for i in {1..100}; do sleep 1; if dig myservice; thenexit 0; fi; done; exit1
Enregistrer ce Pod à un serveur distant depuis l'API downward avec une commande telle que :
curl -X POST http://$MANAGEMENT_SERVICE_HOST:$MANAGEMENT_SERVICE_PORT/register -d 'instance=$(<POD_NAME>)&ip=$(<POD_IP>)'
Attendre un certain temps avant de démarrer le conteneur d'application avec une commande telle que :
Placer des valeurs dans un fichier de configuration et exécuter un outil de templating pour générer
dynamiquement un fichier de configuration pour le conteneur d'application principal.
Par exemple, placer la valeur POD_IP dans une configuration et générer le fichier de configuration de l'application principale
en utilisant Jinja.
Les init containers en utilisation
Cet exemple définit un simple Pod possédant deux init containers.
Le premier attend myservice et le second attend mydb. Une fois que les deux
init containers terminent leur exécution, le Pod exécute le conteneur d'application décrit dans sa section spec.
apiVersion:v1kind:Podmetadata:name:myapp-podlabels:app.kubernetes.io/name:MyAppspec:containers:- name:myapp-containerimage:busybox:1.28command:['sh','-c','echo "L''app s''exécute!" && sleep 3600']initContainers:- name:init-myserviceimage:busybox:1.28command:['sh','-c',"until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo en attente de myservice; sleep 2; done"]- name:init-mydbimage:busybox:1.28command:['sh','-c',"until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo en attente de mydb; sleep 2; done"]
Les fichiers YAML suivants résument les services mydb et myservice :
Vous verrez ensuite que ces init containers se terminent et que le Pod myapp-pod évolue vers l'état "Running" (en exécution) :
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 1/1 Running 0 9m
Cet exemple simple devrait suffire à vous inspirer pour créer vos propres init containers.
A suivre contient un lien vers un exemple plus détaillé.
Comportement détaillé
Pendant le démarrage d'un Pod, chaque init container démarre en ordre, après que le réseau
et les volumes ont été initialisés. Chaque conteneur doit se terminer avec succès avant que le prochain
ne démarre. Si un conteneur n'arrive pas à démarrer à cause d'un problème d'exécution ou
se termine avec un échec, il est redémarré selon la restartPolicy du Pod.
Toutefois, si la restartPolicy du Pod est configurée à "Always", les init containers utilisent la restartPolicy "OnFailure".
Un Pod ne peut pas être Ready tant que tous les init containers ne se sont pas exécutés avec succès.
Les ports d'un init container ne sont pas agrégés sous un Service. Un Pod qui s'initialise
est dans l'état Pending mais devrait avoir une condition Initialized configurée à "true".
Si le Pod redémarre ou est redémarré, tous les init containers
doivent s'exécuter à nouveau.
Les changements aux spec d'un init containers sont limités au champ image du conteneur.
Changer le champ image d'un init container équivaut à redémarrer le Pod.
Puisque les init containers peuvent être redémarrés, réessayés ou ré-exécutés,
leur code doit être idempotent. En particulier, le code qui écrit dans des fichiers sur EmptyDirs
devrait être préparé à la possibilité qu'un fichier de sortie existe déjà.
Les init containers ont tous les champs d'un conteneur d'application.
Cependant, Kubernetes interdit l'utilisation de readinessProbe parce que les init containers
ne peuvent pas définir une "readiness" distincte de la complétion. Ceci est appliqué lors de la validation.
L'utilisation de activeDeadlineSeconds sur le Pod et livenessProbe sur le conteneur
permet d'empêcher les init containers d'échouer tout le temps.
La deadline active inclut les init containers.
Le nom de chaque application et init container dans un Pod doit être unique; une erreur de validation
est générée pour tout conteneur partageant un nom avec un autre.
Ressources
Étant donné l'ordonnancement et l'exécution des init containers, les règles suivantes s'appliquent pour l'utilisation des ressources :
La plus haute requête ou limite particulière de ressource définie pour tous les init containers
est la limite/requête d'initialisation effective
La limite/requête effective d'un Pod pour une ressource est la plus haute parmis :
la somme de toutes les requêtes/limites des conteneurs d'application pour une ressource
la limite/requête d'initialisation effective pour une ressource
Le Scheduling est effectué sur la base des requêtes/limites effectives, ce qui signifie
que les init containers peuvent réserver des ressources pour l'initialisation qui ne sont pas utilisées durant le
cycle de vie du Pod.
La QoS (qualité de service) tierce de la QoS tierce effective d'un Pod est la QoS tierce aussi bien pour les init containers
que pour les conteneurs d'application.
Les quotas et limites sont appliqués sur la base de la requête/limite effective d'un Pod.
Les groupes de contrôle au niveau du Pod (cgroups) sont basés sur la requête/limite effective de Pod, la même que
celle du scheduler.
Raisons du redémarrage d'un Pod
Un Pod peut redémarrer, ce qui cause la ré-exécution des init containers, pour les raisons suivantes :
Un utilisateur met à jour les spécifications du Pod, ce qui cause le changement de l'image de l'init container.
Tout changement à l'image du init container redémarre le Pod. Les changements au conteneur d'application entraînent seulement le
redémarrage du conteneur d'application.
Le conteneur d'infrastructure Pod est redémarré. Ceci est peu commun et serait effectué par une personne ayant un accès root aux nœuds.
Tous les conteneurs dans un Pod sont terminés tandis que restartPolicy est configurée à "Always", ce qui force le redémarrage, et l'enregistrement de complétion du init container a été perdu à cause d'une opération de garbage collection (récupération de mémoire).
Un ReplicaSet (ensemble de réplicas en français) a pour but de maintenir un ensemble stable de Pods à un moment donné.
Cet objet est souvent utilisé pour garantir la disponibilité d'un certain nombre identique de Pods.
Comment un ReplicaSet fonctionne
Un ReplicaSet est défini avec des champs, incluant un selecteur qui spécifie comment identifier les Pods qu'il peut posséder,
un nombre de replicas indiquant le nombre de Pods qu'il doit maintenir et un modèle de Pod spécifiant les données que les
nouveaux Pods que le replicatSet va créer jusqu'au nombre de replicas demandé.
Un ReplicaSet va atteindre son objectif en créant et supprimant des Pods pour atteindre le nombre de réplicas désirés.
Quand un ReplicaSet a besoin de créer de nouveaux Pods, il utilise alors son Pod template.
Le lien d'un ReplicaSet à ses Pods est fait par le champ metadata.ownerReferences,
qui spécifie la ressource de l'objet par lequel il est détenu. Tous les Pods acquis par un ReplicaSet ont leurs propres informations d'identification de leur Replicaset, avec leur propre champ ownerReferences. C'est par ce lien que le ReplicaSet connait l'état des Pods qu'il maintient et agit en fonction de ces derniers.
Un ReplicaSet identifie des nouveaux Pods à acquérir en utilisant son selecteur.
Si il y a un Pod qui n'a pas de OwnerReference ou que OwnerReference n'est pas un controller et qu'il correspond à un sélecteur de ReplicaSet, il va immédiatement être acquis par ce ReplicaSet.
Quand utiliser un ReplicaSet ?
Un ReplicaSet garantit qu’un nombre spécifié de réplicas de Pod soient exécutés à un moment donné.
Cependant, un Deployment est un concept de plus haut niveau qui gère les ReplicaSets et
fournit des mises à jour déclaratives aux Pods ainsi que de nombreuses autres fonctionnalités utiles.
Par conséquent, nous vous recommandons d’utiliser des Deployments au lieu d’utiliser directement des ReplicaSets, sauf si
vous avez besoin d'une orchestration personnalisée des mises à jour ou si vous n'avez pas besoin de mises à jour.
Cela signifie qu'il est possible que vous n'ayez jamais besoin de manipuler des objets ReplicaSet :
utilisez plutôt un déploiement et définissez votre application dans la section spec.
apiVersion:apps/v1kind:ReplicaSetmetadata:name:frontendlabels:app:guestbooktier:frontendspec:# modify replicas according to your casereplicas:3selector:matchLabels:tier:frontendtemplate:metadata:labels:tier:frontendspec:containers:- name:php-redisimage:gcr.io/google_samples/gb-frontend:v3
Enregistrer ce manifeste dans frontend.yaml et le soumettre à un cluster Kubernetes va créer le ReplicaSet défini et les pods qu’il gère.
Vous pouvez ensuite récupérer les ReplicaSets actuellement déployés :
kubectl get rs
Et voir le frontend que vous avez créé :
NAME DESIRED CURRENT READY AGE
frontend 333 6s
Vous pouvez également vérifier l'état du ReplicaSet :
kubectl describe rs/frontend
Et vous verrez une sortie similaire à :
Name: frontend
Namespace: default
Selector: tier=frontend,tier in (frontend)Labels: app=guestbook
tier=frontend
Annotations: <none>
Replicas: 3 current / 3 desired
Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed
Pod Template:
Labels: app=guestbook
tier=frontend
Containers:
php-redis:
Image: gcr.io/google_samples/gb-frontend:v3
Port: 80/TCP
Requests:
cpu: 100m
memory: 100Mi
Environment:
GET_HOSTS_FROM: dns
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1{replicaset-controller } Normal SuccessfulCreate Created pod: frontend-qhloh
1m 1m 1{replicaset-controller } Normal SuccessfulCreate Created pod: frontend-dnjpy
1m 1m 1{replicaset-controller } Normal SuccessfulCreate Created pod: frontend-9si5l
Et enfin, vous pourrez afficher les Pods déployés :
kubectl get Pods
Vous devriez voir des informations sur les Pods avec une sortie similaire à :
NAME READY STATUS RESTARTS AGE
frontend-9si5l 1/1 Running 0 1m
frontend-dnjpy 1/1 Running 0 1m
frontend-qhloh 1/1 Running 0 1m
Vous pouvez également vérifier que la OwnerReference de ces pods est définie sur le frontend ReplicaSet.
Pour ce faire, récupérez le yaml de l’un des pods :
kubectl get pods frontend-9si5l -o yaml
La sortie sera similaire à celle-ci, avec les informations de l'interface ReplicaSet frontend définies dans le champ ownerReferences des métadonnées:
Bien que vous puissiez créer des pods manuellement sans problème, il est fortement recommandé de s’assurer que ces pods n'ont pas de
labels correspondant au sélecteur de l’un de vos ReplicaSets. Car un ReplicaSet n’est pas limité
à posséder les pods spécifiés par son modèle - il peut acquérir d’autres pods de la manière spécifiée dans les sections précédentes.
Prenez l'exemple précédent de ReplicaSet, ainsi que les pods spécifiés dans le manifeste suivant :
Ces pods n’ayant pas de contrôleur (ni d’objet) en tant que référence propriétaire, ils correspondent au sélecteur de du ReplicaSet frontend, ils seront donc immédiatement acquis par ce ReplicaSet.
Supposons que vous créiez les pods une fois le ReplicaSet frontend déployé et qui a déjà déployé ses replicas de Pods initiaux afin de
remplir son exigence de nombre de replicas :
Vous verrez que le ReplicaSet a acquis les pods et n'a créé que les nouveaux Pods manquants, conformément à ses spécifications,
jusqu'au nombre souhaité de Pods. En récupérant les Pods :
kubectl get Pods
La sortie va donner :
NAME READY STATUS RESTARTS AGE
frontend-pxj4r 1/1 Running 0 5s
pod1 1/1 Running 0 13s
pod2 1/1 Running 0 13s
De cette manière, un ReplicaSet peut avoir un ensemble de Pods hétérogène.
Écrire un manifest de ReplicaSet
Comme avec tous les autres objets API Kubernetes, un ReplicaSet a besoin des champs apiVersion, kind et metadata.
Pour ReplicaSets, l'attribut kind est toujours ReplicaSet.
Dans Kubernetes 1.9, la version de l'API apps/v1 pour le type ReplicaSet est la version actuelle et activée par défaut. La version de l'API apps/v1beta2 est obsolète.
Reportez-vous aux premières lignes de l'exemple frontend.yaml pour obtenir des conseils.
L'attribut .spec.template est un modèle de pod qui requiert d'avoir des labels. Dans notre exemple frontend.yaml, nous avons un label : tier: frontend.
Il faut faire attention à ne pas avoir des selecteurs que d'autres controllers utilisent, afin d'éviter que le ReplicaSet n'adopte ce pod.
Pour le champ restart policy,
.spec.template.spec.restartPolicy, la seule valeur autorisée est Always, qui est la valeur par défaut.
Sélecteur de Pod
Le champ .spec.selector est un label selector. Tel que discuté
précédemment, ce sont les labels utilisés pour identifier les Pods potentiels à acquérir. Dans notre
exemple avec frontend.yaml, le sélecteur était :
matchLabels:
tier: frontend
Dans le ReplicaSet, .spec.template.metadata.labels doit correspondre à spec.selector, ou sinon il sera rejeté par l'API.
Note: Pour 2 ReplicaSets spécifiant le même .spec.selector mais différents .spec.template.metadata.labels et .spec.template.spec, chaque ReplicaSet ignore les pods créés par l'autre ReplicaSet.
Replicas
Vous pouvez spécifier le nombre de pods à exécuter simultanément en définissant .spec.replicas. Le ReplicaSet va créer/supprimer
ses pods pour correspondre à ce nombre.
Si vous ne spécifiez pas .spec.replicas, la valeur par défaut est 1.
Travailler avec des ReplicaSets
Suppression d'un ReplicaSet et de ses pods
Pour supprimer un ReplicaSet et tous ses pods, utilisez kubectl delete. The Garbage collector supprime automatiquement tous les pods associés par défaut.
Lors de l’utilisation de l’API REST ou de la bibliothèque client-go, vous devez définir propagationPolicy sur Background ou Foreground dans
l'option -d.
Par exemple :
Vous pouvez supprimer un ReplicaSet sans affecter ses pods à l’aide de kubectl delete avec l'option --cascade=orphan.
Lorsque vous utilisez l'API REST ou la bibliothèque client-go, vous devez définir propagationPolicy sur Orphan.
Par exemple :
Une fois l’original supprimé, vous pouvez créer un nouveau ReplicaSet pour le remplacer. Tant que l'ancien et le nouveau .spec.selector sont identiques, le nouveau adoptera les anciens Pods.
Cependant, le ReplicaSet ne fera aucun effort pour que les pods existants correspondent à un nouveau Pod template.
Pour mettre à jour les Pods à une nouvelle spec de manière contrôlée, utilisez un
Deployment, car les ReplicaSets ne supportent pas de rolling update directement.
Isoler les pods d'un ReplicaSet
Vous pouvez supprimer les pods d'un ReplicaSet en modifiant leurs labels. Cette technique peut être utilisée pour enlever les pods
pour le débogage, récupération de données, etc. Les pods ainsi supprimés seront automatiquement remplacés
(en supposant que le nombre de réplicas n’est pas également modifié).
Scaling d'un ReplicaSet
Un ReplicaSet peut facilement être scalé en mettant simplement à jour le champ .spec.replicas. Le contrôleur ReplicaSet
garantit que le nombre souhaité de pods avec un sélecteur de label correspondant soient disponibles et opérationnels.
ReplicaSet en tant que Horizontal Pod Autoscaler Target
Un ReplicaSet peut également être une cible pour
Horizontal Pod Autoscalers (HPA).
Un ReplicaSet peut être mis à l'échelle automatiquement par un HPA. Voici un exemple HPA qui cible
le ReplicaSet que nous avons créé dans l'exemple précédent.
Enregistrer ce manifeste dans hpa-rs.yaml et le soumettre à un cluster Kubernetes devrait
créer le HPA défini qui scale automatiquement le ReplicaSet cible en fonction de l'utilisation du processeur
des pods répliqués.
Vous pouvez aussi utiliser la commande kubectl autoscale pour accomplir la même chose.
(et c'est plus facile !)
kubectl autoscale rs frontend --max=10
Alternatives au ReplicaSet
Deployment (recommandé)
Le Deployment est un object qui peut posséder les ReplicaSets et les mettres à jour ainsi que leurs Pods de façon déclarative, côté serveur et avec des rolling updates.
Alors que les ReplicaSets peuvent être utilisés indépendamment, ils sont principalement utilisés aujourd'hui par Deployments comme mécanisme pour orchestrer la création, suppresion et mises à jour des Pods.
Lorsque vous utilisez des Deployments, vous n’aurez plus à vous soucier de la gestion des ReplicaSets ainsi créés.
Les déploiements possèdent et gèrent leurs ReplicaSets.
C'est pourquoi il est recommandé d’utiliser les déploiements lorsque vous voulez des ReplicaSets.
Pods nus
Contrairement au cas où un utilisateur a créé directement des pods, un ReplicaSet remplace les pods supprimés ou terminés pour quelque raison que ce soit, par exemple en cas de défaillance d'un nœud ou de maintenance de nœud perturbateur, telle qu'une mise à jour kernel. Pour cette raison, nous vous recommandons d'utiliser un ReplicaSet même si votre application ne nécessite qu'un seul pod. Pensez-y de la même manière qu’un superviseur de processus, mais il supervise plusieurs pods sur plusieurs nœuds au lieu de processus individuels sur un seul nœud. Un ReplicaSet délègue les redémarrages de conteneurs locaux à un agent du nœud (par exemple, Kubelet ou Docker).
Job
Utilisez un Job au lieu d'un ReplicaSet pour les pods qui doivent se terminer seuls
(c'est à dire des batch jobs).
DaemonSet
Utilisez un DaemonSet au lieu d’un ReplicaSet pour les pods qui fournissent une
fonction au niveau du noeud, comme le monitoring ou la gestion des logs de ce noeud. Ces pods ont une durée de vie qui est liée
durée de vie d’une machine : le pod doit être en cours d’exécution sur la machine avant le démarrage des autres Pods et sont
sûrs de se terminer lorsque la machine est prête à être redémarrée/arrêtée.
ReplicationController
Les ReplicaSets sont les successeurs de ReplicationControllers.
Les deux servent le même objectif et se comportent de la même manière, à la différence près que ReplicationController ne prend pas en charge les
les exigences de sélecteur décrites dans le labels user guide.
En tant que tels, les ReplicaSets sont préférés aux ReplicationControllers.
2.2 - Déploiements
Un Deployment (déploiement en français) fournit des mises à jour déclaratives pour Pods et ReplicaSets.
Vous décrivez un état désiré dans un déploiement et le controlleur déploiement change l'état réel à l'état souhaité à un rythme contrôlé.
Vous pouvez définir des Deployments pour créer de nouveaux ReplicaSets, ou pour supprimer des déploiements existants et adopter toutes leurs ressources avec de nouveaux déploiements.
Note: Ne gérez pas les ReplicaSets appartenant à un Deployment.
Pensez à ouvrir un ticket dans le dépot Kubernetes principal si votre cas d'utilisation n'est pas traité ci-dessous.
Cas d'utilisation
Voici des cas d'utilisation typiques pour les déploiements:
Déclarez le nouvel état des Pods en mettant à jour le PodTemplateSpec du déploiement.
Un nouveau ReplicaSet est créé et le déploiement gère le déplacement des pods de l'ancien ReplicaSet vers le nouveau à un rythme contrôlé.
Chaque nouveau ReplicaSet met à jour la révision du déploiement.
Un déploiement nommé nginx-deployment est créé, indiqué par le champ .metadata.name.
Le déploiement crée trois pods répliqués, indiqués par le champ replicas.
Le champ selector définit comment le déploiement trouve les pods à gérer.
Dans ce cas, vous sélectionnez simplement un label définie dans le template de pod (app:nginx).
Cependant, des règles de sélection plus sophistiquées sont possibles, tant que le modèle de pod satisfait lui-même la règle.
Note: Le champ matchLabels est une table de hash {clé, valeur}.
Une seule {clé, valeur} dans la table matchLabels est équivalente à un élément de matchExpressions, dont le champ clé est "clé", l'opérateur est "In" et le tableau de valeurs contient uniquement "valeur".
Toutes les exigences, à la fois de matchLabels et de matchExpressions, doivent être satisfaites pour correspondre.
Le champ template contient les sous-champs suivants:
Les Pods reçoivent le label app:nginx dans le champ labels.
La spécification du template de pod dans le champ .template.spec, indique que les pods exécutent un conteneur, nginx, qui utilise l'image nginxDocker Hub à la version 1.7.9.
Créez un conteneur et nommez-le nginx en utilisant le champ name.
Suivez les étapes ci-dessous pour créer le déploiement ci-dessus:
Avant de commencer, assurez-vous que votre cluster Kubernetes est opérationnel.
Créez le déploiement en exécutant la commande suivante:
Note: Vous pouvez spécifier l'indicateur --record pour écrire la commande exécutée dans l'annotation de ressource kubernetes.io/change-cause.
C'est utile pour une future introspection.
Par exemple, pour voir les commandes exécutées dans chaque révision de déploiement.
Exécutez kubectl get deployments pour vérifier si le déploiement a été créé.
Si le déploiement est toujours en cours de création, la sortie est similaire à:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 0/3 00 1s
Lorsque vous inspectez les déploiements de votre cluster, les champs suivants s'affichent:
NAME répertorie les noms des déploiements dans le cluster.
DESIRED affiche le nombre souhaité de répliques de l'application, que vous définissez lorsque vous créez le déploiement.
C'est l'état désiré.
CURRENT affiche le nombre de réplicas en cours d'exécution.
UP-TO-DATE affiche le nombre de réplicas qui ont été mises à jour pour atteindre l'état souhaité.
AVAILABLE affiche le nombre de réplicas de l'application disponibles pour vos utilisateurs.
AGE affiche la durée d'exécution de l'application.
Notez que le nombre de réplicas souhaitées est de 3 selon le champ .spec.replicas.
Pour voir l'état du déploiement, exécutez:
kubectl rollout status deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
Exécutez à nouveau kubectl get deployments quelques secondes plus tard.
La sortie est similaire à ceci:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18s
Notez que le déploiement a créé les trois répliques et que toutes les répliques sont à jour (elles contiennent le dernier modèle de pod) et disponibles.
Pour voir le ReplicaSet (rs) créé par le déploiement, exécutez kubectl get rs.
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE
nginx-deployment-75675f5897 3 3 3 18s
Notez que le nom du ReplicaSet est toujours formaté comme: [DEPLOYMENT-NAME]-[RANDOM-STRING].
La chaîne aléatoire est générée aléatoirement et utilise le pod-template-hash comme graine.
Pour voir les labels générées automatiquement pour chaque Pod, exécutez kubectl get pods --show-labels.
La sortie est similaire à ceci:
NAME READY STATUS RESTARTS AGE LABELS
nginx-deployment-75675f5897-7ci7o 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-kzszj 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
nginx-deployment-75675f5897-qqcnn 1/1 Running 0 18s app=nginx,pod-template-hash=3123191453
Le ReplicaSet créé garantit qu'il y a trois pods nginx.
Note: Vous devez spécifier un sélecteur approprié et des labels de template de pod dans un déploiement (dans ce cas, app: nginx).
Ne superposez pas les étiquettes ou les sélecteurs avec d'autres contrôleurs (y compris d'autres déploiements et StatefulSets).
Kubernetes n'empêche pas les chevauchements de noms, et si plusieurs contrôleurs ont des sélecteurs qui se chevauchent, ces contrôleurs peuvent entrer en conflit et se comporter de façon inattendue.
Étiquette pod-template-hash
Note: Ne modifiez pas ce label.
Le label pod-template-hash est ajoutée par le contrôleur de déploiement à chaque ReplicaSet créé ou adopté par un déploiement.
Ce label garantit que les ReplicaSets enfants d'un déploiement ne se chevauchent pas.
Il est généré en hachant le PodTemplate du ReplicaSet et en utilisant le hachage résultant comme valeur de label qui est ajoutée au sélecteur ReplicaSet, aux labels de template de pod et dans tous les pods existants que le ReplicaSet peut avoir.
Mise à jour d'un déploiement
Note: Le re-déploiement d'un déploiement est déclenché si et seulement si le modèle de pod du déploiement (c'est-à-dire .spec.template) est modifié, par exemple si les labels ou les images de conteneur du template sont mis à jour.
D'autres mises à jour, telles que la mise à l'échelle du déploiement, ne déclenchent pas de rollout.
Suivez les étapes ci-dessous pour mettre à jour votre déploiement:
Mettons à jour les pods nginx pour utiliser l'image nginx: 1.9.1 au lieu de l'image nginx: 1.7.9.
kubectl --record deployment.apps/nginx-deployment set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
ou utilisez la commande suivante:
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1 --record
La sortie est similaire à ceci:
deployment.apps/nginx-deployment image updated
Alternativement, vous pouvez éditer le déploiement et changer .spec.template.spec.containers[0].image de nginx: 1.7.9 à nginx: 1.9.1:
kubectl edit deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
deployment.apps/nginx-deployment edited
Pour voir l'état du déploiement, exécutez:
kubectl rollout status deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
ou
deployment "nginx-deployment" successfully rolled out
Obtenez plus de détails sur votre déploiement mis à jour:
Une fois le déploiement réussi, vous pouvez afficher le déploiement en exécutant kubectl get deployments.
La sortie est similaire à ceci:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 36s
Exécutez kubectl get rs pour voir que le déploiement a mis à jour les pods en créant un nouveau ReplicaSet et en le redimensionnant jusqu'à 3 replicas, ainsi qu'en réduisant l'ancien ReplicaSet à 0 réplicas.
kubectl get rs
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 6s
nginx-deployment-2035384211 0 0 0 36s
L'exécution de kubectl get pods ne devrait désormais afficher que les nouveaux pods:
kubectl get pods
La sortie est similaire à ceci:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-khku8 1/1 Running 0 14s
nginx-deployment-1564180365-nacti 1/1 Running 0 14s
nginx-deployment-1564180365-z9gth 1/1 Running 0 14s
La prochaine fois que vous souhaitez mettre à jour ces pods, il vous suffit de mettre à jour le modèle de pod de déploiement à nouveau.
Le déploiement garantit que seul un certain nombre de pods sont en panne pendant leur mise à jour.
Par défaut, il garantit qu'au moins 75% du nombre souhaité de pods sont en place (25% max indisponible).
Le déploiement garantit également que seul un certain nombre de pods sont créés au-dessus du nombre souhaité de pods.
Par défaut, il garantit qu'au plus 125% du nombre de pods souhaité sont en hausse (surtension maximale de 25%).
Par exemple, si vous regardez attentivement le déploiement ci-dessus, vous verrez qu'il a d'abord créé un nouveau pod, puis supprimé certains anciens pods et en a créé de nouveaux.
Il ne tue pas les anciens Pods tant qu'un nombre suffisant de nouveaux Pods n'est pas apparu, et ne crée pas de nouveaux Pods tant qu'un nombre suffisant de Pods anciens n'a pas été tué.
Il s'assure qu'au moins 2 pods sont disponibles et qu'au maximum 4 pods au total sont disponibles.
Obtenez les détails de votre déploiement:
kubectl describe deployments
La sortie est similaire à ceci:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Thu, 30 Nov 2017 10:56:25 +0000
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=2
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-1564180365 (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 2m deployment-controller Scaled up replica set nginx-deployment-2035384211 to 3
Normal ScalingReplicaSet 24s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 1
Normal ScalingReplicaSet 22s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 2
Normal ScalingReplicaSet 22s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 2
Normal ScalingReplicaSet 19s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 1
Normal ScalingReplicaSet 19s deployment-controller Scaled up replica set nginx-deployment-1564180365 to 3
Normal ScalingReplicaSet 14s deployment-controller Scaled down replica set nginx-deployment-2035384211 to 0
Ici, vous voyez que lorsque vous avez créé le déploiement pour la première fois, il a créé un ReplicaSet (nginx-deployment-2035384211) et l'a mis à l'échelle directement jusqu'à 3 réplicas.
Lorsque vous avez mis à jour le déploiement, il a créé un nouveau ReplicaSet (nginx-deployment-1564180365) et l'a mis à l'échelle jusqu'à 1, puis a réduit l'ancien ReplicaSet à 2, de sorte qu'au moins 2 pods étaient disponibles et au plus 4 pods ont été créés à chaque fois.
Il a ensuite poursuivi la montée en puissance du nouveau et de l'ancien ReplicaSet, avec la même stratégie de mise à jour continue.
Enfin, vous aurez 3 réplicas disponibles dans le nouveau ReplicaSet, et l'ancien ReplicaSet est réduit à 0.
Rollover (alias plusieurs mises à jour en vol)
Chaque fois qu'un nouveau déploiement est observé par le contrôleur de déploiement, un ReplicaSet est créé pour afficher les pods souhaités.
Si le déploiement est mis à jour, le ReplicaSet existant qui contrôle les pods dont les étiquettes correspondent à .spec.selector mais dont le modèle ne correspond pas à .spec.template est réduit.
Finalement, le nouveau ReplicaSet est mis à l'échelle à .spec.replicas et tous les anciens ReplicaSets sont mis à l'échelle à 0.
Si vous mettez à jour un déploiement alors qu'un déploiement existant est en cours, le déploiement crée un nouveau ReplicaSet conformément à la mise à jour et commence à le mettre à l'échelle, et arrête de mettre à jour le ReplicaSet qu'il augmentait précédemment - il l'ajoutera à sa liste de anciens ReplicaSets et commencera à le réduire.
Par exemple, supposons que vous créez un déploiement pour créer 5 répliques de nginx: 1.7.9, puis mettez à jour le déploiement pour créer 5 répliques de nginx: 1.9.1, alors que seulement 3 répliques de nginx:1.7.9 avait été créés.
Dans ce cas, le déploiement commence immédiatement à tuer les 3 pods nginx: 1.7.9 qu'il avait créés et commence à créer des pods nginx: 1.9.1.
Il n'attend pas que les 5 répliques de nginx: 1.7.9 soient créées avant de changer de cap.
Mises à jour du sélecteur de labels
Il est généralement déconseillé de mettre à jour le sélecteur de labels et il est suggéré de planifier vos sélecteurs à l'avance.
Dans tous les cas, si vous devez effectuer une mise à jour du sélecteur de labels, soyez très prudent et assurez-vous d'avoir saisi toutes les implications.
Note: Dans la version d'API apps/v1, le sélecteur de label d'un déploiement est immuable après sa création.
Les ajouts de sélecteur nécessitent que les labels de template de pod dans la spécification de déploiement soient également mises à jour avec les nouveaux labels, sinon une erreur de validation est renvoyée.
Cette modification ne se chevauche pas, ce qui signifie que le nouveau sélecteur ne sélectionne pas les ReplicaSets et les pods créés avec l'ancien sélecteur, ce qui entraîne la perte de tous les anciens ReplicaSets et la création d'un nouveau ReplicaSet.
Les mises à jour du sélecteur modifient la valeur existante dans une clé de sélection - entraînent le même comportement que les ajouts.
La suppression de sélecteur supprime une clé existante du sélecteur de déploiement - ne nécessite aucune modification dans les labels du template de pod.
Les ReplicaSets existants ne sont pas orphelins et aucun nouveau ReplicaSet n'est créé, mais notez que le label supprimé existe toujours dans tous les Pods et ReplicaSets existants.
Annulation d'un déploiement
Parfois, vous souhaiterez peut-être annuler un déploiement; par exemple, lorsque le déploiement n'est pas stable, comme en cas d'échecs à répétition (CrashLoopBackOff).
Par défaut, tout l'historique des déploiements d'un déploiement est conservé dans le système afin que vous puissiez le restaurer à tout moment (vous pouvez le modifier en modifiant la limite de l'historique des révisions).
Note: La révision d'un déploiement est créée lorsque le déploiement d'un déploiement est déclenché.
Cela signifie qu'une nouvelle révision est créée si et seulement si le template de pod de déploiement (.spec.template) est modifié, par exemple si vous mettez à jour les labels ou les images de conteneur du template.
D'autres mises à jour, telles que la mise à l'échelle du déploiement, ne créent pas de révision de déploiement, de sorte que vous puissiez faciliter la mise à l'échelle manuelle ou automatique simultanée.
Cela signifie que lorsque vous revenez à une révision antérieure, seule la partie du template de pod de déploiement est annulée.
Supposons que vous ayez fait une faute de frappe lors de la mise à jour du déploiement, en mettant le nom de l'image sous la forme nginx:1.91 au lieu de nginx: 1.9.1:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true
La sortie est similaire à ceci:
deployment.apps/nginx-deployment image updated
Le déploiement est bloqué.
Vous pouvez le vérifier en vérifiant l'état du déploiement:
kubectl rollout status deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
Waiting for rollout to finish: 1 out of 3 new replicas have been updated...
Appuyez sur Ctrl-C pour arrêter la surveillance d'état de déploiement ci-dessus.
Pour plus d'informations sur les déploiements bloqués, en savoir plus ici.
Vous voyez que le nombre d'anciens réplicas (nginx-deployment-1564180365 et nginx-deployment-2035384211) est 2, et les nouveaux réplicas (nginx-deployment-3066724191) est 1.
kubectl get rs
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1564180365 3 3 3 25s
nginx-deployment-2035384211 0 0 0 36s
nginx-deployment-3066724191 1 1 0 6s
En regardant les pods créés, vous voyez que 1 pod créé par le nouveau ReplicaSet est coincé dans une boucle pour récupérer son image:
kubectl get pods
La sortie est similaire à ceci:
NAME READY STATUS RESTARTS AGE
nginx-deployment-1564180365-70iae 1/1 Running 0 25s
nginx-deployment-1564180365-jbqqo 1/1 Running 0 25s
nginx-deployment-1564180365-hysrc 1/1 Running 0 25s
nginx-deployment-3066724191-08mng 0/1 ImagePullBackOff 0 6s
Note: Le contrôleur de déploiement arrête automatiquement le mauvais déploiement et arrête la mise à l'échelle du nouveau ReplicaSet.
Cela dépend des paramètres rollingUpdate (maxUnavailable spécifiquement) que vous avez spécifiés.
Kubernetes définit par défaut la valeur à 25%.
Obtenez la description du déploiement:
kubectl describe deployment
La sortie est similaire à ceci:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Tue, 15 Mar 2016 14:48:04 -0700
Labels: app=nginx
Selector: app=nginx
Replicas: 3 desired | 1 updated | 4 total | 3 available | 1 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.91
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
OldReplicaSets: nginx-deployment-1564180365 (3/3 replicas created)
NewReplicaSet: nginx-deployment-3066724191 (1/1 replicas created)
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
1m 1m 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-2035384211 to 3
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 1
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 2
22s 22s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 2
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 1
21s 21s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-1564180365 to 3
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled down replica set nginx-deployment-2035384211 to 0
13s 13s 1 {deployment-controller } Normal ScalingReplicaSet Scaled up replica set nginx-deployment-3066724191 to 1
Pour résoudre ce problème, vous devez revenir à une version précédente de Deployment qui est stable.
Vérification de l'historique de déploiement d'un déploiement
Suivez les étapes ci-dessous pour vérifier l'historique de déploiement:
Tout d'abord, vérifiez les révisions de ce déploiement:
kubectl rollout history deployment.v1.apps/nginx-deployment
CHANGE-CAUSE est copié de l'annotation de déploiement kubernetes.io/change-cause dans ses révisions lors de la création.
Vous pouvez spécifier le messageCHANGE-CAUSE en:
Annoter le déploiement avec kubectl annotate deployment.v1.apps/nginx-deployment kubernetes.io/change-cause="image mis à jour en 1.9.1"
Ajoutez le drapeau --record pour enregistrer la commande kubectl qui apporte des modifications à la ressource.
Modification manuelle du manifeste de la ressource.
Pour voir les détails de chaque révision, exécutez:
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
Pour plus de détails sur les commandes liées au déploiement, lisez kubectl rollout.
Le déploiement est maintenant rétabli à une précédente révision stable.
Comme vous pouvez le voir, un événement DeploymentRollback pour revenir à la révision 2 est généré à partir du contrôleur de déploiement.
Vérifiez si la restauration a réussi et que le déploiement s'exécute comme prévu, exécutez:
kubectl get deployment nginx-deployment
La sortie est similaire à ceci:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 30m
Obtenez la description du déploiement:
kubectl describe deployment nginx-deployment
La sortie est similaire à ceci:
Name: nginx-deployment
Namespace: default
CreationTimestamp: Sun, 02 Sep 2018 18:17:55 -0500
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision=4
kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.9.1
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-c4747d96c (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 12m deployment-controller Scaled up replica set nginx-deployment-75675f5897 to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 2
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 1
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-c4747d96c to 3
Normal ScalingReplicaSet 11m deployment-controller Scaled down replica set nginx-deployment-75675f5897 to 0
Normal ScalingReplicaSet 11m deployment-controller Scaled up replica set nginx-deployment-595696685f to 1
Normal DeploymentRollback 15s deployment-controller Rolled back deployment "nginx-deployment" to revision 2
Normal ScalingReplicaSet 15s deployment-controller Scaled down replica set nginx-deployment-595696685f to 0
Mise à l'échelle d'un déploiement
Vous pouvez mettre à l'échelle un déploiement à l'aide de la commande suivante:
En supposant que l'horizontal Pod autoscaling est activé dans votre cluster, vous pouvez configurer une mise à l'échelle automatique pour votre déploiement et choisir le nombre minimum et maximum de pods que vous souhaitez exécuter en fonction de l'utilisation du processeur de vos pods existants.
Les déploiements RollingUpdate prennent en charge l'exécution simultanée de plusieurs versions d'une application.
Lorsque vous ou un autoscaler mettez à l'échelle un déploiement RollingUpdate qui se trouve au milieu d'un déploiement (en cours ou en pause), le contrôleur de déploiement équilibre les réplicas supplémentaires dans les ReplicaSets actifs existants (ReplicaSets avec pods) afin d'atténuer le risque.
Ceci est appelé mise à l'échelle proportionnelle.
Par exemple, vous exécutez un déploiement avec 10 réplicas, maxSurge=3, et maxUnavailable=2.
Assurez-vous que les 10 réplicas de votre déploiement sont en cours d'exécution.
kubectl get deploy
La sortie est similaire à ceci:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 10 10 10 10 50s
Vous effectuez une mise à jour vers une nouvelle image qui s'avère impossible à résoudre depuis l'intérieur du cluster.
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:sometag
La sortie est similaire à ceci:
deployment.apps/nginx-deployment image updated
La mise à jour de l'image démarre un nouveau déploiement avec ReplicaSet nginx-deployment-1989198191, mais elle est bloquée en raison de l'exigence maxUnavailable que vous avez mentionnée ci-dessus.
Découvrez l'état du déploiement:
kubectl get rs
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 5 5 0 9s
nginx-deployment-618515232 8 8 8 1m
Ensuite, une nouvelle demande de mise à l'échelle pour le déploiement arrive.
La mise à l'échelle automatique incrémente les réplicas de déploiement à 15.
Le contrôleur de déploiement doit décider où ajouter ces 5 nouvelles répliques.
Si vous n'utilisiez pas la mise à l'échelle proportionnelle, les 5 seraient ajoutés dans le nouveau ReplicaSet.
Avec une mise à l'échelle proportionnelle, vous répartissez les répliques supplémentaires sur tous les ReplicaSets.
Des proportions plus importantes vont aux ReplicaSets avec le plus de répliques et des proportions plus faibles vont aux ReplicaSets avec moins de replicas.
Tous les restes sont ajoutés au ReplicaSet avec le plus de répliques.
Les ReplicaSets avec zéro réplicas ne sont pas mis à l'échelle.
Dans notre exemple ci-dessus, 3 répliques sont ajoutées à l'ancien ReplicaSet et 2 répliques sont ajoutées au nouveau ReplicaSet.
Le processus de déploiement devrait éventuellement déplacer toutes les répliques vers le nouveau ReplicaSet, en supposant que les nouvelles répliques deviennent saines.
Pour confirmer cela, exécutez:
kubectl get deploy
La sortie est similaire à ceci:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 15 18 7 8 7m
Le statut de déploiement confirme la façon dont les réplicas ont été ajoutés à chaque ReplicaSet.
kubectl get rs
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE
nginx-deployment-1989198191 7 7 0 7m
nginx-deployment-618515232 11 11 11 7m
Pause et reprise d'un déploiement
Vous pouvez suspendre un déploiement avant de déclencher une ou plusieurs mises à jour, puis le reprendre.
Cela vous permet d'appliquer plusieurs correctifs entre la pause et la reprise sans déclencher de déploiements inutiles.
Par exemple, avec un déploiement qui vient d'être créé:
Obtenez les détails du déploiement:
kubectl get deploy
La sortie est similaire à ceci:
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx 3 3 3 3 1m
Obtenez le statut de déploiement:
kubectl get rs
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 3 3 3 1m
Mettez le déploiement en pause en exécutant la commande suivante:
L'état initial du déploiement avant de le suspendre continuera de fonctionner, mais les nouvelles mises à jour du déploiement n'auront aucun effet tant que le déploiement sera suspendu.
Finalement, reprenez le déploiement et observez un nouveau ReplicaSet à venir avec toutes les nouvelles mises à jour:
NAME DESIRED CURRENT READY AGE
nginx-2142116321 0 0 0 2m
nginx-3926361531 3 3 3 28s
Note: Vous ne pouvez pas annuler un déploiement suspendu avant de le reprendre.
Statut de déploiement
Un déploiement entre dans différents états au cours de son cycle de vie.
Il peut être progressant lors du déploiement d'un nouveau ReplicaSet, il peut être effectué, ou il peut ne pas progresser.
Progression du déploiement
Kubernetes marque un déploiement comme progressing lorsqu'une des tâches suivantes est effectuée:
Le déploiement crée un nouveau ReplicaSet.
Le déploiement augmente son nouveau ReplicaSet.
Le déploiement réduit ses anciens ReplicaSet.
De nouveaux pods deviennent prêts ou disponibles (prêt pour au moins MinReadySeconds).
Vous pouvez surveiller la progression d'un déploiement à l'aide de kubectl rollout status.
Déploiement effectué
Kubernetes marque un déploiement comme effectué lorsqu'il présente les caractéristiques suivantes:
Toutes les répliques associées au déploiement ont été mises à jour vers la dernière version que vous avez spécifiée, ce qui signifie que toutes les mises à jour que vous avez demandées ont été effectuées.
Toutes les répliques associées au déploiement sont disponibles.
Aucune ancienne réplique pour le déploiement n'est en cours d'exécution.
Vous pouvez vérifier si un déploiement est terminé en utilisant kubectl rollout status.
Si le déploiement s'est terminé avec succès, kubectl rollout status renvoie un code de sortie de 0.
kubectl rollout status deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
Waiting for rollout to finish: 2 of 3 updated replicas are available...
deployment "nginx-deployment" successfully rolled out
$ echo $?
0
Déploiement échoué
Votre déploiement peut rester bloqué en essayant de déployer son nouveau ReplicaSet sans jamais terminer.
Cela peut se produire en raison de certains des facteurs suivants:
Quota insuffisant
Échecs de la sonde de préparation
Erreurs d'extraction d'image
Permissions insuffisantes
Plages limites
Mauvaise configuration de l'exécution de l'application
Vous pouvez détecter cette condition en spécifiant un paramètre d'échéance dans votre spécification de déploiement:
(.spec.progressDeadlineSeconds).
.spec.progressDeadlineSeconds indique le nombre de secondes pendant lesquelles le contrôleur de déploiement attend avant d'indiquer (dans l'état de déploiement) que la progression du déploiement est au point mort.
La commande kubectl suivante définit la spécification avec progressDeadlineSeconds pour que le contrôleur signale l'absence de progression pour un déploiement après 10 minutes:
Une fois le délai dépassé, le contrôleur de déploiement ajoute un DeploymentCondition avec les attributs suivants aux .status.conditions du déploiement:
Note: Kubernetes ne prend aucune mesure sur un déploiement bloqué, sauf pour signaler une condition d'état avec Reason=ProgressDeadlineExceeded.
Les orchestrateurs de niveau supérieur peuvent en tirer parti et agir en conséquence, par exemple, restaurer le déploiement vers sa version précédente.
Note: Si vous suspendez un déploiement, Kubernetes ne vérifie pas la progression par rapport à votre échéance spécifiée.
Vous pouvez suspendre un déploiement en toute sécurité au milieu d'un déploiement et reprendre sans déclencher la condition de dépassement du délai.
Vous pouvez rencontrer des erreurs transitoires avec vos déploiements, soit en raison d'un délai d'attente bas que vous avez défini, soit en raison de tout autre type d'erreur pouvant être traité comme transitoire.
Par exemple, supposons que votre quota soit insuffisant.
Si vous décrivez le déploiement, vous remarquerez la section suivante:
kubectl describe deployment nginx-deployment
La sortie est similaire à ceci:
<...>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True ReplicaSetUpdated
ReplicaFailure True FailedCreate
<...>
Si vous exécutez kubectl get deployment nginx-deployment -o yaml, l'état de déploiement est similaire à ceci:
status:availableReplicas:2conditions:- lastTransitionTime:2016-10-04T12:25:39ZlastUpdateTime:2016-10-04T12:25:39Zmessage:Replica set "nginx-deployment-4262182780" is progressing.reason:ReplicaSetUpdatedstatus:"True"type:Progressing- lastTransitionTime:2016-10-04T12:25:42ZlastUpdateTime:2016-10-04T12:25:42Zmessage:Deployment has minimum availability.reason:MinimumReplicasAvailablestatus:"True"type:Available- lastTransitionTime:2016-10-04T12:25:39ZlastUpdateTime:2016-10-04T12:25:39Zmessage: 'Error creating:pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:object-counts, requested: pods=1, used: pods=3, limited:pods=2'reason:FailedCreatestatus:"True"type:ReplicaFailureobservedGeneration:3replicas:2unavailableReplicas:2
Finalement, une fois la date limite de progression du déploiement dépassée, Kubernetes met à jour le statut et la raison de la condition de progression:
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing False ProgressDeadlineExceeded
ReplicaFailure True FailedCreate
Vous pouvez résoudre un problème de quota insuffisant en réduisant votre déploiement, en réduisant d'autres contrôleurs que vous exécutez ou en augmentant le quota de votre namespace.
Si vous remplissez les conditions de quota et que le contrôleur de déploiement termine ensuite le déploiement de déploiement, vous verrez la mise à jour de l'état du déploiement avec une condition réussie (Status=True et Reason=NewReplicaSetAvailable).
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
Type=Available avec Status=True signifie que votre déploiement a une disponibilité minimale.
La disponibilité minimale est dictée par les paramètres spécifiés dans la stratégie de déploiement.
Type=Progressing avec Status=True signifie que votre déploiement est soit au milieu d'un déploiement et qu'il progresse ou qu'il a terminé avec succès sa progression et que les nouvelles répliques minimales requises sont disponibles (voir la raison de la condition pour les détails - dans notre cas, Reason=NewReplicaSetAvailable signifie que le déploiement est terminé).
Vous pouvez vérifier si un déploiement n'a pas pu progresser en utilisant kubectl rollout status.
kubectl rollout status renvoie un code de sortie différent de zéro si le déploiement a dépassé le délai de progression.
kubectl rollout status deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
Waiting for rollout to finish: 2 out of 3 new replicas have been updated...
error: deployment "nginx" exceeded its progress deadline
$ echo $?
1
Agir sur un déploiement échoué
Toutes les actions qui s'appliquent à un déploiement complet s'appliquent également à un déploiement ayant échoué.
Vous pouvez le mettre à l'échelle à la hausse/baisse, revenir à une révision précédente ou même la suspendre si vous devez appliquer plusieurs réglages dans le modèle de pod de déploiement.
Politique de nettoyage
Vous pouvez définir le champ .spec.revisionHistoryLimit dans un déploiement pour spécifier le nombre d'anciens ReplicaSets pour ce déploiement que vous souhaitez conserver.
Le reste sera effacé en arrière-plan.
Par défaut, c'est 10.
Note: La définition explicite de ce champ sur 0 entraînera le nettoyage de tout l'historique de votre déploiement, de sorte que le déploiement ne pourra pas revenir en arrière.
Déploiement des Canaries
Si vous souhaitez déployer des versions sur un sous-ensemble d'utilisateurs ou de serveurs à l'aide du déploiement, vous pouvez créer plusieurs déploiements, un pour chaque version, en suivant le modèle canari décrit dans gestion des ressources.
Écriture d'une spécification de déploiement
Comme pour toutes les autres configurations Kubernetes, un déploiement a besoin des champs apiVersion, kind et metadata.
Pour des informations générales sur l'utilisation des fichiers de configuration, voir déploiement d'applications, configuration des conteneurs, et Utilisation de kubectl pour gérer les ressources.
Un déploiement nécessite également un .spec section.
Pod Template
Les .spec.template et .spec.selector sont les seuls champs obligatoires du .spec.
Le .spec.template est un Pod template.
Il a exactement le même schéma qu'un Pod, sauf qu'il est imbriqué et n'a pas de apiVersion ou de kind.
En plus des champs obligatoires pour un pod, un Pod Template dans un déploiement doit spécifier des labels appropriées et une stratégie de redémarrage appropriée.
Pour les labels, assurez-vous de ne pas chevaucher l'action d'autres contrôleurs.
Voir sélecteur).
.spec.replicas est un champ facultatif qui spécifie le nombre de pods souhaités.
Il vaut par défaut 1.
Sélecteur
.spec.selector est un champ obligatoire qui spécifie un sélecteur de labels pour les pods ciblés par ce déploiement.
.spec.selector doit correspondre .spec.template.metadata.labels, ou il sera rejeté par l'API.
Dans la version d'API apps/v1, .spec.selector et .metadata.labels ne sont pas définis par défaut sur .spec.template.metadata.labels s'ils ne sont pas définis.
Ils doivent donc être définis explicitement.
Notez également que .spec.selector est immuable après la création du déploiement dans apps/v1.
Un déploiement peut mettre fin aux pods dont les étiquettes correspondent au sélecteur si leur modèle est différent de .spec.template ou si le nombre total de ces pods dépasse .spec.replicas.
Il fait apparaître de nouveaux pods avec .spec.template si le nombre de pods est inférieur au nombre souhaité.
Note: Vous ne devez pas créer d'autres pods dont les labels correspondent à ce sélecteur, soit directement, en créant un autre déploiement, soit en créant un autre contrôleur tel qu'un ReplicaSet ou un ReplicationController.
Si vous le faites, le premier déploiement pense qu'il a créé ces autres pods.
Kubernetes ne vous empêche pas de le faire.
Si vous avez plusieurs contrôleurs qui ont des sélecteurs qui se chevauchent, les contrôleurs se battront entre eux et ne se comporteront pas correctement.
Stratégie
.spec.strategy spécifie la stratégie utilisée pour remplacer les anciens pods par de nouveaux.
.spec.strategy.type peut être "Recreate" ou "RollingUpdate".
"RollingUpdate" est la valeur par défaut.
Déploiment Recreate
Tous les pods existants sont tués avant que de nouveaux ne soient créés lorsque .spec.strategy.type==Recreate.
Déploiement de mise à jour continue
Le déploiement met à jour les pods dans une mise à jour continue quand .spec.strategy.type==RollingUpdate.
Vous pouvez spécifier maxUnavailable et maxSurge pour contrôler le processus de mise à jour continue.
Max non disponible
.spec.strategy.rollingUpdate.maxUnavailable est un champ facultatif qui spécifie le nombre maximal de pods qui peuvent être indisponibles pendant le processus de mise à jour.
La valeur peut être un nombre absolu (par exemple, 5) ou un pourcentage des pods souhaités (par exemple, 10%).
Le nombre absolu est calculé à partir du pourcentage en arrondissant vers le bas.
La valeur ne peut pas être 0 si .spec.strategy.rollingUpdate.maxSurge est 0.
La valeur par défaut est 25%.
Par exemple, lorsque cette valeur est définie sur 30%, l'ancien ReplicaSet peut être réduit à 70% des pods souhaités immédiatement au démarrage de la mise à jour continue.
Une fois que les nouveaux pods sont prêts, l'ancien ReplicaSet peut être réduit davantage, suivi d'une augmentation du nouveau ReplicaSet, garantissant que le nombre total de pods disponibles à tout moment pendant la mise à jour est d'au moins 70% des pods souhaités.
Max Surge
.spec.strategy.rollingUpdate.maxSurge est un champ facultatif qui spécifie le nombre maximal de pods pouvant être créés sur le nombre de pods souhaité.
La valeur peut être un nombre absolu (par exemple, 5) ou un pourcentage des pods souhaités (par exemple, 10%).
La valeur ne peut pas être 0 si MaxUnavailable est 0.
Le nombre absolu est calculé à partir du pourcentage en arrondissant.
La valeur par défaut est 25%.
Par exemple, lorsque cette valeur est définie sur 30%, le nouveau ReplicaSet peut être mis à l'échelle immédiatement au démarrage de la mise à jour continue, de sorte que le nombre total d'anciens et de nouveaux pods ne dépasse pas 130% des pods souhaités.
Une fois que les anciens pods ont été détruits, le nouveau ReplicaSet peut être augmenté davantage, garantissant que le nombre total de pods en cours d'exécution à tout moment pendant la mise à jour est au maximum de 130% des pods souhaités.
Progress Deadline Seconds
.spec.progressDeadlineSeconds est un champ facultatif qui spécifie le nombre de secondes pendant lesquelles vous souhaitez attendre que votre déploiement progresse avant que le système ne signale que le déploiement a échoué - refait surface comme une condition avec Type=Progressing, Status=False et Reason=ProgressDeadlineExceeded dans l'état de la ressource.
Le contrôleur de déploiement continuera de réessayer le déploiement.
À l'avenir, une fois la restauration automatique implémentée, le contrôleur de déploiement annulera un déploiement dès qu'il observera une telle condition.
S'il est spécifié, ce champ doit être supérieur à .spec.minReadySeconds.
Min Ready Seconds
.spec.minReadySeconds est un champ facultatif qui spécifie le nombre minimum de secondes pendant lequel un pod nouvellement créé doit être prêt sans qu'aucun de ses conteneurs ne plante, pour qu'il soit considéré comme disponible.
Cette valeur par défaut est 0 (le pod sera considéré comme disponible dès qu'il sera prêt).
Pour en savoir plus sur le moment où un pod est considéré comme prêt, consultez Sondes de conteneur.
Rollback To
Le champ .spec.rollbackTo est obsolète dans les versions d'API extensions/v1beta1 et apps/v1beta1 et n'est plus pris en charge dans les versions d'API commençant par apps/v1beta2.
Utilisez, kubectl rollout undo pour Revenir à une révision précédente.
Limite de l'historique des révisions
L'historique de révision d'un déploiement est stocké dans les ReplicaSets qu'il contrôle.
.spec.revisionHistoryLimit est un champ facultatif qui spécifie le nombre d'anciens ReplicaSets à conserver pour permettre la restauration.
Ces anciens ReplicaSets consomment des ressources dans etcd et encombrent la sortie de kubectl get rs.
La configuration de chaque révision de déploiement est stockée dans ses ReplicaSets; par conséquent, une fois un ancien ReplicaSet supprimé, vous perdez la possibilité de revenir à cette révision du déploiement.
Par défaut, 10 anciens ReplicaSets seront conservés, mais sa valeur idéale dépend de la fréquence et de la stabilité des nouveaux déploiements.
Plus précisément, la définition de ce champ à zéro signifie que tous les anciens ReplicaSets avec 0 réplicas seront nettoyés.
Dans ce cas, un nouveau panneau déroulant Déploiement ne peut pas être annulé, car son historique de révision est nettoyé.
Paused
.spec.paused est un champ booléen facultatif pour suspendre et reprendre un déploiement.
La seule différence entre un déploiement suspendu et un autre qui n'est pas suspendu, c'est que toute modification apportée au PodTemplateSpec du déploiement suspendu ne déclenchera pas de nouveaux déploiements tant qu'il sera suspendu.
Un déploiement n'est pas suspendu par défaut lors de sa création.
Alternative aux déploiements
kubectl rolling-update
kubectl rolling-update met à jour les pods et les ReplicationControllers de la même manière.
Mais les déploiements sont recommandés, car ils sont déclaratifs, côté serveur et ont des fonctionnalités supplémentaires, telles que la restauration de toute révision précédente même après la mise à jour progressive..
2.3 - StatefulSets
StatefulSet est l'objet de l'API de charge de travail utilisé pour gérer des applications avec état (stateful).
Gère le déploiement et la mise à l'échelle d'un ensemble de Pods, et fournit des garanties sur l'ordre et l'unicité de ces Pods.
Comme un Déploiement, un StatefulSet gère des Pods qui sont basés sur une même spécification de conteneur. Contrairement à un Deployment, un StatefulSet maintient une identité pour chacun de ces Pods. Ces Pods sont créés à partir de la même spec, mais ne sont pas interchangeables : chacun a un identifiant persistant qu'il garde à travers tous ses re-scheduling.
Si vous voulez utiliser des volumes de stockage pour fournir de la persistance à votre charge de travail, vous pouvez utiliser un StatefulSet comme partie de la solution. Même si des Pods individuels d'un StatefulSet sont susceptibles d'échouer, les identifiants persistants des Pods rendent plus facile de faire correspondre les volumes existants aux nouveaux Pods remplaçant ceux ayant échoué.
Utiliser des StatefulSets
Les StatefulSets sont utiles pour des applications qui nécessitent une ou plusieurs des choses suivantes :
Des identifiants réseau stables et uniques.
Un stockage persistant stable.
Un déploiement et une mise à l'échelle ordonnés et contrôlés.
Des mises à jour continues (rolling update) ordonnées et automatisées.
Ci-dessus, stable est synonyme de persistance suite au (re)scheduling de Pods.
Si une application ne nécessite aucun identifiant stable ou de déploiement, suppression ou
mise à l'échelle stables, vous devriez déployer votre application en utilisant un objet de charge de travail
fournissant un ensemble de réplicas sans état (stateless).
Un Deployment ou
ReplicaSet peut être mieux adapté pour vos applications sans état.
Limitations
Le stockage pour un Pod donné doit être provisionné soit par un approvisionneur de PersistentVolume basé sur un storage class donné, soit pré-provisionné par un admin.
Supprimer et/ou réduire l'échelle d'un StatefulSet à zéro ne supprimera pas les volumes associés avec le StatefulSet. Ceci est fait pour garantir la sécurité des données, ce qui a généralement plus de valeur qu'une purge automatique de toutes les ressources relatives à un StatefulSet.
Les StatefulSets nécessitent actuellement un Service Headless qui est responsable de l'identité réseau des Pods. Vous êtes responsable de la création de ce Service.
Les StatefulSets ne fournissent aucune garantie de la terminaison des pods lorsqu'un StatefulSet est supprimé. Pour avoir une terminaison ordonnée et maîtrisée des pods du StatefulSet, il est possible de réduire l'échelle du StatefulSet à 0 avant de le supprimer.
L'exemple ci-dessous décrit les composants d'un StatefulSet.
apiVersion:v1kind:Servicemetadata:name:nginxlabels:app:nginxspec:ports:- port:80name:webclusterIP:Noneselector:app:nginx---apiVersion:apps/v1kind:StatefulSetmetadata:name:webspec:selector:matchLabels:app:nginx# doit correspondre à .spec.template.metadata.labelsserviceName:"nginx"replicas:3# est 1 par défauttemplate:metadata:labels:app:nginx# doit correspondre à .spec.selector.matchLabelsspec:terminationGracePeriodSeconds:10containers:- name:nginximage:k8s.gcr.io/nginx-slim:0.8ports:- containerPort:80name:webvolumeMounts:- name:wwwmountPath:/usr/share/nginx/htmlvolumeClaimTemplates:- metadata:name:wwwspec:accessModes:["ReadWriteOnce"]storageClassName:"my-storage-class"resources:requests:storage:1Gi
Dans l'exemple ci-dessus :
Un Service Headless, appelé nginx, est utilisé pour contrôler le domaine réseau.
Le StatefulSet, appelé web, a une Spec indiquant que 3 réplicas du container nginx seront démarrés dans des Pods.
Le volumeClaimTemplates fournira un stockage stable utilisant des PersistentVolumes provisionnés par un approvisionneur de PersistentVolume.
Vous devez renseigner le champ .spec.selector d'un StatefulSet pour qu'il corresponde aux labels de son .spec.template.metadata.labels. Avant Kubernetes 1.8, le champ .spec.selector était mis par défaut s'il était omis. Pour les versions 1.8 et ultérieures, ne pas spécifier de sélecteur de Pod résulte en une erreur de validation lors de la création du StatefulSet.
Identité du Pod
Les Pods d'un StatefulSet ont une identité unique comprenant un ordinal, une identité réseau stable et un stockage stable.
L'identité est accrochée au Pod, indépendamment du noeud sur lequel il est (re)programmé.
Index Ordinal
Pour un StatefulSet avec N réplicas, chaque Pod du StatefulSet se verra assigné un ordinal entier, de 0 à N-1,
unique sur l'ensemble des pods.
ID réseau stable
Chaque Pod dans un StatefulSet dérive son nom d'hôte du nom du StatefulSet
et de l'ordinal du Pod. Le modèle pour le nom d'hôte généré est
$(nom statefulset)-$(ordinal). L'exemple ci-dessus créera trois Pods
nommés web-0,web-1,web-2.
Un StatefulSet peut utiliser un Service Headless
pour contrôler le domaine de ses Pods. Le domaine pris en charge par ce Service prend la forme :
$(nom service).$(namespace).svc.cluster.local, où "cluster.local" est le domaine du cluster.
Chaque fois qu'un Pod est créé, il obtient un sous-domaine DNS correspondant, prenant la forme :
$(nom pod).$(domaine du service gouvernant), où le service gouvernant est défini par le
champ serviceName du StatefulSet.
En fonction de la façon dont est configuré le DNS dans votre cluster, vous ne pourrez peut-être pas rechercher immédiatement
le nom DNS d'un pod nouvellement exécuté. Ce problème peut se produire lorsque d'autres clients dans le
cluster ont déjà envoyé des requêtes pour le nom d'hôte du Pod avant sa création.
La mise en cache négative (normale pour le DNS) signifie que les résultats des recherches précédentes ayant échoué sont
mémorisés et réutilisés, même après que le Pod ait démarré, pendant au moins quelques secondes.
Si vous avez besoin de découvrir les Pods rapidement après leur création, vous avez plusieurs options :
Interrogez directement l'API Kubernetes (par exemple, à l'aide d'un watch) plutôt que de vous fier aux recherches DNS.
Réduisez le temps de mise en cache dans votre fournisseur de DNS Kubernetes (cela signifie généralement modifier le ConfigMap de CoreDNS, qui met actuellement en cache pendant 30 secondes).
Comme mentionné dans la section limitations, vous êtes responsable de
créer le Service Headless
responsable de l'identité réseau des Pods.
Voici quelques exemples de choix pour le domaine du cluster, le nom du service,
le nom du StatefulSet et comment cela affecte les noms DNS des pods du StatefulSet.
Domaine Cluster
Service (ns/nom)
StatefulSet (ns/nom)
Domaine StatefulSet
DNS Pod
Nom d'hôte
cluster.local
default/nginx
default/web
nginx.default.svc.cluster.local
web-{0..N-1}.nginx.default.svc.cluster.local
web-{0..N-1}
cluster.local
foo/nginx
foo/web
nginx.foo.svc.cluster.local
web-{0..N-1}.nginx.foo.svc.cluster.local
web-{0..N-1}
kube.local
foo/nginx
foo/web
nginx.foo.svc.kube.local
web-{0..N-1}.nginx.foo.svc.kube.local
web-{0..N-1}
Note: Le domaine cluster sera cluster.local à moins qu'il soit
configuré autrement.
Stockage stable
Kubernetes crée un PersistentVolume pour chaque
VolumeClaimTemplate. Dans l'exemple nginx ci-dessus, chaque Pod se verra affecter un unique PersistentVolume
avec un StorageClass de my-storage-class et 1 Gib de stockage provisionné. Si aucun StorageClass
n'est spécifié, alors le StorageClass par défaut sera utilisé. Lorsqu'un Pod est (re)schedulé
sur un noeud, ses volumeMounts montent les PersistentVolumes associés aux
PersistentVolumeClaims. Notez que les PersistentVolumes associés avec les PersistentVolumeClaims des Pods
ne sont pas supprimés lorsque les Pods, ou le StatefulSet, sont supprimés.
Ceci doit être fait manuellement.
Étiquette du nom de Pod
Lorsque le StatefulSet Contrôleur crée un Pod,
il ajoute une étiquette, statefulset.kubernetes.io/pod-name, renseignée avec le nom du Pod.
Cette étiquette vous permet d'attacher un Service à un Pod spécifique du StatefulSet.
Garanties de déploiement et de mise à l'échelle
Pour un StatefulSet avec N réplicas, lorsque les Pods sont déployés, ils sont créés de manière séquentielle, dans l'ordre {0..N-1}.
Lorsque les Pods sont supprimés, ils sont terminés dans l'ordre inverse, {N-1..0}.
Avant qu'une opération de mise à l'échelle soit appliquée à un Pod, tous ses prédécesseurs doivent être Running et Ready.
Avant qu'un Pod soit terminé, tous ses successeurs doivent être complètement arrêtés.
Le StatefulSet ne devrait pas spécifier un pod.Spec.TerminationGracePeriodSeconds à 0. Cette pratique
est dangereuse et fortement déconseillée. Pour plus d'explications, veuillez vous référer à forcer la suppression de Pods de StatefulSet.
Lorsque l'exemple nginx ci-dessus est créé, trois Pods seront déployés dans l'ordre
web-0, web-1, web-2. web-1 ne sera pas déployé avant que web-0 soit
Running et Ready, et web-2 ne sera pas déployé avant que
web-1 soit Running et Ready. Si web-0 venait à échouer, après que web-1 soit Running et Ready, mais avant que
web-2 soit lancé, web-2 ne serait pas lancé avant que web-0 soit correctement relancé et redevienne Running et Ready.
Si un utilisateur venait à mettre à l'échelle l'exemple déployé en patchant le StatefulSet pour que
replicas=1, web-2 serait terminé en premier. web-1 ne serait pas terminé avant que web-2
ne soit complètement arrêté et supprimé. Si web-0 venait à échouer après que web-2 soit terminé et complètement arrêté,
mais avant que web-1 soit terminé, web-1 ne serait pas terminé avant que web-0 soit Running et Ready.
Politiques de gestion d'un Pod
Dans Kubernetes 1.7 et ultérieurs, le StatefulSet vous permet d'assouplir ses garanties d'ordre,
tout en préservant ses garanties d'unicité et d'identité via son champ .spec.podManagementPolicy.
Gestion de Pod OrderedReady
La gestion de Pod OrderedReady est la valeur par défaut pour les StatefulSets. Il implémente le comportement décrit ci-dessus.
Gestion de Pod Parallel
La gestion de Pod Parallel indique au contrôleur de StatefulSet de lancer ou
terminer tous les Pods en parallèle, et de ne pas attendre que les Pods deviennent Running
et Ready ou complètement terminés avant de lancer ou terminer un autre
Pod. Cette option affecte seulement le comportement pour les opérations de mise à l'échelle.
Les mises à jour ne sont pas affectées.
Stratégies de mise à jour
Dans Kubernetes 1.7 et ultérieurs, le champ .spec.updateStrategy d'un StatefulSet vous permet
de configurer et désactiver les rolling updates automatisés pour les conteneurs, étiquettes,
requête/limites de ressources, et annotations pour les Pods d'un StatefulSet.
On Delete
La stratégie de mise à jour OnDelete implémente l'ancien comportement (1.6 et précédents). Lorsque
.spec.updateStrategy.type d'un StatefulSet est mis à OnDelete, le contrôleur de StatefulSet
ne mettra pas à jour automatiquement les Pods dans un StatefulSet.
Les utilisateurs doivent supprimer manuellement les Pods pour forcer le contrôleur à créer de nouveaux
Pods qui réflètent les modifications faites à un .spec.template d'un StatefulSet.
Rolling Updates
La stratégie de mise à jour RollingUpdate implémente le rolling update automatisé pour les Pods d'un
StatefulSet. C'est la stratégie par défaut lorsque .spec.updateStrategy n'est pas spécifié.
Lorsqu'un .spec.updateStrategy.type d'un StatefulSet est mis à RollingUpdate, le contrôleur de
StatefulSet va supprimer et recréer chaque Pod d'un StatefulSet. Il va procéder dans le même ordre
que pour la terminaison d'un Pod (de l'ordinal le plus grand au plus petit), mettant à jour chaque Pod,
un seul à la fois. Il va attendre qu'un Pod mis à jour soit Running et Ready avant de mettre à jour
son prédécesseur.
Partitions
La stratégie de mise à jour RollingUpdate peut être partitionnée, en spécifiant une
.spec.updateStrategy.rollingUpdate.partition. Si une partition est spécifiée, tous les Pods ayant un
ordinal plus grand ou égal à la partition seront mis à jour lorsque le
.spec.template du StatefulSet sera mis à jour. Tous les Pods ayant un ordinal inférieur à la partition
ne sera pas mis à jour, et, même s'ils sont supprimés, ils seront recréés avec l'ancienne version. Si une
.spec.updateStrategy.rollingUpdate.partition d'un StatefulSet est plus grand que son .spec.replicas,
les mises à jour de son .spec.template ne seront pas propagés à ses Pods.
Dans la plupart des cas vous n'aurez pas à utiliser de partition, mais elles sont utiles si vous désirez
organiser une mise à jour, déployer une version canari, ou effectuer un déploiement par étapes.
Rollback forcé
En utilisant des Rolling Updates avec la
politique de gestion d'un Pod par défaut (OrderedReady),
il est possible de se retrouver dans un état inconsistant nécessitant une intervention manuelle pour réparation.
Si vous mettez à jour le template de Pod dans une configuration qui ne devient jamais Running et
Ready (par exemple, du fait d'un mauvais binaire ou d'une erreur de configuration au niveau de l'application),
le StatefulSet va arrêter le rollout et attendre.
Dans cet état, il n'est pas suffisant de revenir à une bonne configuration du template de Pod.
En raison d'une erreur connue,
le StatefulSet va continuer à attendre que le Pod en échec Pod devienne Ready
(ce qui n'arrive jamais) avant qu'il tente de revenir à la bonne configuration.
Après être revenu au bon template, vous devez aussi supprimer tous les Pods que le StatefulSet
avait déjà essayé de démarrer avec la mauvaise configuration.
Le StatefulSet va alors commencer à recréer les Pods en utilisant le bon template.