C’est quoi Kubernetes et pourquoi l’utiliser ?

C’est quoi Kubernetes et pourquoi l’utiliser ?

Temps de lecture : 9 minutes

Au premier abord, on ne comprend pas Kubernetes à cause de sa complexité et on se demande bien à quoi cela sert. Mais une fois compris, on ne veut que l’adopter pour gérer son infrastructure conteneurisée. Nous allons voir pourquoi et comment l’utiliser dans cet article.

Kubernetes est un orchestrateur de conteneurs développé par Google. Il a été annoncé en 2014 et sa première version stable date de 2015. Rapidement, il a suscité l’intérêt de plusieurs autres entreprises comme IBM, Microsoft ou Amazon. Depuis, Google l’a donné en projet open source à la CNCF (Cloud Native Computing Foundation) qui le maintient et est donc développé par une multitude de personnes et organismes.

Vous trouverez dans cet article des ressources expliquant Kubernetes, cependant, j’appuierai sur certains points que je trouve intéressants.

Vidéo de présentation

Source: YouTube (Cookie connecté)

Cette vidéo résume très bien ce qu’est Kubernetes et l’importance qu’il peut avoir pour la gestion de conteneurs. Nous allons maintenant explorer les différents concepts évoqués ainsi que d’autres points non évoqués que je trouve plutôt importants.

Petit point jargon, Kubernetes vient du grec ancien signifiant « Capitaine » ou « Pilote » et est la racine de « Gouverneur » et « Cybernetic ». Il est souvent abrégé « k8s », dérivée par le remplacement des 8 lettres « ubernete » par « 8 ».

Par défaut Kubernetes utilise le moteur de conteneur Docker, mais il est compatible avec d’autres moteurs tel que cri-o, containerd ou frakti

Liens utiles

Qu’est-ce-que Kubernetes (Documentation Officielle Kubernetes)
LearnK8S (Compte twitter partageant des ressources/tutoriels sur Kubernetes)

Pourquoi l’utiliser ?

On utilise/installe pas soi-même Kubernetes pour déployer un simple blog WordPress et un serveur MySQL, pour cet usage on se tourne vers un fournisseur de services Cloud proposant de l’hébergement web au travers de Kubernetes afin de profiter d’un coût moindre (comme Otux.fr par exemple).
On l’utilise pour disposer d’une plateforme de déploiement résiliente et à haute disponibilité avec une configuration et une gestion simple (on manipule seulement des données YAML via l’API), automatiser des concepts compliqués à mettre en place (auto scaling par exemple), réserver des ressources pour une application et l’isoler.
Il est par exemple installé pour éviter au développeur de devoir gérer son environnement (développement, pré production, production). Il n’a plus qu’à se concentrer sur la partie programmation de son logiciel, il est ensuite « packagé » avec Docker et déployé sur les serveurs via Kubernetes par un/une team devops. La gestion du versioning est aussi simplifiée car la version du logiciel est représentée par le tag de l’image docker (Exemple: php:7.4 pour php version 7.4) dans le déploiement et chaque modification crée un objet (ReplicaSet) afin de garder un historique des versions déployées auparavant (pour faciliter les rollbacks).
Et encore, ce ne sont que des exemples dans l’éventail des possibilités que Kubernetes offre.


Les concepts

Pour utiliser Kubernetes, il faut comprendre comment il fonctionne en détail et le configurer afin de correspondre à nos attentes. En fonction des limitations de votre fournisseur ou de votre infrastructure système / réseau, vous serez amené à faire un choix plutôt qu’un autre.

Master, worker et base de données

Un serveur ayant pour rôle d’être un master s’occupe de la gestion globale du cluster Kubernetes.

Plusieurs composants (le control plane) sont déployés sur un master:

  • Le serveur API:
    • Reçoit des informations de Kubelet (l’agent sur chaque serveur qui contrôle les conteneurs) et d’autres contrôleurs.
    • Sert a administrer le cluster
    • Point d’entrée vers d’autre APIs/contrôleurs déployé sur le cluster
    • Est relié à la base de données ETCD
  • Le manager de contrôleur
    • S’occupe de surveiller d’autres contrôleurs (imbriqués dans le manager) du système de Kubernetes (réplication, point finaux (endpoint), espace de nom (namespace), compte de service (service account)).
  • Le planificateur
    • Reçoit des ordres du contrôleur de réplication
    • Orchestre le placement des Pod (et ses conteneurs) sur les serveurs worker en fonction des ressources nécessaires et des conditions de placement (conditions sur le serveur ou dans le pod)

Le worker quant à lui n’a que deux composants déployés de base par Kubernetes (en oubliant le réseau)

  • Kubelet
    • C’est le composant majeur car c’est lui qui envoie les informations du serveur (ressources disponibles et totales, état des conteneurs) à l’API et permet à tout le reste de fonctionner. Il lance aussi les conteneurs avec les informations fournies par le planificateur (volumes de stockage, réseau, ressources, permissions, etc…)
  • Kube Proxy
    • C’est un proxy transparent permettant de router les requêtes de service k8s. Il maintient les règles réseau pour permettre une communication réseau vers les Pods depuis des sessions réseau à l’intérieur ou à l’extérieur du cluster.
  • Un proxy NGINX
    • Ce proxy est déployé par défaut avec kubespray et permet au composant kubelet de communiquer vers l’API avec via un répartiteur de charge, cela permet une configuration haute disponibilité pour l’accès à l’API.

La base de données ETCD et généralement déployée sur les masters mais peut aussi être présente en réplique sur un ou plusieur autre serveur(s) tant que leurs nombres sont impairs. Elle contient tous les objets Kubernetes et sans cette dernière, Kubernetes ne fonctionne pas. C’est donc le composant le plus critique de Kubernetes même si un autre etcd prend le relai quand le principal tombe.

Les serveurs

Kubernetes peut en théorie fonctionner sur un seul serveur, ce dernier étant master et worker en même temps. Mais ce n’est vraiment pas ce qu’on veut n’est-ce pas ? On veut de la disponibilité et de la répartition de charge !

Pour ça, plus il y a de serveurs mieux c’est ! Kubernetes peut en gérer jusqu’à 5000 serveurs sans soucis, mais je vous conseille de bien balancer les serveurs en matière de puissance afin de ne pas surcharger Kubernetes avec 3000 petits serveurs.
Exemple de serveur: 8 Coeurs/16 Thread, 32 Gb de ram ou plus, 1x500Gb SSD (pour le système d’exploitation et les images docker téléchargées), plusieurs (au minimum 2) SSD/HDD en fonction de votre choix de stockage.

Pour de la production, il faut au minimum 2 serveurs car il y aura 2 serveurs master et 2 worker (les masters étant aussi worker si on réactive la planification de Pod sur les masters qui est désactivée par défaut en retirant une condition sur l’objet k8s du serveur, ainsi le planificateur peut planifier des pods sur ces derniers). Ainsi, si un master tombe, l’autre sera encore en mesure d’orchestrer le cluster. Il est cependant possible de faire des petits masters en terme de CPU/RAM s’ils ne sont pas worker car ils exécuteront seulement les logiciels vitaux de Kubernetes.

Le réseau

Le principe même de Kubernetes est de faire un cluster de serveurs, pour cela, les serveurs doivent pouvoir communiquer entre eux. Ils peuvent le faire via Internet (via un tunnel afin de garder les composants du cluster en sécurité) ou tout simplement via un réseau privé sur une autre interface.

Plus il y a de bande passante, mieux c’est ! Le minimum recommandé est 1Gb/s voir 10Gb/s pour des clusters avec beaucoup de charge de travail (workload), voir plus (40Gb/s, infrastructure « SAN ») pour le stockage.

Maintenant que nos serveurs peuvent communiquer entre eux (en IPv4 et en IPv6 de préférence), il est temps de s’attaquer au plat de résistance: le CNI (Container Network Interface). Ce n’est pas un composant obligatoire mais fortement conseillé car il va permettre de créer et gérer « automatiquement » un ou plusieurs réseau(x) virtuel(s) pour notre cluster de conteneurs et on a le choix quant-aux solutions !

On appelle « underlay » le réseau physique entre les serveurs et « overlay » le réseau virtuel composé de VLAN, interfaces virtuelles et VxLAN. Le CNI est un moyen de créer et gérer un overlay et permet d’y attacher des conteneurs.

Liste des solutions:

  • Calico
    • Supporte les networkPolicies de k8s (isolation/filtrage avec objet natif de k8s)
    • Supporte IPv6
    • Utilise la couche 3 (Réseau) du modèle OSI (IPinIP, BGP)
    • Plusieurs réseau possible
    • Gestion via configuration ou CLI calicoctl
  • Cilium
    • Supporte les networkPolicies de k8s ainsi que son objet personnalisé « ciliumNetworkPolicies »
    • Supporte IPv6
    • Utilise les couches 3 (Réseau), 4 (Transport) et 7 (Application, seulement pour le filtrage)
    • Sous réseaux par noeud
    • Gestion via configuration ou CLI cilium
    • Peut remplacer kube-proxy (vu qu’il utilise la couche 7)
  • Contiv
    • Ne supporte pas les networkPolicies de k8s
    • Supporte IPv6
    • Utilise les couches 2 (liaison, pour VxLAN) et 3 (réseau, pour BGP)
    • Plusieurs réseau possible
    • Gestion via configuration
  • Weave Net
    • Supporte les networkPolicies de k8s
    • Supporte IPv6
    • Utilise la couche 2 (liaison, pour VxLAN)
    • Sous réseaux par noeud
    • Gestion via configuration
  • Flannel
    • Ne supporte pas les networkPolicies de k8s
    • Ne supporte pas IPv6
    • Utilise la couche 2 (liaison, pour VxLAN)
    • Plusieurs réseaux possible avec plusieurs flannel dans le cluster
  • Multus
    • Celui ci est un peu différent, il permet juste à un pod et à ses conteneurs d’être lié à plusieurs CNI personnalisés (Weave, Calico, etc…) ou CNI natifs (bridge, macvlan, host, etc…)

Vous pouvez retrouver plus d’informations ainsi que la même comparaison sur l’article du site d’Objectif Libre: Comparatif des solutions réseaux pour Kubernetes

Volumes

Les volumes sous Kubernetes (ou PersistentVolume) sont des « disques durs » attachés au pod. Mais pour pouvoir les utiliser, il nous faut déjà un fournisseur de stockage (CSI = Container Storage Interface) ou un serveur NFS externe au cluster. Il y en a plusieurs et vous pouvez en utiliser plusieurs à la fois:

  • OpenEBS
  • Portworx
  • Rook (opérateur Kubernetes pour Ceph principalement)
  • StorageOS
  • Rancher Longhorn
  • GlusterFS

Je ne détaillerai pas les avantages et inconvénients de chacun car certaines solutions sont meilleures pour une certaine utilisation. Vous devez donc faire votre choix en vous informant sur chaque. Personnellement j’utilise Ceph (déployé avec rook).

Ensuite chaque CSI est configuré avec un objet « StorageClass » qui définit la pool de stockage et quel fournisseur CSI utiliser. Après cela, le « PersistentVolume » est créé grâce à un objet « PersistentVolumeClaim » qui permet de configurer le nom, le stockage et le mode d’accès du volume. Ce dernier est ensuite utilisé pour être lié à un ou plusieur conteneur selon son mode d’accès (ReadWriteOnce = un seul pod peut utiliser le volume, ReadWriteMany = plusieurs pods peuvent utiliser le volume) et la disponibilité du « PersistentVolume » (s’il est créé, déjà utilisé, etc…)

Services

Les services Kubernetes sont des répartiteurs de charge virtuels. C’est kube-proxy qui s’occupe de router les requêtes vers les points finaux (Endpoints) du service.
Chaque service possède une VIP (Virtual IP) dans le réseau overlay et pointe vers des objets « Endpoints » contenant les VIP du/des pod(s) vers le(s) quel(s) rediriger le trafic.
L’objet Service contient aussi un champ « type ». Car en effet plusieurs types de services peuvent être créés:

  • ClusterIP
    • Seulement une VIP
  • NodePort
    • Une VIP
    • Un port publique NAT (dans une plage de port réservée sur chaque noeud)
  • LoadBalancer
    • Une VIP
    • Un port publique NAT (dans une plage de port réservée sur chaque noeud)
    • Un port publique NAT de vérification d’état de santé du service pour savoir sur quel serveur router l’IP (dans une plage de port réservée sur chaque noeud)
    • Nécessite un fournisseur cloud qui s’occupe de router les IP sur les serveurs ou utiliser MetalLB pour annonces des IP en ARP ou en BGP.

Un service peut soit être en IPv4 soit en IPv6. Pour un service dual-stack, il faudra en créer deux (un pour chaque type de protocole)

Le service créé un objet « Endpoint » et Kubernetes injecte dans ce dernier les adresses IP des pods correspondants aux labels du sélecteur dans l’objet « Service ». Le service est ensuite opérationnel sur les ports définis.

Il est aussi possible de créer un service du type « Headless ». Il permet de pointer directement un champ DNS sur l’ip de chaque pod dans le service. Le service ne possède pas de VIP et n’effectue donc pas de répartition de charge, seuls les pods sont accessible via nom_pod.nom_service.namespace.svc.cluster.local (cluster.local étant le domaine racine du cluster par défaut).

Pod

Un pod est un groupement logique d’un ou plusieurs conteneur(s). Chaque conteneur dans un pod a les mêmes paramètres réseau (étant dans le même espace de nom réseau au niveau du noyau linux). Chaque conteneur peut donc communiquer avec un autre dans un même pod via l’adresse loopback (localhost/127.0.0.1/::1). Il est généralement créé et contrôlé par un objet appelé « ReplicaSet » lui-même créé et contrôlé par l’objet « Deployment ».

Scaling (dimensionnement)

Un déploiement peut être scalé horizontalement et verticalement, dans un scaling horizontal on augmente le nombre de réplique d’un pod et le trafic est réparti grâce au service alors que dans un scaling vertical on augmente les ressources du pod dans le déploiement.

Kubernetes intègre par défaut l’auto-scaling horizontal, c’est-à-dire qu’en fonction de l’utilisation d’un groupe de pod en matière de CPU ou RAM, d’autres instances seront créées afin de tenir la charge du service ou au contraire, supprimées par manque de charge. L’auto-scaling vertical ainsi que d’autres contrôleurs de scaling horizontal sont disponibles avec des contrôleurs indépendants qu’il faut déployer manuellement.

Exemple de déploiement

L’utilisateur crée un objet « Deployment » avec 2 répliques du Pod et un objet « Service » qu’il envoie à l’API. Voici comment Kubernetes traite ces deux objets jusqu’au déploiement des pods et du routage du service vers ces derniers.
Les objets se lient entre eux, si l’utilisateur supprime l’objet Deployment les ReplicaSets créés ainsi que les Pods seront supprimés. Pareil pour l’objet Service, l’endpoint sera supprimé automatiquement.

Schéma de creation des pods et routage du service sur ces derniers à partir de la création des objets « Deployment » et « Service »

Installation/Utilisation

Pour installer ou utiliser Kubernetes, plusieurs méthodes s’offrent à vous:

  • Utiliser un fournisseur de service Kubernetes
  • Installer RedHat OpenShift
    • OpenShift intègre Kubernetes mais avec quelques modifications comparé à la distribution de base.
  • L’installer via Kubespray
    • C’est la méthode que j’utilise et que je conseille, c’est la distribution de base et la configuration du cluster ainsi que les éléments réseau est simplifiée avec Ansible. Cet outil est proposé par la team SIG de Kubernetes et est donc officiellement supporté et mis à jour pour la production.
  • Installer Rancher
    • Distribution de base modifiée afin de coller avec l’environnement de Rancher.
    • Permet de gérer plusieurs clusters (cloud hybride)
  • Installer k3s
    • Un Kubernetes plus léger que la distribution de base
  • Installer minikube
    • Un Kubernetes plus léger que la distribution de base
    • Utilisé pour les environnement de développement (de test) sur une seule machine ou un petit cluster local (avec des machines virtuelles par exemple)
    • Proposé à l’installation sur plusieurs OS (Ubuntu, Docker for Mac, etc…)

D’autres solutions s’offrent à vous, je ne les ai pas listé ici car il y en a beaucoup: Choisir la bonne solution

Conclusion

J’espère qu’avec cet article vous aurez réussi à mieux comprendre Kubernetes et pourquoi l’utiliser.

Cet article est le premier d’une série d’article consacrée à Kubernetes, il pose la base de connaissances à avoir afin de mieux comprendre les suivants.

 

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *