This the multi-page printable view of this section. Click here to print.
Workloads
- 1: Pods
- 1.1: Aperçu du Pod
- 1.2: Pods
- 1.3: Cycle de vie d'un Pod
- 1.4: Contraintes de propagation de topologie pour les Pods
- 1.5: Init Containers
- 2: Contrôleurs
- 2.1: ReplicaSet
- 2.2: Déploiements
1 - Pods
1.1 - Aperçu du Pod
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 :
Templates de Pod
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/v1
kind: Job
metadata:
name: hello
spec:
template:
# Ceci est un template de pod
spec:
containers:
- name: hello
image: busybox
command: ['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.
A suivre
- En savoir plus sur les Pods
- The Distributed System Toolkit: Patterns for Composite Containers explique les dispositions courantes pour des Pods avec plusieurs conteneurs
- En savoir plus sur le comportement des Pods :
1.2 - Pods
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.
Pour une explication plus détaillée, voir The Distributed System ToolKit: Patterns for Composite Containers.
Alternatives envisagées
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 modifierterminationGracePeriodSeconds
si le hookpreStop
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.
- Si un des conteneurs du Pod a défini un preStop hook, il est exécuté à l'intérieur du conteneur. Si le
- (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 0
force 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 estSuccess
.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 estFailure
. Si le Conteneur ne fournit pas de readiness probe, l'état par défaut estSuccess
.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 estSuccess
.
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 ?
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 ?
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 plus d'informations sur la manière de mettre en place une liveness, readiness ou startup probe, voir Configurer des Liveness, Readiness et Startup Probes.
Statut d'un Pod et d'un Conteneur
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: Waiting Reason: ErrImagePull ...
Running
: Indique que le conteneur s'exécute sans problème. Le hookpostStart
(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: Running Started: 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 hookpreStop
est exécuté (s'il existe).... State: Terminated Reason: Completed Exit Code: 0 Started: Wed, 30 Jan 2019 11:45:26 +0530 Finished: Wed, 30 Jan 2019 11:45:26 +0530 ...
Pod readiness
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ée
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
- type: "www.example.com/feature-1" # une PodCondition supplémentaire
status: "False"
lastProbeTime: null
lastTransitionTime: 2018-01-01T00:00:00Z
containerStatuses:
- 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
sontTrue
.
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 Déploiement, ReplicaSet ou StatefulSet pour les Pods qui ne sont pas censés terminer, par exemple des serveurs web.
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: v1
kind: Pod
metadata:
labels:
test: liveness
name: liveness-http
spec:
containers:
- args:
- /server
image: k8s.gcr.io/liveness
livenessProbe:
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: HTTPS
path: /healthz
port: 8080
httpHeaders:
- name: X-Custom-Header
value: Awesome
initialDelaySeconds: 15
timeoutSeconds: 1
name: 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.
- Always : Redémarrage du Conteneur ; la
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.
- Always : Redémarrage du Conteneur ; la
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.
- Always : Redémarrage du Conteneur ; la
- 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.
- Always : Redémarrage du Conteneur ; la
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.
- Always : Redémarrage du Conteneur ; la
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.
A suivre
Apprenez par la pratique attacher des handlers à des événements de cycle de vie d'un conteneur.
Apprenez par la pratique configurer des liveness, readiness et startup probes.
En apprendre plus sur les hooks de cycle de vie d'un Conteneur.
1.4 - Contraintes de propagation de topologie pour les Pods
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.
Conditions préalables
Autoriser la Feature Gate
La feature gate EvenPodsSpread
doit être autorisée pour
l'API Server et le
scheduler.
Labels de noeuds
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
Une vue logique du cluster est celle-ci :
+---------------+---------------+
| zoneA | zoneB |
+-------+-------+-------+-------+
| node1 | node2 | node3 | node4 |
+-------+-------+-------+-------+
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 :
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
topologySpreadConstraints:
- maxSkew: <integer>
topologyKey: <string>
whenUnsatisfiable: <string>
labelSelector: <object>
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 :
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
containers:
- name: pause
image: k8s.gcr.io/pause:3.1
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, simaxSkew
reste à "1", le Pod entrant peut être uniquement placé dans "node4". - Changez
whenUnsatisfiable: DoNotSchedule
enwhenUnsatisfiable: 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 :
kind: Pod
apiVersion: v1
metadata:
name: mypod
labels:
foo: bar
spec:
topologySpreadConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
- maxSkew: 1
topologyKey: node
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
foo: bar
containers:
- name: pause
image: k8s.gcr.io/pause:3.1
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".
- les Pods localisés sur ces noeuds n'impactent pas le calcul de
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 quetopologySpreadConstraints[*].labelSelector
du workload corresponde à ses propres labels.Si le Pod entrant a défini
spec.nodeSelector
ouspec.affinity.nodeAffinity
, les noeuds non correspondants seront ignorés.Supposons que vous ayez un cluster de 5 noeuds allant de zoneA à zoneC :
+---------------+---------------+-------+ | zoneA | zoneB | zoneC | +-------+-------+-------+-------+-------+ | node1 | node2 | node3 | node4 | node5 | +-------+-------+-------+-------+-------+ | P | P | P | | | +-------+-------+-------+-------+-------+
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.kind: Pod apiVersion: v1 metadata: name: mypod labels: foo: bar spec: topologySpreadConstraints: - maxSkew: 1 topologyKey: zone whenUnsatisfiable: DoNotSchedule labelSelector: matchLabels: foo: bar affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: zone operator: NotIn values: - zoneC containers: - name: pause image: k8s.gcr.io/pause:3.1
Contraintes par défaut au niveau du cluster
Kubernetes v1.18 [alpha]
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 à :
apiVersion: kubescheduler.config.k8s.io/v1alpha2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: ScheduleAnyway
Note: Le score produit par les contraintes de scheduling par défaut peuvent rentrer en conflit avec le score produit par le pluginDefaultPodTopologySpread
. Il est recommandé de désactiver ce plugin dans le profil de scheduling lorsque vous utilisez des contraintes par défaut pourPodTopologySpread
.
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 commesed
,awk
,python
, oudig
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; then exit 0; fi; done; exit 1
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 :
sleep 60
Cloner un dépôt Git dans un Volume
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: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo "L''app s''exécute!" && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['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-mydb
image: busybox:1.28
command: ['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
:
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
Vous pouvez démarrer ce Pod en exécutant :
kubectl apply -f myapp.yaml
pod/myapp-pod created
Et vérifier son statut avec :
kubectl get -f myapp.yaml
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:0/2 0 6m
ou pour plus de détails :
kubectl describe -f myapp.yaml
Name: myapp-pod
Namespace: default
[...]
Labels: app=myapp
Status: Pending
[...]
Init Containers:
init-myservice:
[...]
State: Running
[...]
init-mydb:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Containers:
myapp-container:
[...]
State: Waiting
Reason: PodInitializing
Ready: False
[...]
Events:
FirstSeen LastSeen Count From SubObjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
16s 16s 1 {default-scheduler } Normal Scheduled Successfully assigned myapp-pod to 172.17.4.201
16s 16s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulling pulling image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Pulled Successfully pulled image "busybox"
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Created Created container with docker id 5ced34a04634; Security:[seccomp=unconfined]
13s 13s 1 {kubelet 172.17.4.201} spec.initContainers{init-myservice} Normal Started Started container with docker id 5ced34a04634
Pour voir les logs des init containers dans ce Pod, exécuter :
kubectl logs myapp-pod -c init-myservice # Inspecter le premier init container
kubectl logs myapp-pod -c init-mydb # Inspecter le second init container
À ce stade, ces init containers attendent de découvrir les services nommés
mydb
et myservice
.
Voici une configuration que vous pouvez utiliser pour faire apparaître ces Services :
---
apiVersion: v1
kind: Service
metadata:
name: myservice
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9376
---
apiVersion: v1
kind: Service
metadata:
name: mydb
spec:
ports:
- protocol: TCP
port: 80
targetPort: 9377
Pour créer les services mydb
et myservice
:
kubectl apply -f services.yaml
service/myservice created
service/mydb created
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).
A suivre
- Lire à propos de la création d'un Pod ayant un init container
- Apprendre à debugger les init containers
2 - Contrôleurs
2.1 - ReplicaSet
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.
Exemple
apiVersion: apps/v1
kind: ReplicaSet
metadata:
name: frontend
labels:
app: guestbook
tier: frontend
spec:
# modify replicas according to your case
replicas: 3
selector:
matchLabels:
tier: frontend
template:
metadata:
labels:
tier: frontend
spec:
containers:
- name: php-redis
image: 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.
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
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 3 3 3 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:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: 2019-01-31T17:20:41Z
generateName: frontend-
labels:
tier: frontend
name: frontend-9si5l
namespace: default
ownerReferences:
- apiVersion: extensions/v1beta1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: frontend
uid: 892a2330-257c-11e9-aecd-025000000001
...
Acquisitions de Pod en dehors du template
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 :
apiVersion: v1
kind: Pod
metadata:
name: pod1
labels:
tier: frontend
spec:
containers:
- name: hello1
image: gcr.io/google-samples/hello-app:2.0
---
apiVersion: v1
kind: Pod
metadata:
name: pod2
labels:
tier: frontend
spec:
containers:
- name: hello2
image: gcr.io/google-samples/hello-app:1.0
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 :
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
Les nouveaux pods seront acquis par le ReplicaSet, puis immédiatement terminés car le ReplicaSet dépasserait alors le compte désiré.
En récupérant les pods :
kubectl get Pods
La sortie montre que les nouveaux pods sont soit déjà terminés, soit en voie de l'être :
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
pod2 0/1 Terminating 0 4s
Cependant, si vous créez d'abord les pods :
kubectl apply -f https://kubernetes.io/examples/pods/pod-rs.yaml
Et puis créez le ReplicaSet :
kubectl apply -f https://kubernetes.io/examples/controllers/frontend.yaml
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.
Un ReplicaSet a également besoin de .spec
section.
Pod Template
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 :
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Foreground"}' \
> -H "Content-Type: application/json"
Supprimer juste un ReplicaSet
Vous pouvez supprimer un ReplicaSet sans affecter ses pods à l’aide de kubectl delete
avec l'option --cascade=false
.
Lorsque vous utilisez l'API REST ou la bibliothèque client-go
, vous devez définir propagationPolicy
sur Orphan
.
Par exemple :
kubectl proxy --port=8080
curl -X DELETE 'localhost:8080/apis/extensions/v1beta1/namespaces/default/replicasets/frontend' \
> -d '{"kind":"DeleteOptions","apiVersion":"v1","propagationPolicy":"Orphan"}' \
> -H "Content-Type: application/json"
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.
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: frontend-scaler
spec:
scaleTargetRef:
kind: ReplicaSet
name: frontend
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 50
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.
kubectl apply -f https://k8s.io/examples/controllers/hpa-rs.yaml
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:
- Créer un déploiement pour déployer un ReplicaSet. Le ReplicaSet crée des pods en arrière-plan. Vérifiez l'état du déploiement pour voir s'il réussit ou non.
- 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.
- Revenir à une révision de déploiement antérieure si l'état actuel du déploiement n'est pas stable. Chaque restauration met à jour la révision du déploiement.
- Augmentez le déploiement pour traiter plus de charge.
- Suspendre le déploiement d'appliquer plusieurs correctifs à son PodTemplateSpec, puis de le reprendre pour démarrer un nouveau déploiement.
- Utiliser l'état du déploiement comme indicateur qu'un déploiement est bloqué.
- Nettoyer les anciens ReplicaSets dont vous n'avez plus besoin.
Création d'un déploiement
Voici un exemple de déploiement.
Il crée un ReplicaSet pour faire apparaître trois pods nginx
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
Dans cet exemple:
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 champmatchLabels
est une table de hash {clé, valeur}. Une seule {clé, valeur} dans la tablematchLabels
est équivalente à un élément dematchExpressions
, dont le champ clé est "clé", l'opérateur est "In" et le tableau de valeurs contient uniquement "valeur". Toutes les exigences, à la fois dematchLabels
et dematchExpressions
, doivent être satisfaites pour correspondre.Le champ
template
contient les sous-champs suivants:- Les Pods reçoivent le label
app:nginx
dans le champlabels
. - La spécification du template de pod dans le champ
.template.spec
, indique que les pods exécutent un conteneur,nginx
, qui utilise l'imagenginx
Docker Hub à la version 1.7.9. - Créez un conteneur et nommez-le
nginx
en utilisant le champname
.
- Les Pods reçoivent le label
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 ressourcekubernetes.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.kubectl apply -f https://k8s.io/examples/controllers/nginx-deployment.yaml
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 0 0 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écutezkubectl 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'imagenginx: 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
denginx: 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'APIapps/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 denginx: 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
etnginx-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
La sortie est similaire à ceci:
deployments "nginx-deployment" REVISION CHANGE-CAUSE 1 kubectl apply --filename=https://k8s.io/examples/controllers/nginx-deployment.yaml --record=true 2 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true 3 kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.91 --record=true
CHANGE-CAUSE
est copié de l'annotation de déploiementkubernetes.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 commandekubectl
qui apporte des modifications à la ressource. - Modification manuelle du manifeste de la ressource.
- Annoter le déploiement avec
Pour voir les détails de chaque révision, exécutez:
kubectl rollout history deployment.v1.apps/nginx-deployment --revision=2
La sortie est similaire à ceci:
deployments "nginx-deployment" revision 2 Labels: app=nginx pod-template-hash=1159050644 Annotations: kubernetes.io/change-cause=kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1 --record=true Containers: nginx: Image: nginx:1.9.1 Port: 80/TCP QoS Tier: cpu: BestEffort memory: BestEffort Environment Variables: <none> No volumes.
Revenir à une révision précédente
Suivez les étapes ci-dessous pour restaurer le déploiement de la version actuelle à la version précédente, qui est la version 2.
Vous avez maintenant décidé d'annuler le déploiement actuel et le retour à la révision précédente:
kubectl rollout undo deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
deployment.apps/nginx-deployment
Alternativement, vous pouvez revenir à une révision spécifique en la spécifiant avec
--to-revision
:kubectl rollout undo deployment.v1.apps/nginx-deployment --to-revision=2
La sortie est similaire à ceci:
deployment.apps/nginx-deployment
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:
kubectl scale deployment.v1.apps/nginx-deployment --replicas=10
La sortie est similaire à ceci:
deployment.apps/nginx-deployment scaled
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.
kubectl autoscale deployment.v1.apps/nginx-deployment --min=10 --max=15 --cpu-percent=80
La sortie est similaire à ceci:
deployment.apps/nginx-deployment scaled
Mise à l'échelle proportionnelle
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'exigencemaxUnavailable
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:
kubectl rollout pause deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
deployment.apps/nginx-deployment paused
Mettez ensuite à jour l'image du déploiement:
kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1
La sortie est similaire à ceci:
deployment.apps/nginx-deployment image updated
Notez qu'aucun nouveau déploiement n'a commencé:
kubectl rollout history deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
deployments "nginx" REVISION CHANGE-CAUSE 1 <none>
Obtenez l'état de déploiement pour vous assurer que le déploiement est correctement mis à jour:
kubectl get rs
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE nginx-2142116321 3 3 3 2m
Vous pouvez effectuer autant de mises à jour que vous le souhaitez, par exemple, mettre à jour les ressources qui seront utilisées:
kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
La sortie est similaire à ceci:
deployment.apps/nginx-deployment resource requirements updated
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:
kubectl rollout resume deployment.v1.apps/nginx-deployment
La sortie est similaire à ceci:
deployment.apps/nginx-deployment resumed
Regardez l'état du déploiement jusqu'à ce qu'il soit terminé.
kubectl get rs -w
La sortie est similaire à ceci:
NAME DESIRED CURRENT READY AGE nginx-2142116321 2 2 2 2m nginx-3926361531 2 2 0 6s nginx-3926361531 2 2 1 18s nginx-2142116321 1 2 2 2m nginx-2142116321 1 2 2 2m nginx-3926361531 3 2 1 18s nginx-3926361531 3 2 1 18s nginx-2142116321 1 1 1 2m nginx-3926361531 3 3 1 18s nginx-3926361531 3 3 2 19s nginx-2142116321 0 1 1 2m nginx-2142116321 0 1 1 2m nginx-2142116321 0 0 0 2m nginx-3926361531 3 3 3 20s
Obtenez le statut du dernier déploiement:
kubectl get rs
La sortie est similaire à ceci:
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:
kubectl patch deployment.v1.apps/nginx-deployment -p '{"spec":{"progressDeadlineSeconds":600}}'
La sortie est similaire à ceci:
deployment.apps/nginx-deployment patched
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:
- Type=Progressing
- Status=False
- Reason=ProgressDeadlineExceeded
Voir les conventions Kubernetes API pour plus d'informations sur les conditions d'état.
Note: Kubernetes ne prend aucune mesure sur un déploiement bloqué, sauf pour signaler une condition d'état avecReason=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: 2
conditions:
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: Replica set "nginx-deployment-4262182780" is progressing.
reason: ReplicaSetUpdated
status: "True"
type: Progressing
- lastTransitionTime: 2016-10-04T12:25:42Z
lastUpdateTime: 2016-10-04T12:25:42Z
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: 2016-10-04T12:25:39Z
lastUpdateTime: 2016-10-04T12:25:39Z
message: 'Error creating: pods "nginx-deployment-4262182780-" is forbidden: exceeded quota:
object-counts, requested: pods=1, used: pods=3, limited: pods=2'
reason: FailedCreate
status: "True"
type: ReplicaFailure
observedGeneration: 3
replicas: 2
unavailableReplicas: 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).
Seulement un .spec.template.spec.restartPolicy
égal à Always
est autorisé, ce qui est la valeur par défaut s'il n'est pas spécifié.
Répliques
.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..