Déploiement en cluster par une usine logicielle
Le besoin d’orchestration
1. Objectif
Le chapitre précédent montrait un déploiement de l’application exemple par Docker et Docker Compose dans le contexte d’une machine local unique. Lorsque nous parlions déploiement, le registre permettait de mettre à disposition de machines extérieures des images créées sur une machine donnée, mais il n’empêche que ces machines extérieures, après s’être connectées au registre pour récupérer l’image, instanciaient les conteneurs correspondants de manière locale. Le fonctionnement restait donc unitaire, et finalement pas très différent d’un déploiement sur la machine ayant servi à créer l’image. Cette approche souffre bien sûr d’une limite sur la taille possible pour une application, limite à laquelle le présent chapitre va remédier en montrant le même déploiement, mais sur un cluster d’hôtes Docker, permettant de dépasser le carcan de la machine unique. Nous utiliserons pour cela la technologie Swarm, qui est intégrée dans Docker.
Cette approche nous forcera au passage à opérer une saine séparation entre la machine pilotant le déploiement des applications et la ou les machines qui vont porter effectivement les conteneurs. Le but principal de ce découpage est de pouvoir cibler facilement plusieurs machines pour la seconde partie, et ainsi de pouvoir facilement étendre sa capacité de déploiement de conteneurs, en ajoutant des ressources matérielles de manière transparente par rapport au déploiement. Bref, le but du clustering sur les conteneurs est de permettre le déploiement de conteneurs sur un ensemble de machines qui se comportent comme une seule et énorme entité...
L’approche Docker Swarm
Toutes ces explications théoriques étant posées, nous pouvons passer à la mise en œuvre avec Swarm, ou pour être plus précis le mode Swarm de Docker. Ce dernier est un système de clustering des démons et d’orchestration des conteneurs implémenté nativement dans le produit depuis sa version 1.12. Auparavant, un logiciel externe existait sous le nom de Docker Swarm, d’où le nom légèrement différent aujourd’hui de mode Swarm pour Docker. Dans la suite, nous utiliserons simplement l’expression Swarm.
Comme expliqué plus haut, l’avantage de Swarm sur d’autres orchestrateurs est qu’il est très simple à prendre en main par une personne habituée à utiliser le client Docker, l’outil réutilisant au mieux les API de Docker et supportant l’utilisation de Docker Compose, ce qui permet de reprendre une grande partie des habitudes de travail développées dans les chapitres précédents.
Ce support de la description d’une application dans la grammaire Docker Compose n’est plus réellement un avantage, dans la mesure où Kubernetes est désormais le logiciel référence et sa grammaire YAML de description d’artefacts celle qui est - par conséquent - la plus utilisée.
Un peu moins de deux ans après la première édition du présent ouvrage, force est de constater que, malgré la suprématie technique de Kubernetes, Swarm est bel et bien toujours présent sur le marché. Docker a su rajouter quelques fonctionnalités d’interconnexion et, en s’intégrant dans certaines fonctionnalités de Kubernetes ou en en reprenant d’autres dans son écosystème (comme les contextes)...
Outils avancés d’exposition
1. Traefik
a. Utilité
Dans les éditions précédentes de cet ouvrage, l’application exemple était plus fortement découpée, dans une approche tendant vers des microservices. Même l’interface graphique était fournie par plusieurs services séparés, même si on ne pouvait pas parler de micro-frontends.
Cette approche a été laissée de côté pour une architecture plus moderne, et surtout sur laquelle la part belle est faite surtout au partage strict des responsabilités fonctionnelles, plutôt qu’à une approche très granulaire. Cette évolution est celle liée à l’expérience de l’auteur, mais aussi à la veille technologique opérée sur les architectures de référence.
Sur l’ancienne application, plusieurs services étant exposés sur Internet, il était assez vite visible que rajouter des ports n’était pas une approche soutenable à long terme, et Traefik était donc introduit comme un moyen simple et efficace :
-
d’assurer une surcouche d’exposition basée sur des chemins d’URL ;
-
de gérer la dynamicité des conteneurs (qui peuvent passer à l’échelle, changer de nœud sur un cluster, être relancés fréquemment) là où des approches de proxy plus traditionnels auraient nécessité d’être sans arrêt rechargés, voire même redémarrés ;
-
de porter des fonctionnalités de reverse-proxy, de passerelle SSL, etc.
Sur l’application exemple, le cas de figure qui pourrait éventuellement justifier l’utilisation de Traefik serait la volonté d’exposer sous le même domaine...
Introduction à Kubernetes
1. Positionnement
En tout début de ce chapitre, Kubernetes a été présenté comme l’orchestrateur numéro un, regroupant toutes les fonctionnalités nécessaires, disponible en open source et dont les qualités ont permis l’adoption par une très large majorité des acteurs. Bien qu’il soit surdimensionné pour des déploiements de taille limitée, dès qu’il s’agit de mettre en œuvre des plateformes d’une certaine complexité, Kubernetes est sans aucun doute la voie à suivre à ce jour. L’avance technologique dont il va bénéficier de manière durable, vu que la concurrence a quasiment abandonné ce terrain, fait d’ailleurs que cette situation a de bonnes chances de perdurer pendant au moins quelques années.
Sans entrer dans les détails de la mise en œuvre, il est indispensable dans un livre sur Docker de décrire comment déployer une application microservices en conteneur sur un orchestrateur Kubernetes. Nous n’aborderons pas en détail l’installation ni le maintien en condition opérationnelle d’un cluster Kubernetes, mais uniquement les liens avec Docker, donc toutes les fonctionnalités correspondant à la définition d’une solution logicielle déployée par conteneurs sur le cluster. Pour ce faire, le plus simple sera de déployer l’exemple d’application en microservices créée dans le chapitre précédent sur une plateforme Kubernetes installée rapidement auparavant.
Pour plus de détails sur Kubernetes, l’auteur se permet de renvoyer aux deux livres sur le sujet aux Éditions ENI. Le premier Kubernetes - Mise en œuvre d’un cluster et déploiement...
Intégration et déploiement continus
1. Approche
Cette section porte la toute dernière grosse manipulation du présent ouvrage, et l’exercice a pour but de regrouper dans un seul environnement tout ce qui a été montré, avec une approche la plus industrielle possible.
Tout d’abord, il manquait jusqu’à maintenant une réelle usine d’intégration continue qui, à chaque commit dans le projet, réalisera toutes les commandes nécessaires pour la production des livrables de manière automatique. Pour cela, nous utiliserons Azure DevOps, tout en continuant à pointer sur les codes sources dans GitHub. Comme les builds automatiques ne sont désormais que dans la version payante de Docker Hub, autant prendre avantage des crédits Azure gratuits pour faire un projet sur Azure DevOps.
Même si le projet a été passé en public sur Azure DevOps, le dépôt de référence de l’application reste Github et les fichiers YAML descriptifs pour Kubernetes seront portés par ce dépôt, comme d’ailleurs les fichiers descriptifs dont Azure DevOps se servira pour ses ressources propres. La version Azure DevOps restera uniquement un projet portant les mécanismes de compilation et de déploiement, et tous les fichiers resteront dans GitHub, de façon à constituer un dépôt unique pour l’ensemble des fichiers nécessaires à l’application.
Pour aller au bout de l’automatisation d’une chaîne industrielle, le déploiement continu sera également mis en œuvre dans Azure DevOps, en ciblant l’environnement Azure Kubernetes Services qui a été préparé plus haut. Ceci permettra de montrer comment se passe le déploiement d’une réelle...
Azure Container Instances
1. Principe
À titre de curiosité, imaginons que le lecteur souhaite déployer une image Docker sans avoir ne serait-ce qu’à appeler un cluster de machines. Bref, obtenir un vrai "Container as a Service" dans lequel seule l’image serait spécifiée ainsi que les paramètres d’exposition, un système externe se chargeant de tout le reste.
Le déploiement prendrait alors juste le temps de créer l’image, et c’est la promesse portée par le service Azure Container Instances qui va être démontré ci-dessous.
2. Préparation d’une image
Pour faire fonctionner cet exemple, nous allons créer une image basée sur l’image officielle nginx et qui portera simplement en plus quelques fichiers statiques correspondant à un site web. Le site sera ainsi immutable. Le lecteur est normalement autonome désormais pour produire le fichier Dockerfile suivant :
FROM nginx:1.19.3
ADD ftpperso.free.fr/* /usr/share/nginx/html/
Le dossier pourrait par exemple avoir été créé par une simple commande wget -m ftp://user:motdepasse@ftpperso.free.fr aspirant le contenu complet d’un site web sur lequel l’utilisateur possède un accès FTP en lecture. À partir du moment où le contenu inclut un fichier index.html, c’est suffisant pour créer une image autonome :
docker build -t jpgouigoux/antuallarmor .
Une commande docker login plus loin, cette image est poussée sur le registre Docker Hub :
docker push jpgouigoux/antuallarmor
Et il est donc désormais possible de l’exposer de toutes les manières possibles que nous avons vues avec Docker, mais aussi avec ACI (Azure Container Instances) comme nous allons le montrer dans la prochaine section.