Il existe plusieurs options pour mettre à jour les ressources dans Kubernetes : apply, edit, patch et replace. Il y a confusion sur ce que chacun d'eux fait et quand les appliquer. Déchiffrons cela.

Si la phrase "kubernetes apply vs replace", on trouve , qui est incorrecte. "kubernetes apply vs patch", le premier lien est la documentation sur kubectl patch, qui ne comprend pas de comparaison appliquer et patch. Cet article examinera les différentes options ainsi que l'utilisation appropriée de chacune d'elles.
Au cours du cycle de vie d'une ressource Kubernetes (service, deployment, ingress, etc.), il est parfois nécessaire de modifier, d'ajouter ou de supprimer certaines propriétés de cette ressource. Par exemple, ajouter une note, augmenter ou diminuer le nombre de réplicas.
Kubernetes CLI
Si vous travaillez déjà avec des clusters Kubernetes via la CLI, vous êtes déjà familier avec appliquer et edit. La commande appliquer lit la spécification de la ressource depuis un fichier et fait un "upsert" dans le cluster Kubernetes, c'est-à-dire crée la ressource si elle n'existe pas et la met à jour si elle existe. La commande edit lit la ressource via l'API, puis écrit la spécification de la ressource dans un fichier local qui est ensuite ouvert dans un éditeur de texte. Une fois que vous avez édité et enregistré le fichier, kubectl enverra les modifications effectuées via l'API, qui appliquera soigneusement ces modifications à la ressource.
Tout le monde ne connaît pas les commandes patch et remplacer. La commande patch permettent de modifier une partie de la spécification de la ressource en fournissant uniquement la partie modifiée dans la ligne de commande. La commande remplacer fonctionne de la même manière que edit, mais il faut tout faire manuellement : il faut télécharger la version actuelle de la spécification de la ressource, par exemple en utilisant kubectl get -o yaml, l'éditer, puis utiliser remplacer pour mettre à jour la ressource selon la spécification modifiée. La commande remplacer ne fonctionnera pas si des changements ont eu lieu entre la lecture et le remplacement de la ressource.
Kubernetes API
Vous êtes probablement familier avec les méthodes CoreV1().Pods().Update(), replaceNamespacedService ou patch_namespaced_deployment, si vous travaillez avec des clusters via en utilisant un certain langage de programmation. La bibliothèque gère ces méthodes avec des requêtes HTTP, en utilisant les méthodes PUT et PATCH. Par ailleurs update et remplacer utilisé PUT, et patch, aussi banal que cela puisse paraître, utilise PATCH.
Il convient de noter que kubectl fonctionne également avec des clusters via l'API. En d'autres termes, kubectl– c'est un wrapper au-dessus de la bibliothèque cliente pour le langage Go, permettant en grande partie de fournir des sous-commandes dans un format plus compact et lisible, en complément des capacités standard de l'API. Par exemple, comme vous l'avez déjà remarqué, la méthode appliquer n'a pas été mentionnée dans le paragraphe précédent. Actuellement (mai 2020, note du traducteur) toute la logique kubectl apply, c'est-à-dire la création de ressources inexistantes et la mise à jour de ressources existantes, fonctionne entièrement côté code kubectl. Des efforts sont en cours appliquer vers le côté API, mais cela est encore en phase de test bêta. Je détaillerai ci-dessous.
Le patch par défaut
Il est préférable de l'appliquer patch, si vous souhaitez mettre à jour une ressource. C'est ainsi que fonctionnent à la fois les bibliothèques clientes au-dessus de l'API Kubernetes et kubectl (pas étonnant, car c'est un wrapper de bibliothèque cliente, note du traducteur).
Travailler de manière stratégique
Toutes les commandes kubectl appliquer, edit et patch utilisent la méthode PATCH dans les requêtes HTTP pour mettre à jour une ressource existante. Si l'on examine plus en détail la mise en œuvre des commandes, on constate que toutes utilisent l'approche pour mettre à jour les ressources, bien que la commande patch puisse également utiliser d'autres approches (plus de détails ci-dessous). L'approche du patching stratégique-merge essaie de "faire les choses correctement" en fusionnant la spécification fournie avec la spécification existante. Plus précisément, elle essaie de fusionner à la fois les objets et les tableaux, ce qui signifie que les modifications sont généralement additive. Par exemple, exécuter la commande patch avec une nouvelle variable d'environnement dans la spécification du conteneur pod entraîne l'ajout de cette variable d'environnement aux variables d'environnement existantes, plutôt que de les écraser. Pour supprimer avec cette approche, il faut impérativement définir la valeur du paramètre à null dans la spécification fournie. Quelles sont donc les commandes kubectl pour la mise à jour qu'il vaut mieux utiliser?
Si vous créez et gérez vos ressources à l'aide de kubectl apply, il est toujours préférable d'utiliser lors de la mise à jour kubectl apply, afin que kubectl puisse gérer la configuration et suivre correctement les modifications demandées d'une application à l'autre. L'avantage d'utiliser toujours appliquer est qu'il suit la spécification précédemment appliquée, lui permettant de savoir quand les propriétés de la spécification et les éléments de tableau sont explicitement supprimés. Cela permet d'utiliser appliquer pour supprimer les propriétés et les éléments d'un tableau, alors que la fusion stratégique ordinaire ne fonctionnera pas. Commandes edit et patch ne mettent pas à jour les notes qui kubectl apply sont appliquées pour suivre leurs changements, donc tous les changements qui sont suivis et effectués via l'API Kubernetes, mais réalisés par des commandes edit et patch, sont invisibles pour les commandes suivantes appliquer, c'est-à-dire appliquer ne les supprime pas, même s'ils n'apparaissent pas dans la spécification d'entrée pour appliquer (La documentation indique que edit et patch faites des mises à jour des notes utilisées appliquer, mais en pratique – non).
Si vous n'utilisez pas la commande appliquer, vous pouvez utiliser comme edit, et via patch, en choisissant la commande qui convient le mieux à la modification apportée. Lors de l'ajout et de la modification des propriétés de la spécification, les deux approches sont à peu près similaires. Lors de la suppression de propriétés de la spécification ou d'éléments de tableau edit se comporte comme un lancement unique appliquer, y compris le suivi de ce qu'était la spécification avant et après son édition, donc on peut explicitement supprimer des propriétés et des éléments de tableau de la ressource. Il faut explicitement définir la valeur d'une propriété sur null dans la spécification pour patch, afin de la supprimer de la ressource. La suppression d'un élément de tableau à l'aide de patching stratégique-merge est plus complexe, car elle nécessite l'utilisation de directives de fusion. Voir d'autres approches de mise à jour ci-dessous pour choisir des alternatives plus acceptables.
Pour implémenter dans la bibliothèque cliente des méthodes de mise à jour se comportant comme les commandes mentionnées ci-dessus kubectl, il faut spécifier dans les requêtes content-type dans application/strategic-merge-patch+json. Si vous souhaitez supprimer des propriétés dans la spécification, vous devez explicitement définir leurs valeurs sur null, de manière similaire à kubectl patch. Si vous devez supprimer des éléments de tableau, vous devriez inclure des directives de fusion dans la spécification de mise à jour ou utiliser une autre approche pour les mises à jour.
Autres approches pour les mises à jour
Kubernetes prend en charge deux autres approches pour les mises à jour : et . L'approche JSON merge patch prend une spécification Kubernetes partielle comme entrée et prend en charge la fusion des objets de manière similaire à l'approche du patching strategic-merge. La différence entre les deux est qu'elle prend uniquement en charge le remplacement des tableaux, y compris le tableau des conteneurs dans la spécification du pod. Cela signifie qu'en utilisant JSON merge patch, vous devez fournir des spécifications complètes pour tous les conteneurs si une propriété de l'un d'eux change. Ainsi, cette approche est utile pour supprimer des éléments d'un tableau dans la spécification. Dans la ligne de commande, vous pouvez choisir JSON merge patch en utilisant kubectl patch --type=merge. Lors de l'utilisation de l'API Kubernetes, il convient d'utiliser la méthode de requête PATCH et définir content-type dans application/merge-patch+json.
L'approche JSON patch, au lieu de fournir une spécification partielle de la ressource, utilise la fourniture de modifications que vous souhaitez apporter à la ressource sous forme de tableau, où chaque élément du tableau représente une description de la modification à apporter à la ressource. Cette approche est plus flexible et puissante pour exprimer les modifications apportées, mais au prix du fait que la liste des modifications est au format distinct de Kubernetes, au lieu d'envoyer une spécification partielle de la ressource. Dans kubectl vous pouvez choisir JSON patch en utilisant kubectl patch --type=json. Lors de l'utilisation de l'API Kubernetes, cette approche fonctionne en utilisant la méthode de requête PATCH et définir content-type dans application/json-patch+json.
Avoir confiance — utiliser replace
Dans certains cas, il est nécessaire d'avoir la certitude qu'aucune modification ne sera apportée à la ressource entre la lecture de la ressource et sa mise à jour. Autrement dit, il est prudent de s'assurer que tous les changements seront atomiques. Dans ce cas, pour mettre à jour les ressources, il convient d'utiliser remplacer. Par exemple, s'il existe un ConfigMap avec un compteur mis à jour par plusieurs sources, il est important de s'assurer que deux sources ne mettent pas à jour le compteur en même temps, ce qui entraînerait une perte de mise à jour. Pour illustrer, imaginez une séquence d'événements en utilisant l'approche patch:
- A et B obtiennent l'état actuel de la ressource à partir de l'API
- Chacun met à jour localement la spécification, en augmentant le compteur de un, tout en ajoutant "A" ou "B" respectivement dans la note "updated-by"
- A met à jour la ressource un peu plus rapidement
- B met à jour la ressource
L'update A a été perdu. Dernière opération patch gagne, le compteur augmente de un au lieu de deux, et la note "updated-by" se termine par "B" et ne contient pas "A". Comparons ce qui précède avec ce qui se passe lorsque des mises à jour sont effectuées en utilisant l'approche remplacer:
- A et B obtiennent l'état actuel de la ressource à partir de l'API
- Chacun met à jour localement la spécification, en augmentant le compteur de un, tout en ajoutant "A" ou "B" respectivement dans la note "updated-by"
- A met à jour la ressource un peu plus rapidement
- B tente de mettre à jour la ressource, mais la mise à jour est rejetée par l'API car la version de la ressource dans la spécification
remplacerne correspond pas à la version actuelle de la ressource dans Kubernetes, car la version a été augmentée lors de l'opération de remplacement de la part de A.
Dans le cas ci-dessus, B devra récupérer à nouveau la ressource, apporter les modifications dans le nouvel état et tenter à nouveau de faire remplacer. En conséquence, le compteur sera augmenté de deux, et la note "updated-by" contiendra "AB" à la fin.
L'exemple ci-dessus implique que lors de l'exécution de remplacer une substitution complète de toute la ressource est effectuée. La spécification utilisée pour remplacer, doit être complète, et non partielle comme dans appliquer, mais complète, y compris l'ajout de resourceVersion dans les métadonnées de la spécification. Si vous n'avez pas inclus resourceVersion ou si la version fournie par vous n'est pas la version actuelle, le remplacement sera rejeté. Par conséquent, la meilleure approche à utiliser remplacer est de lire la ressource, de la mettre à jour et de la remplacer immédiatement. En utilisant kubectl, cela pourrait ressembler à :
$ kubectl get deployment my-deployment -o json
| jq '.spec.template.spec.containers[0].env[1].value = "new value"'
| kubectl replace -f -Il est à noter que les deux commandes suivantes, exécutées consécutivement, s'exécuteront avec succès, car deployment.yaml ne contient pas la propriété .metadata.resourceVersion
$ kubectl create -f deployment.yaml
$ kubectl replace -f deployment.yamlCela semblerait contredire ce qui a été dit ci-dessus, c'est-à-dire "ajout de resourceVersion dans les métadonnées de la spécification". Est-il faux d'affirmer cela ? Non, ce n'est pas le cas, car si kubectl il remarque que vous n'avez pas spécifié resourceVersion, il la lira à partir de la ressource et l'ajoutera à la spécification que vous avez fournie, puis effectuera remplacer. Étant donné que cela est potentiellement dangereux, si l'on compte sur l'atome, cette magie fonctionne entièrement du côté kubectl, ne comptez pas sur elle lorsque vous utilisez des bibliothèques clientes travaillant avec l'API. Dans ce cas, vous devrez lire la spécification actuelle de la ressource, la mettre à jour, puis effectuer PUT la requête.
Impossible de faire un patch - faisons un replace
Parfois, il est nécessaire d'apporter certaines modifications qui ne peuvent pas être traitées par l'API. Dans ces cas, il est possible de forcer le remplacement d'une ressource en la supprimant et en la recréant. Cela se fait à l'aide de kubectl replace --force. L'exécution de la commande supprime immédiatement les ressources, puis les recrée avec la spécification fournie. L'API ne dispose pas de gestionnaire pour "forcer le remplacement", et pour le faire via l'API, il faut effectuer deux opérations. Tout d'abord, il faut supprimer la ressource en définissant gracePeriodSeconds à zéro (0) et propagationPolicy à "Background", puis recréer cette ressource avec la spécification souhaitée.
Attention : cette approche est potentiellement dangereuse, elle peut conduire à un état indéterminé.
Apply côté serveur
Comme mentionné précédemment, les développeurs de Kubernetes travaillent à la mise en œuvre de la logique appliquer de kubectl dans l'API Kubernetes. La logique appliquer est disponible dans Kubernetes 1.18 via kubectl apply --server-side ou par l'intermédiaire de l'API en utilisant la méthode PATCH avec content-type application/apply-patch+YAML.
Remarque : JSON est également un YAML valide, donc on peut envoyer la spécification sous forme de JSON, même si
content-typeun mot de passe/PIN/biométrie/clé matérielle du compte OS sera requis (à condition qu'un mot de passe principal ne soit pas défini). L'implémentation de cette fonctionnalité sous Linux est perturbée parapplication/apply-patch+yaml.
En outre, la logique kubectl devient accessible à tous via l'API, appliquer côté serveur suit les responsables des champs dans la spécification, permettant ainsi un accès multiple sûr pour son édition sans conflit. En d'autres termes, si appliquer côté serveur obtient une portée plus large, une interface de gestion des ressources sécurisée et universelle apparaîtra pour différents clients, tels que kubectl, Pulumi ou Terraform, GitOps, ainsi que des scripts personnalisés utilisant des bibliothèques clientes.
Résultats
J'espère que cet aperçu des différentes manières de mettre à jour les ressources dans les clusters a été utile pour vous. Il est bon de savoir que les opposants ne se contentent pas d'appliquer contre remplacer, car il est possible de mettre à jour une ressource en utilisant apply, edit, patch ou replace. En effet, chaque approche a son domaine d'application. Pour des modifications atomiques, le remplacement est préférable, sinon il vaut mieux utiliser le patch strategic-merge via apply. En dernier recours, je compte sur le fait que vous avez compris qu'il ne faut pas faire confiance à Google ou à StackOverflow pour rechercher "kubernetes apply vs replace". Du moins jusqu'à ce que cet article ne remplace la réponse actuelle.

Source : habr.com
