1. Livres & vidéos
  2. Docker
  3. Déploiement en cluster par une usine logicielle
Extrait - Docker Concepts fondamentaux et déploiement d'applications conçues en services (3e édition)
Extraits du livre
Docker Concepts fondamentaux et déploiement d'applications conçues en services (3e édition) Revenir à la page d'achat du livre

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é hôte de conteneurs.

Un autre but qui est fortement corrélé est de déployer un nombre variable d’instances de certains conteneurs, de façon à équilibrer au mieux la charge de ces conteneurs. Après tout, c’est une des raisons principales pour laquelle nous avions décomposé une application en microservices : pour pouvoir facilement jouer sur le nombre d’instances et les ressources allouées à...

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), il reste toujours présent dans le jeu. L’auteur initial de cet ouvrage, après avoir écrit à la fois sur Docker Swarm et Kubernetes et mis en production dans son métier de directeur technique plusieurs plateformes utilisant les deux technologies, reste convaincu qu’il y a de la place pour les deux orchestrateurs, Kubernetes étant trop complexe pour une grande majorité des déploiements applicatifs standards.

1. Gestion du cluster...

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 des auteurs, 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 et le même port 80 l’application cliente, mais aussi la GED - qui est également exposée à l’externe, comme vue plus haut - ainsi que les API.

b. Lancement

Traefik est disponible sous forme d’une image Docker, donc la première chose à faire est de rajouter une entrée de service qui pointe dessus dans le fichier docker-compose.yml :

  traefik: 
    image: traefik:2.8 
    ports: ...

Compléments sur la variabilisation

1. Utilité des variables

Toute application logicielle avec un minimum de complexité fonctionnelle est paramétrable, et il est important que Docker Compose s’adapte à ceci, en laissant paramétrer ce qui est possible, mais aussi en offrant une capacité de fonctionner de manière souple, sans forcer au paramétrage de tout ce qui est nécessaire et en séparant bien les différentes parties du paramétrage.

Certaines entrées sont par exemple obligatoires car systématiquement différentes d’un environnement à un autre. C’est le cas dans notre application exemple du domaine de déploiement, car le lecteur ne peut pas utiliser celui réservé par les auteurs. C’est aussi le cas de la gestion des certificats de sécurité, car ils sont périssables et doivent de toute façon être uniques pour réaliser leur rôle de sécurité, même s’il avait été possible de fournir des fichiers exemples.

D’autres entrées doivent être faciles à paramétrer si l’utilisateur souhaite les modifier, tout en gardant des valeurs par défaut qui font sens et, si possible, soient les plus sécurisées possible. C’est le cas des noms des bases de données, par exemple.

Pour ce qui est des paramètres confidentiels, comme les mots de passe, il s’agit de variables à traiter complètement à part, comme cela a été vu plus haut avec la gestion des secrets.

Enfin, certaines variables sont tellement rarement modifiées qu’on peut se permettre de les intégrer comme des arguments de compilation des images Docker.

2. Mise en œuvre dans Docker

Nous ne reviendrons pas sur le mécanisme de gestion des secrets, qui a déjà été montré. Par contre, la gestion des variables est assez sophistiquée et mérite qu’on s’y attarde. 

Dans sa version la plus simple, la variabilisation du comportement d’un conteneur est réalisée en utilisant l’option -e dans la commande docker run. Par exemple :

docker run -it -e HEARTBEATSTEP=2 repetiteur:0.1 

En montant un premier cran de structuration, le groupe environment: dans...

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, les auteurs se permettent de renvoyer aux deux livres sur le sujet aux Éditions ENI. Le premier, Kubernetes - Mise en œuvre d’un cluster et déploiement de microservices, portant plus sur les concepts et destiné aux débutants, co-écrit par un des auteurs du présent ouvrage ; et le deuxième, Kubernetes - Gérez la plateforme de déploiement de vos applications conteneurisées (2e édition), couvrant de manière plus large toutes les fonctionnalités de Kubernetes mais s’adressant à des lecteurs désirant approfondir leur connaissance de la plateforme....

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 application dans ce mode de fonctionnement ; un espace de nommage dédié sera mis en place et les services seront mis en œuvre grâce à des fichiers YAML descriptifs de leur mode de fonctionnement, et formatés tels que Kubernetes l’attend.

De façon à simuler une situation réaliste, c’est le registre privé d’images Docker créé un peu plus haut qui sera utilisé pour récupérer...

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.

3. Lancement du conteneur

Le démarrage du conteneur dans...