Vous utilisez peut-être déjà les conteneurs depuis un moment, mais avez-vous déjà essayé de mettre en place des solutions distribuées ou simplement redondantes avec des conteneurs ? Faire tourner deux conteneurs de la même application sur la même machine peut vite devenir lourd, il n’y a pas moyen de simplement lancer la même commande, car le port réseau est déjà utilisé par exemple. Simple à gérer vous me direz, il suffit de lancer le deuxième conteneur en mappant un autre port, c’est vrai, mais essayez de faire cela quand vous devez gérer 150 conteneurs, le cauchemar n’est-ce pas ? Il y a une solution pour ça, et cette solution porte le nom si bien choisi d' « orchestrateur », car oui tel le maître d’orchestre, il va nous permettre de donner du rythme et de l’ordre dans le brouhaha que peut être la gestion de conteneurs.
1. Un orchestrateur c'est quoi ?
Je vais essayer de ne pas rentrer dans trop de détails techniques dans cette partie, mais simplement donner une vue d’ensemble de l'implémentation d’un orchestrateur.
Pour faire simple, un orchestrateur est un outil d’automatisation et de gestion de conteneurs et de services, mais c’est aussi un outil opérationnel visant à gérer toutes les ressources devant permettre à vos conteneurs ou services d'être fonctionnels.
C’est ainsi que l’orchestrateur s’occupera de gérer l’attribution IP de vos conteneurs ainsi que leur port mapping au niveau du système d’exploitation où tourneront vos conteneurs.
C’est l’orchestrateur qui se charge du scaling de votre application si c’est nécessaire lorsque vous subissez un pic d’utilisation de votre application web, mais c’est aussi lui qui se charge de faire le rolling upgrade de votre application quand vous mettez à jour l’image de vos conteneurs.
Si votre application a besoin d’un volume de stockage, il est capable de demander ce volume à un provider (cloud ou non) et de l'attacher à votre conteneur.
C’est aussi à lui de trouver le ou les nœuds les plus adaptés pour faire tourner votre workload, en fonction par exemple de leur capacité ou de leur OS.
Un orchestrateur c’est un peu comme un OS distribué, il gère des conteneurs, du stockage, le réseau ainsi que les droits d'accès des utilisateurs voulant démarrer une application, comme le ferait Linux, la différence est qu’il peut le faire sur une multitude de nœuds en même temps.
2. L'histoire abrégée des orchestrateurs
Avec le succès de Docker dès 2013, plusieurs problématiques se sont posées aux équipes qui ont dû gérer des environnements conteneurisés. Comment allaient-elles devoir manager les déploiements, peut-on mutualiser les infrastructures pour y faire tourner plusieurs conteneurs sur la même machine virtuelle, ou encore comment faire en sorte que les systèmes soient suffisamment robustes pour faire en sorte de ne pas avoir d'arrêts de production suite au crash d’une machine virtuelle ? Mais comment se passer des conteneurs et du formidable gain qu’ils pouvaient apporter à la mise en production de nouvelles fonctionnalités ou de correction de bugs ?
En 2015, c’est l’annonce de la version 1.0 d’un projet basé sur un outil utilisé chez Google, un certain Kubernetes [1], en 2015 c’est aussi Docker qui lance de son côté Docker Swarm. Plusieurs autres projets voient leur version 1.0 en 2016 tels que Marathon d’Apache Mesos.
Et dernièrement, nous avons aussi eu l'arrivée en 2020 de Nomad de Hashicorp en version 1.0 sur le segment des orchestrateurs, bien que le projet ait débuté en 2015.
Cette vision du paysage de l’orchestration n’est pas exhaustive, AWS ou Microsoft ont par exemple créé le leur pour leur cloud avant d'intégrer Kubernetes, ou d'autres un peu moins connus comme Rancher avec Cattle.
Tout cet écosystème a permis de voir évoluer les différentes solutions, mais en fin 2017 la communauté a définitivement choisi son champion, et c’est Kubernetes. Depuis lors nous avons vu s'arrêter certains projets tels que Cattle de Rancher, qui s'est alors focalisé sur l’instanciation de clusters Kubernetes, de son côté le projet Marathon a totalement été arrêté en 2019. Avec le rachat de Docker par Mirantis, les plateformes Swarm migrent petit à petit vers Kubernetes, surtout depuis l’ajout de Mirantis Kubernetes Engine permettant de faire tourner dans un cluster hybride, Swarm aux côtés de Kubernetes.
3. Passons à la pratique
Quoi de mieux pour comprendre les avantages et la joie que peut être un orchestrateur à l’usage, qu’en mettant les mains dans le cambouis ?
Cet article étant une exploration des orchestrateurs, je vais me permettre de choisir deux des trois orchestrateurs encore sur le marché, en dehors de ceux spécifiques aux différents cloud provider.
Pour chaque orchestrateur, nous allons tester deux types d’installation, la première, vous permettant d’utiliser l’orchestrateur directement depuis votre ordinateur, la deuxième méthode vous permettra d'être proche d’un environnement rencontré en entreprise.
Mon choix s'est donc porté sur Docker Swarm et Kubernetes.
Swarm, car malgré sa perte de vitesse, il reste encore très présent dans de nombreuses entreprises, et si vous êtes déjà habitué à Docker Compose vous ne serez pas perdu.
Le deuxième choix est évidemment Kubernetes, choix de la communauté pour ses diverses forces telles que son évolutivité, son intégration avec les différents clouds ou encore son écosystème, mais c’est aussi le mien lorsqu’il s’agit de faire tourner un conteneur.
Je n’aborderai pas ici Nomad, malgré un certain intérêt pour les produits créés par Hashicorp, celui-ci n’a pour moi pas d’avantages par rapport à Kubernetes dans un usage standard de conteneurs.
3.1 Docker Swarm
Un des avantages de Swarm c’est qu’il est directement prêt à être mis en place lorsque vous installez Docker sur une machine, même si toutefois ce n’est pas utile sur votre Mac ou Linux de salon, cela peut être intéressant de le noter lorsque vous voulez monter une infra Swarm dans votre lab.
Si vous avez déjà l’habitude d’utiliser Docker Compose, l’utilisation de Swarm ne va pas vous perdre, ce qui est un avantage lorsque vous voulez découvrir les bienfaits de l’orchestration.
3.1.1 SinD
SinD [2] ou Swarm in Docker, est un binaire qui vous permet de créer un cluster Swarm directement sur un nœud faisant tourner Docker (disons votre laptop). C’est un formidable outil si vous souhaitez tester un déploiement Compose dans Swarm, mais que vous n’avez pas la possibilité de créer de machines virtuelles.
Pour commencer, il vous faut une machine avec Docker.
La première étape va consister à télécharger le binaire depuis la page GitHub du projet :
Puis d’ajouter le binaire à votre PATH :
Vérifions la version de SinD pour valider que nous sommes capables d'exécuter le binaire :
Maintenant, nous sommes prêts à lancer la création de notre cluster Swarm de taille standard composé d'un manager et d'un worker :
Félicitations, vous venez de créer votre premier cluster Swarm !
Cette configuration inclut un mapping sur le port 8080 de la machine qui va nous servir dans quelques instants à accéder à une application web que nous allons déployer.
Bien entendu, si vous désirez déployer vos propres applications, il vous faudra faire vous-même ce travail de mapping de ports. Mais encore une fois, si vous êtes déjà familiarisés avec Docker, la méthode est la même et elle ne devrait donc pas vous dérouter.
Connectons-nous au cluster Swarm :
Nous pouvons ensuite lister les noeuds du cluster Swarm et interagir avec eux :
C’est parfait, nous voyons bien nos deux nœuds, un manager et un worker, et tout ça tourne dans mon Docker desktop.
Maintenant que notre environnement est fonctionnel, déployons une première application. Pour éviter la complexité, nous allons déployer un simple serveur web qui affiche un message de bienvenue.
Voici le fichier Compose que nous utilisons :
C’est parti pour le déploiement :
Vérifions que notre déploiement correspond bien à ce que nous attendons :
Puis vérifions que nous avons bien accès à notre application :
Une fois que notre test est validé, nous pouvons faire un peu de ménage pour ne pas consommer des ressources inutilement :
3.1.2 Swarm en vrai
La première étape est d’installer Docker Community Edition sur nos deux machines.
Maintenant que nous avons découvert comment tester Swarm sans aucun effort, passons à une configuration un peu plus conventionnelle. Comme pour SinD, nous allons créer un cluster avec un seul manager et un seul worker. Il ne nous faut donc pas plus de deux machines pour mettre en place le cluster, chacune d'elles avec 1 vCPU et 1Go de RAM. Pour le système d’exploitation, je vais rester classique et choisir Ubuntu, mais n'importe quelle distribution fait aussi bien l'affaire.
La première étape est d’installer Docker Community Edition sur nos deux machines :
Nous ajoutons ensuite notre utilisateur au groupe Docker pour nous faciliter la vie :
Passons ensuite à la création du manager. Pour ce faire, il va nous falloir récupérer l’IP de notre nœud pour l’ajouter à la commande. N'étant pas un adepte du copier-coller, voilà ma petite astuce pour l'obtenir directement en ligne de commandes :
Notre manager est maintenant prêt, nous pouvons passer au worker. Il nous suffit d'utiliser la commande fournie par le manager :
Si tout s'est bien passé, nous pouvons vérifier depuis le manager que les deux noeuds font bien partie du cluster :
À ce stade, nous ne pouvons contrôler notre cluster que depuis le nœud manager, ce qui n'est pas la situation idéale. En effet, à terme il serait plus naturel de pouvoir le commander directement de notre poste de travail. Heureusement c'est quelque chose d'extrêmement simple à configurer avec cette variable d'environnement qui nous permet d'interagir avec le manager au travers de SSH :
Maintenant nous pouvons lister les noeuds du cluster localement :
Notre configuration en place, nous pouvons déployer notre application de test comme précédemment :
Jetons un coup d'oeil à la stack applicative :
Et finalement, testons l'accès à l'application :
Voilà, notre premier cluster Swarm est en place ! Le gros plus de Swarm est sans nul doute son utilisation intuitive lorsque l'on est déjà familiarisé avec Compose.
3.2 Kubernetes
Kubernetes est sans doute intimidant au premier abord, mais dites-vous que seul le premier pas coûte, mais ensuite il n’y plus de retour possible : tout autre orchestrateur vous semblera sans saveur.
L'atout majeur de Kubernetes c’est son adaptabilité et sa capacité d'évolution. Vous voulez y ajouter de nouveaux objets à lui faire gérer ? Pas de soucis, il y a les Custom Resource (CRD) pour ça. Vous voulez empêcher vos utilisateurs de pouvoir déployer dans le namespace d’autres équipes ? Pas de soucis, Kubernetes vient directement avec RBAC.
Kubernetes est un pur outil cloud natif, il est totalement capable de gérer des ressources de votre cloud pour vous, comme le stockage ou les load balancer par exemple.
Pour éviter de vous perdre, je vais directement vous montrer le déploiement de notre application, le tout dans un simple fichier YAML comprenant deux parties : un déploiement et un service. Mais à quoi cela correspond-il simplement ?
Le déploiement permet de gérer les réplicas de conteneurs, comment ils peuvent être déployés au sein du cluster ou combien de réplicas.
Le service permet de donner une IP et un nom DNS uniques dans le réseau interne de Kubernetes pour accéder aux différents pods de l’application que vous déployez.
Voici le contenu de ce fichier :
Interagir avec l’API de Kubernetes peut se faire de diverses façons, Curl ou Postman par exemple, mais la façon la plus simple est d'utiliser kubectl qui a été créé pour cela, téléchargeons donc le binaire :
Passons maintenant à la pratique avec Minikube, un outil du projet Kubernetes qui permet de déployer un cluster local en une seule commande, puis nous passerons au déploiement d’un cluster plus proche d’un environnement d'entreprise.
3.2.1 Minikube
Minikube tout comme SinD est un simple binaire qui s'occupe de tout faire pour nous. Cependant, là où SinD utilise uniquement Docker, Minikube nous permet d’utiliser plusieurs drivers, nous permettant ainsi de faire démarrer notre orchestrateur dans une machine virtuelle KVM, VirtualBox ou Hyperkit, mais aussi dans un simple conteneur.
Il ne tient qu'à vous de choisir le driver qui vous convient le mieux. Ici, je vais utiliser Docker. Et nous allons le voir, la commande créant le cluster nous permet très simplement de choisir notre driver.
Nous avons tout d'abord besoin de télécharger le binaire minikube [3] :
C'est tout ce dont nous avons besoin pour démarrer notre cluster :
Voilà, en même pas 3 minutes (selon votre connexion internet), votre Kubernetes est prêt ! Pour s'en assurer, rien de plus simple : il nous suffit de lister les noeuds de notre cluster avec la commande kubectl :
Un avantage avec minikube c’est qu’il vient avec une liste d’addons à activer en fonction des besoins. Par exemple, il y a une storage classe, permettant ainsi de faire tourner une application nécessitant de la persistance de données. On peut aussi avoir un ingress controller, un runtime sécurisé, ou une registry... La liste est longue ! Nous pouvons voir tous les addons avec une simple commande :
Nous allons garder notre configuration par défaut pour le moment et nous concentrer sur le déploiement de notre application. Pour cela, une simple commande suffit :
Voyons maintenant si notre nombre de réplicas est conforme à ce que nous avons demandé :
Il y a bien 4 réplicas et notre application est bien démarrée. Maintenant, essayons d’y accéder. Dans notre fichier YAML, nous avons choisi de faire un service de type ClusterIP, c'est-à-dire que le service n’est accessible qu'à l'intérieur du cluster Kubernetes. Comment va-t-on y accéder ? C’est là que kubectl est magique, car il nous permet de faire un port-forward temporaire afin de pouvoir tester notre application :
Essayons d'accéder à notre application sur le port 8080 :
Parfait, ça marche !
3.2.2 Kubernetes en vrai
Minikube est un outil vraiment pratique pour se familiariser avec Kubernetes, ou même pour tester ses développements en local, mais les chances de le rencontrer dans un environnement de production sont plus que minces.
Comme pour Swarm, nous allons créer un cluster de deux nœuds : un nœud pour le control-plane et un pour le data-plane. Le premier ne fera tourner aucune application, seulement les composants de Kubernetes quant au second, il nous permettra de faire tourner notre application.
À petite échelle, Kubernetes se montre un peu plus gourmand en ressources que Swarm, aussi nous allons cette fois-ci déployer des machines de 2 vCPU, avec 2Go de RAM.
Depuis la version 1.25 de Kubernetes, Docker n’est plus supporté comme conteneur runtime, nous allons donc le substituer par containerd, ce qui est totalement transparent à l'utilisation, mais toujours bon à savoir :
L'outil que nous allons utiliser pour mettre en place notre cluster s'appelle Kubeadm, et tout comme Minikube, il fait lui aussi partie du projet Kubernetes. C’est un outil qui non seulement nous permet de déployer des clusters Kubernetes de production, mais qui nous permet aussi de gérer leurs mises à jour.
Avec kubeadm, tous les composants de Kubernetes sont conteneurisés, à l'exception bien sûr de kubelet, qui est le composant responsable de la gestion du cycle de vie des conteneurs. Nous allons donc l'installer en même temps que kubeadm sur les deux machines de notre cluster :
Swap
Il est vivement recommandé de supprimer le swap des machines sur lesquelles tourne Kubernetes, alors pensez bien à le désactiver dans le fstab et de lancer la commande : sudo swapoff -a.
Quelques modules kernel doivent aussi être activés pour que Kube fonctionne correctement :
Nous pouvons enfin démarrer et lancer l’initialisation de notre cluster Kubernetes en une seule commande que nous exécutons sur le noeud qui sera notre control-plane :
Vous pouvez copier le contenu du fichier /etc/kubernetes/admin.conf dans le fichier ~/.kube/config de votre machine locale, cela nous évitera de devoir piloter le cluster depuis la machine virtuelle.
Une fois l’initialisation terminée, kubeadm vous retourne une commande à exécuter sur le noeud worker, voici la commande en question :
Il vous suffit de la copier, puis de la coller dans la console de la seconde machine. Elle permet de déployer le nœud worker, et de le faire rejoindre le cluster.
Vérifions que nous avons accès à notre cluster avec la commande kubectl :
Comme on peut le voir, nos deux nœuds sont dans l'état NotReady, ce qui signifie qu'il nous reste encore une étape dans la configuration de notre cluster. En effet, à l'heure actuelle, notre cluster n'a pas de composant pour gérer le réseau, contrairement à Minikube. C'est tout simplement parce que nous sommes dans un déploiement de type « production », et Kubernetes n'a pas d'opinion sur le composant que vous souhaitez utiliser (c'est d'ailleurs une autre de ses forces). Libre à vous donc de choisir votre addon réseau dans l'écosystème de Kubernetes [4] en fonction de vos besoins, même si je vous conseille de vous intéresser à Cilium [5] pour vos environnements de production, il vous permettra notamment de profiter de toutes les capacités d’eBPF [6] ainsi que d’avoir une visibilité maximum de votre couche réseau. Ici, nous allons déployer Calico qui sera largement suffisant pour notre exemple :
Peu de temps après l'installation du réseau, vos noeuds devraient passer à l'état Ready :
Notre cluster est maintenant fonctionnel !
Nous allons une nouvelle fois déployer notre application pour s'assurer qu'elle se comporte exactement de la même manière que sur Minikube :
Si précédemment nous avions utilisé un port forwarding pour accéder à notre application, cette fois-ci nous allons plutôt opter pour une configuration plus adaptée à la production. Plusieurs méthodes s'offrent à nous pour publier notre application directement à l'extérieur du cluster :
- paramétrer le service en mode nodePort permet de créer un mapping avec un port de notre machine ;
- le type loadBalancer permet de faire la même chose, mais associe le port directement avec un load balancer tout en instanciant celui-ci auprès d’un cloud provider par exemple ;
- un ingress controller enfin permet de mutualiser le port externe et d’utiliser des règles de reverse proxy pour accéder à son service.
Pour notre découverte, nous allons utiliser Traefik. L'une des solutions les plus pratiques pour le déployer est d'utiliser Helm. Helm [7] est un package manager pour Kubernetes. Tout comme n'importe quel autre package manager que vous avez l'habitude d'utiliser sur votre distribution Linux, Helm est en mesure de déployer une application dans Kubernetes en gérant ses dépendances. Helm utilise des modèles de fichiers YAML avec lesquels vous n’interagissez pas directement. À la place, vous n'avez qu'à adapter un fichier de valeur fourni avec le chart pour personnaliser le déploiement en fonction de vos besoins. Et il va sans dire que Helm vient avec un immense catalogue d'applications prêtes à l'emploi, comme Traefik que nous allons utiliser, mais aussi Redis, MongoDB ou encore Elastic par exemple.
Première étape, installer le binaire Helm :
Vérifions que Helm fonctionne correctement :
Déployons Traefik : première étape, ajouter le dépôt Traefik à votre liste de dépôts (une opération qu'il est aussi fréquent de faire avec Linux) :
Passons au déploiement :
Vérifions si tout est bien en place dans le namespace traefik :
Parfait, Traefik est déployé avec un service de type node port, mais nous n'avons pas encore d'ingress pour tester l'accès à notre application depuis l'extérieur du cluster. On peut même voir le port mapping qui est appliqué au service Traefik, ici pour accéder au service sur un port 80, il faudra utiliser le port 31743 :
Ajoutons maintenant la définition de l'Ingress au fichier de déploiement de notre application :
Puis nous appliquons à nouveau le fichier YAML :
Testons enfin l'accès à notre application :
Tout fonctionne. Et si vous êtes arrivés au même résultat, bravo ! Sinon je vous encourage à revoir les différentes étapes, peut-être avez-vous manqué quelque chose, mais je ne doute pas qu'à terme, votre configuration sera elle aussi totalement fonctionnelle !
Conclusion
Dans cet article, nous avons pu découvrir deux orchestrateurs de conteneurs, mais aussi deux méthodes pour les déployer et ainsi commencer à mieux les maîtriser. Expérimenter sur son laptop est super simple avec des outils tels que SinD ou Minikube ; d'autres existent aussi, tel que Kind par exemple qui est aussi un équivalent de SinD pour déployer Kubernetes. Nous avons vu la création d’un cluster dans un environnement de type production avec l'aide de Kubeadm, mais ici encore d'autres outils existent comme Kops ou Kubespray (pour ne citer qu'eux). Vous pouvez déployer un cluster Kubernetes en quelques commandes, mais aussi le mettre à jour. Par contre, il vous faudra étudier plus en détail certaines options pour sécuriser vos clusters.
Tandis que Swarm est en perte de vitesse, Kubernetes a un avenir radieux devant lui. Il bénéficie d'un énorme écosystème que je vous invite à découvrir au travers du landscape de la CNCF [8], la fondation qui gère le projet Kubernetes.
Références
[1] L'histoire de Kubernetes, partie 1 : https://www.youtube.com/watch?v=318elIq37PE
et partie 2 : https://www.youtube.com/watch?v=318elIq37PE
[2] https://github.com/jlevesy/sind
[3] https://github.com/kubernetes/minikube
[6] https://ebpf.io/
[7] https://helm.sh/