Comment le CRI de Kubernetes gère exec, attach et la redirection de ports
Une analyse approfondie de 2024 explique l'architecture de streaming unique basée sur des URL derrière les commandes de l'interface d'exécution de conteneurs (CRI) de Kubernetes.
Traduit automatiquement depuis l'original anglais.
Dans un article publié sur le blog Kubernetes en mai 2024, Sascha Grunert a détaillé les mécanismes internes de trois appels de procédure à distance (RPC) spécifiques de l'Interface d'Exécution de Conteneurs (CRI). L'article explique comment Exec, Attach et PortForward diffèrent des interactions gRPC standard en utilisant un modèle de streaming distinct basé sur des URL, qui est resté cohérent depuis sa conception en 2016.
Ce qui s'est passé
Le CRI de Kubernetes sert de pont principal entre le kubelet et les environnements d'exécution de conteneurs, exigeant que ces derniers exposent un serveur gRPC conforme à une interface Protocol Buffer définie. Alors que la plupart des opérations CRI reposent sur des appels unaires simples ou du streaming côté serveur, Grunert a souligné que Exec, Attach et PortForward fonctionnent différemment. Ces trois fonctions sont cruciales pour les développeurs ayant besoin d'exécuter des commandes dans les conteneurs, de visualiser les sorties en direct ou de rediriger des ports réseau pour le débogage.
Grunert a retracé l'historique de ces fonctionnalités jusqu'à un document de conception de 2016, antérieur aux propositions modernes d'amélioration de Kubernetes (KEP). Avant l'initiative CRI, ces capacités étaient étroitement liées à des environnements d'exécution spécifiques comme Docker ou rkt. La communauté a envisagé la mise en œuvre native du streaming RPC mais l'a rejetée car elle créerait des goulets d'étranglement réseau au niveau du kubelet et limiterait la flexibilité des environnements d'exécution. Au lieu de cela, ils ont adopté un modèle où l'environnement d'exécution fournit un serveur de streaming, permettant à chaque implémentation de gérer les connexions indépendamment.
Cette décision architecturale signifie que bien que la demande initiale passe par l'interface gRPC standard, le transfert réel des données se fait via une connexion HTTP séparée. Cette séparation permet aux environnements d'exécution de faire évoluer leurs implémentations de streaming sans modifier la définition centrale du CRI. Bien que des améliorations mineures aient été fusionnées au fil des ans, le schéma fondamental consistant à demander une URL puis à s'y connecter directement est resté inchangé.
Comment cela fonctionne
Le processus commence lorsqu'un client, tel que kubectl ou crictl, envoie une requête gRPC à l'environnement d'exécution pour une session Exec, Attach ou PortForward. Contrairement aux appels API typiques qui renvoient directement les données, l'environnement d'exécution valide la requête et la stocke dans un cache de suivi des connexions. Il renvoie ensuite une réponse contenant uniquement une URL complète. Le client doit alors se connecter à cette URL, en mettant à niveau la connexion pour utiliser soit le protocole SPDY, soit de plus en plus souvent les WebSockets, afin de commencer le streaming des données.
Pour Exec et Attach, Kubernetes définit un protocole spécifique avec cinq versions, actuellement jusqu'à v5.channel.k8s.io. Ce protocole utilise le premier octet de chaque paquet pour identifier le type de flux, tel que l'entrée standard, la sortie standard, les erreurs standard ou les signaux de contrôle comme le redimensionnement du terminal et la fermeture. Le code source du kubelet fournit une bibliothèque réutilisable qui gère cette interprétation du protocole, ne nécessitant des environnements d'exécution que l'implémentation de la logique pour exécuter les commandes ou s'attacher aux processus. PortForward fonctionne différemment, car il n'a pas de définition de protocole stricte. Au lieu de cela, l'environnement d'exécution entre dans l'espace de noms réseau du conteneur et diffuse des trames SPDY brutes, s'appuyant sur des bibliothèques comme moby/spdystream pour gérer le flux de données.
Détails clés
- Les RPC CRI
Exec,AttachetPortForwardne renvoient qu'une chaîne d'URL dans leur réponse, et non le flux de données réel. - Les clients doivent mettre à niveau la connexion HTTP vers SPDY ou WebSockets pour établir la session de streaming après avoir reçu l'URL.
- Les protocoles
ExecetAttachutilisent le premier octet de chaque paquet pour distinguer stdin, stdout, stderr, les erreurs, les événements de redimensionnement et les signaux de fermeture. - Cinq versions du protocole de commande à distance existent, la v5 ajoutant la prise en charge d'un signal CLOSE pour les WebSockets.
- Le kubelet fournit une bibliothèque réutilisable avec une interface
Runtimeque les environnements d'exécution doivent implémenter pour gérer l'exécution sous-jacente des commandes et l'entrée dans l'espace de noms réseau. - Les efforts futurs se concentrent sur le remplacement de SPDY par les WebSockets, avec des outils comme
crictlv1.30 prenant déjà en charge un indicateur--transportpour choisir entre eux.
Pourquoi c'est important
Pour les ingénieurs logiciels qui construisent ou maintiennent des environnements d'exécution de conteneurs, comprendre cette architecture est essentiel pour une implémentation correcte. Le découplage du plan de contrôle (gRPC) et du plan de données (streaming HTTP) signifie que les développeurs d'environnements d'exécution ne peuvent pas simplement traiter ces appels comme des demandes API standard. Ils doivent gérer des sessions de streaming concurrentes, traiter les mises à niveau de protocole et assurer la compatibilité avec plusieurs versions de protocole. Mal interpréter le premier octet d'un paquet de données ou ne pas prendre en charge les événements de redimensionnement du terminal peut entraîner des expériences utilisateur cassées dans les workflows de développement courants.
Cette conception affecte également la façon dont les outils de débogage interagissent avec les clusters. Parce que les données contournent le kubelet après la récupération initiale de l'URL, les politiques réseau et les proxys doivent autoriser la communication directe entre le client et le nœud hébergeant le conteneur. À mesure que l'écosystème évolue vers les WebSockets, les ingénieurs doivent s'assurer que leurs outils prennent en charge la nouvelle couche de transport. Les travaux en cours dans des projets comme CRI-O, qui déplace la logique de streaming vers conmon-rs, démontrent comment cette flexibilité permet aux environnements d'exécution de maintenir les sessions actives même si le processus principal de l'environnement d'exécution redémarre, améliorant ainsi la fiabilité des sessions de débogage de longue durée.
Ce que vous pouvez faire
- Vérifiez que votre environnement d'exécution de conteneurs prend en charge le dernier protocole
v5.channel.k8s.iopour garantir un traitement correct des signaux de fermeture de flux. - Mettez à jour les outils clients comme
crictlà la version 1.30 ou ultérieure pour tester la prise en charge du transport WebSocket à l'aide de l'indicateur--transport. - Examinez vos politiques réseau pour vous assurer que les clients peuvent atteindre les IP et les ports des nœuds utilisés pour les connexions de streaming, et pas seulement le serveur API.
- Si vous développez un environnement d'exécution personnalisé, utilisez la bibliothèque de streaming réutilisable du kubelet pour gérer l'analyse du protocole plutôt que de l'implémenter à partir de zéro.
- Surveillez l'adoption des WebSockets dans votre environnement, car SPDY est progressivement abandonné au profit de normes web plus modernes.
- Vérifiez si votre environnement d'exécution peut décharger les sessions de streaming vers des moniteurs externes comme
conmon-rspour améliorer la résilience lors des mises à jour de l'environnement d'exécution.


