Blog | WeScale

Kubernetes 1.28 Planternetes : fonctionnalités et améliorations

Rédigé par Jérôme Masson | 08/09/2023

La version 1.28 de Kubernetes est sortie le 15 Août, et à chaque nouvelle release de Kubernetes amène son lot de changements et de nouveautés. Voici une liste non exhaustive de fonctionnalités/améliorations qui méritent votre attention si ce n’est pour les fonctionnalités passées en stable, mais aussi garder un œil sur celles qui le seront dans les prochaines versions.

Introduction

L’introduction de fonctionnalités ou leur changement de statut est toujours un mélange entre excitation et challenge. Chacun essaye de voir quel sera l’impact sur son quotidien. L’ops regarderait donc celles qui impacteront l’administration de la plateforme, les changements d’API et les éléments se rapportant à la sécurité ou uniformisation des applications de la plateforme. Quant au Dev, il se concentrerait aux enrichissements améliorant sa capacité de livraison et la stabilité de ses applications.

 La version 1.28 vient avec pas moins de 45 améliorations : 19 en Alpha, 14 sont promues en beta, et 12 passent à Stable.

Nouveautés en Alpha

Les nouveautés offrent toujours un aperçu des futures releases et de la direction que prend votre plateforme et surtout devraient vous permettre d’accueillir et de tester ces nouvelles fonctionnalités en avance.  

Sidecar containers: API awareness of sidecar containers

Arrivée avec la version 1.28, cette fonctionnalité devra être activée via la feature gate SidecarContainers --feature-gates=SidecarContainers=true,...

Elle permet de configurer une politique de redémarrage sur un init-container qui est indépendante des autres init-containers et du pod lui-même. Ce faisant, avec la restartPolicy: Always votre init-containers ne s’arrêtera pas en cherchant un état Complete comme le font les init-containers à l’accoutumée, votre init-container deviendra donc un sidecar container de votre pod qui pourra bénéficier de ses propres sondes, mais celui-ci ne pourra dépasser le cycle de vie du pod (voir l’exemple de Job).

Cependant cette fonctionnalité, en Alpha avec la version 1.28, comporte encore quelques bugs connus qui peuvent augmenter le temps d’analyse en cas d’incident. Par exemple, la gestion des ressources n’est pour le moment pas 100% valide, le cycle de vie est quant à lui réinitialisé à chaque redémarrage de pod.

Je vous conseille de l’utiliser pour un POC, mais pas de manière pérenne pour le moment.

Exemple de Job dont le sidecar récupère les logs générées depuis le conteneur applicatif: 

apiVersion: batch/v1
kind: Job
metadata:
name: myjob
spec:
 template:
   spec:
     containers:
       - name: myjob
         image: alpine:latest
         command: ['sh', '-c', 'echo "logging" > /opt/logs.txt']
         volumeMounts:
           - name: data
             mountPath: /opt
     initContainers:
       - name: logshipper
         image: alpine:latest
         restartPolicy: Always # sidecar init container
         command: ['sh', '-c', 'tail -F /opt/logs.txt']
         volumeMounts:
           - name: data
             mountPath: /opt
     restartPolicy: Never # pod lifecycle
     volumes:
       - name: data
         emptyDir: {}


Multiple versions d’API Server: Mixed version proxy (upgrade)

Cette fonctionnalité Alpha est très prometteuse, elle est activable avec l’option --feature-gates=UnknownVersionInteroperabilityProxy=true Une mise à jour de version de votre cluster, lorsque vous gérez vous-même vos clusters, dans des environnements disposant d’une très lourde charge et qui sollicitent énormément votre API Server, hors switch blue/green, engendre de temps à autre des petits soucis avec certains points d’API. 

En effet dans le cas de l’arrêt de l’API ou de changement (voire de suppressions) de endpoints d’API qui ont été introduits dans la version concernée, l’API Server interrogée ne sera pas en capacité de servir votre requête et entraînera une erreur 404. La fonctionnalité Mixed version proxy permet de relayer votre demande aux autres API Server afin de trouver celui qui sera capable de gérer votre demande, et dans le cas contraire une erreur 404 sera obtenue.

Améliorations en beta 

Les fonctionnalités promues en beta sont très souvent celles que vous retrouverez d’ici quelques versions comme fonctionnalités “natives” de votre cluster. Certains diront “Cela représente toujours un risque d’utiliser une version beta”, mais je suis sûr que si vous regardez bien la liste de versions d’API que vous utilisez dans votre cluster, je suis presque sûr que vous y trouverez a minima une ou deux versions en beta. 

Politique d’admission déclarative : Validating admission policy

Cette fonctionnalité beta, désactivée par défaut, est une alternative déclarative aux admissions webhooks de Kubernetes. Pour ce faire, vous devrez utiliser Common Expression Language (CEL) pour décrire votre policy. Elle se décompose en 3 ressources distinctes:

  • ValidatingAdmissionPolicy : représentant une abstraction de votre déclaration
  • ValidatingAdmissionPolicyBinding : servant de lien entre la déclaration et la cible
  • une ou plusieurs CRD: pouvant servir de paramètres appartenant à l’ensemble du cluster et d’un namespace en particulier

Pour l’activer, il vous suffit d’activer la feature-gate ValidatingAdmissionPolicy --feature-gates=ValidatingAdmissionPolicy=true

Comme les admissions webhook classiques, vous pouvez définir la FailurePolicy dans deux états Fail (état par défaut) qui rejettera votre appel en cas de refus et au contraire Ignore qui laissera passer dans tous les cas.

Cette approche est intéressante pour éviter l’enrichissement de l’API Server avec des outils tiers comme Kyverno sur l’utilisation de règles basiques et simples, mais avec une souplesse avec sa capacité d’utilisation de paramètres clusterwide ou par namespace.

Il est possible de coupler cette fonctionnalité matchConditions.

Exemple de configuration avec paramètre dans un namespace: 

La policy présentée contrôle que le nombre de réplicas de vos déploiements contenant le label environment = test correspond bien au maximum (params.maxReplicas) configuré dans la CRD rules.wescale.io/v1/ReplicaLimit de votre namespace.

---
# Définition de la ValidatingAdmissionPolicy
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingAdmissionPolicy
metadata:
  name: "replicalimit-policy.wescale.io"
spec:
 failurePolicy: Fail
  paramKind: # paramètre
    apiVersion: rules.wescale.io/v1
    kind: ReplicaLimit
  matchConstraints:
    resourceRules:
    - apiGroups:   ["apps"]
      apiVersions: ["v1"]
      operations:  ["CREATE", "UPDATE"]
      resources:   ["deployments"]
  validations:
    - expression: "object.spec.replicas <= params.maxReplicas"
     reason: Invalid
---
# Définition de la ValidatingAdmissionPolicyBinding
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingAdmissionPolicyBinding
metadata:
  name: "replicalimit-binding-test.wescale.io"
spec:
  policyName: "replicalimit-policy.wescale.io"
  validationActions: [Deny]
  paramRef# paramètre namespacé
    name: "replica-limit-test.wescale.io"
    namespace: "default"
 matchResources:
   namespaceSelector:
     matchLabels:
       environment: test
---
# Définition de la CRD
apiVersion: rules.wescale.io/v1
kind: ReplicaLimit
metadata:
  name: "replica-limit-test.wescale.io"
  namesapce: "default"
maxReplicas3


Filtrage des policies d’admission: Matching requests - matchConditions

Tout comme la fonctionnalité des ValidatingAdmissionPolicy, cette fonctionnalité s'appuie sur le CEL, feature beta activée par défaut, elle est utilisable avec les ValidatingAdmissionPolicy ainsi que ValidatingWebhookConfiguration. Le concept de ces conditions est d’offrir des capacités de filtrage avancé quand l’information recherchée n’est pas disponible dans les informations des objets par défaut (objectSelectors ou namespaceSelectors).

Par exemple, cette condition permet d’enrichir la policy (définie plus haut) en excluant les ressources de type leases ,les requêtes kubelet et RBAC :

matchConditions:
    - name: 'exclude-leases' # Each match condition must have a unique name
     expression: '!(request.resource.group == "coordination.k8s.io" && request.resource.resource == "leases")' # Match non-lease resources.
   - name: 'exclude-kubelet-requests'
     expression: '!("system:nodes" in request.userInfo.groups)' # Match requests made by non-node users.
   - name: 'rbac' # Skip RBAC requests.
     expression: 'request.resource.group != "rbac.authorization.k8s.io"'


Support du swap Linux: beta support for using swap on Linux

Introduite en Alpha dans la vers 1,22, il est maintenant possible de gérer simplement et “officiellement” le swap linux activé. Il conviendra de désactiver la configuration failSwapOn et de décider quelle option de swap vous souhaitez fournir à votre cluster. La métrique est disponible directement, le kubelet vous permet de contrôler l’usage du swap par votre application. Dernière subtilité, il vous faudra vous appuyer sur les cgroups v2, le support des cgroups v1 ayant été supprimé dans cette release.

Configuration de l’agent Kubelet

# Portion de code à ajouter dans votre fichier de configuration Kubelet
failSwapOn: false # (default) true
NodeSwap: true
memorySwap:
 # UnlimitedSwap (default): les applications dans votre cluster pourront utiliser à leur guise dans la limite du system
 # LimitedSwap: Uniquement disponible pour les Pods avec la QoS à Burstable
 swapBehavior: UnlimitedSwap

⚠️ Attention
L’activation du swap doit se faire en connaissance de cause et être opérée correctement. Cela peut être la source de différents problèmes comme une dégradation des performances (les accès disque I/O étant plus faibles que les accès RAM) ou de sécurité si le swap n’est pas encrypté correctement : (un attaquant pourrait prendre connaissance des données se trouvant sur le swap.

 

Améliorations passées en Stable

Toutes les fonctionnalités Stable peuvent être passées en production, elles apporteront plus de robustesse et/ou de souplesse. Comme toutes fonctionnalités et évolutions, elles pourraient être amenées à disparaître dans de futures versions et c’est pourquoi, il faudra être attentif aux dépréciations à venir en lien avec les versions que vous utilisez au sein de vos clusters.

Amélioration sur la maîtrise de l’arrêt non désiré des nœuds: Recovery from non-graceful node shutdown

En cas d'incidents, il se peut qu'un de vos nœuds de cluster ne soit plus en capacité de gérer vos applications. L’agent Kubelet du nœud incriminé ne sera pas capable de détecter un arrêt et ni de fournir les informations de drainage permettant de redéployer les applications sur d’autres nœuds. Même si un tel incident ne devrait pas impacter les applications de type stateless, celles de type stateful le seront. En ajoutant une taint à votre nœud, vous pouvez désormais lancer le redéploiement de vos applications plus rapidement: 

kubectl taint nodes mon-nœud-hs node.kubernetes.io/out-of-service=nodeshutdown:NoExecute

De nouvelles métriques vous permettront de visualiser les impacts des actions réalisées. Le calcul du nombre de pods arrêtés avec la taint précédemment appliqué force_delete_pods_total et force_delete_pod_errors_total ainsi que le nombre de pod attachdetach_controller_forced_detaches.

L’inconvénient reste ici de devoir placer cette information “manuellement” sur votre nœud. Mais un contournement devrait aisément être faisable pour appliquer cette méthode automatiquement.

Nouvelle gestion de la StorageClass par défaut: Automatic, retroactive assignment of a default StorageClass

Cette fonctionnalité, paraissant mineure et simpliste, change grandement le paradigme de séquençage de création de PVC dans votre plateforme. Jusqu’à lors, il vous fallait définir une storageClass par défaut (ou bien de la configurer dans vos PVC) pour éviter d’avoir des PVCs dont l’allocation de ressources n’aboutira jamais dans votre environnement. Avec la version 1.28, l’ordre n’a plus d’importance grâce à la rétroactivité de la storageClass par défaut qui s’applique sur tout PVC n’ayant pas de définition.

Petit risque cependant,  par exemple si vous ne contrôliez pas les PVC bloqués (dans un environnement de POC/DEV) ou que vous n’aviez pas de storageClass par défaut et que vous décidiez d’en avoir une maintenant, vous risquez de vous retrouver avec de l’allocation de stockage complémentaire qui pourrait avoir un coût non négligeable dans vos environnements.

Conclusion

Cette nouvelle version n’apporte pas de gros changements, mais des fonctionnalités qui passent en stable ou en beta offrant des enrichissements de vos clusters. J’ai essayé au travers de cet article de retenir celles qui selon moi devraient apporter des changements permettant de réduire le nombre d’outils déployés dans vos clusters tout en permettant d’avoir une plateforme stable répondant à vos contraintes de production. Côté cloud providers et distributions, comme à son habitude, il faudra être patient selon que vous vous appuyez sur une distribution native ou celle d’un cloud provider variant de quelques jours à quelques semaines.

Liens