TP8 : Docker Swarm & High availability

Introduction

Nous avons maintenant un environnement complet et sécurisé, il est à présent temps de le rendre plus robuste aux pannes. Certains ont peut-être mis en place un serveur DNS secondaire afin de ne pas entraver le fonctionnement du DNS si le serveur primaire venait à être inaccessible. Aujourd’hui, nous allons appliquer le même principe de redondance au service Web.

Pour simplifier, dans le cadre de ce TP, nous n’allons pas toucher à votre infrastructure existante et nous allons donc déployer un serveur web indépendant sur un autre port (le 8080) afin de ne pas perturber votre infrastructure existante. Une fois que vous aurez compris les techniques illustrées dans le TP, vous pourrez les transférer sur votre infrastructure principale.

Nous allons utiliser Docker Swarm : c’est un outil d’orchestration de conteneurs qui facilite la gestion et la mise à l’échelle de l’infrastructure Docker existante. Il permet une haute disponibilité en utilisant un groupe (cluster) d’hôtes Docker fonctionnant en mode Swarm. Certains de ces hosts (‘node’) vont agir en tant que ‘manager’ (pour gérer le Swarm/cluster) et d’autres vont uniquement agir en tant que ‘workers’. Cette configuration assure une résilience accrue et la possibilité d’appliquer des mises à jour incrémentielles sans temps d’arrêt, ce qui est essentiel pour les environnements de production.

A la fin de ce TP, vous devez être capable de :

  • Déployer une image Docker sur dockerHub
  • Initialiser un Docker Swarm
  • Exécuter et mettre à jour un service (ex : votre serveur web) sur votre cluster

Prérequis pour la réalisation du TP

Avant de pouvoir réaliser ce TP, assurez-vous d’avoir :

  • sécurisé votre VPS, notamment par la mise en place de l’authentification par clé SSH (TP3)
  • mis en place votre zone DNS, notamment via la délégation. (TP4)
  • avoir idéalement 3 VPS à votre disposition

Éléments clés de Docker Swarm:

Elément Description
Host Un ordinateur individuel exécutant Docker.
Node Un host qui participe à un Docker Swarm. Un node peut être un manager ou un worker.
Service Une application ou un ensemble d’applications conteneurisées déployées sur un Docker Swarm.
Manager Un node responsable de la gestion de l’essaim, y compris l’ajout et la suppression de nodes, la planification des tâches et la gestion des services.
Worker Un node qui exécute les tâches des services.
Task Une instance d’un conteneur exécuté sur un node.

Environnement de travail et organisation

Chacun de vos VPS sera un node et pourra être du type manager ou worker. Il n’est pas toujours conseillé d’avoir trop de manager car cela augmente la charge. Cependant, pour atteindre un maximum de haute disponibilité, nous devons avoir un minimum de 3 manager. Si vous n’avez que 2 VPS à votre disposition, le TP reste faisable mais notez que votre solution sera moins robuste (pour les curieux, c’est lié au concept de quorum).

Afin de vous faciliter la vie dans la gestion de vos machines, il est judicieux de modifier le nom d’hôte de vos VPS pour un nom plus lisible. Vous pouvez effectuer cette modification à l’aide de la commande suivante :

sudo hostnamectl set-hostname <votre hostname>

Et si vous voulez ne plus avoir de warnings liés au hostname (exemple, lorsque vous tapez sudo), vous devrez aussi modifier le fichier /etc/hosts.

1. Publier une image Docker sur dockerHub

Rappelez-vous, vous avez déjà utilisé la plateforme Docker Hub pour aller chercher toutes les images que vous avez utilisé. Aujourd’hui, nous allons l’utiliser pour y stocker notre image afin que celle-ci soit accessible de n’importe où.

Vous devez donc vous créer un compte sur Docker Hub et bien garder votre user/password, nous en aurons bientôt besoin.

1.1. Construire votre image docker

Jusqu’ici, on a beaucoup utilisé les bind mounts pour pouvoir facilement modifier des fichiers de configurations sans devoir re-builder son image. Ici, nous allons plutôt construire une image avec toutes les configurations ‘incluses’, correspondant plus à une image de “production”.

Lors de prochains TP, on portera notre configuration actuelle sur Docker Swarm, mais pour ce TP, nous partirons sur un exercice indépendant (libre à vous d’adapter), à titre d’exemple, vous pouvez prendre ce dockerfile:

FROM nginx:1.25.4

COPY ./index.html /usr/share/nginx/html/

Notez qu’on n’a pas modifié la configuration de Nginx car sa configuration par défaut nous suffira. Nous nous contenterons d’une simple page d’index, à personnaliser à votre goût.

Pour builder l’image, nous vous conseillons de bien inclure votre nom d’utilisateur Docker Hub dans le nom de l’image : cela vous facilitera la vie pour la suite. La commande est rappelée ci-dessous.

docker build -t votre_user_sur_docker_hub/image_name:version .

Construisez une image d’un serveur Web affichant une page web personnalisé. Vérifiez qu’elle fonctionne.

1.2. Publication de votre Image Docker

Pour publier une image sur le Docker Hub, il faut d’abord se connecter avec la commande docker login. Ensuite, effectuez un docker pushen indiquant bien le nom complet de l’image (votre_user_sur_docker_hub/image_name:version)

Publiez l’image de votre serveur web sur le Docker Hub. Testez ensuite qu’elle est accessible en vous connectant sur l’interface Web DockerHub, puis en essayant de l’exécuter depuis un autre VPS (conseil : utilisez le port 8080 du VPS)

2. Mise en place de votre Swarm

Ce chapitre est fortement inspiré du tuto officiel, nous vous invitons à vous y référez si quelque chose ici semble incomplet.

2.1. Initialisation

Pour initialiser un Swarm, il suffit de taper, dans votre premier VPS:

docker swarm init

Faites bien attention à l’output de cette commande ; vous y trouverez la commande à taper sur vos autres VPS pour qu’ils puissent rejoindre le cluster. Cette commande sera du type :

docker swarm join <token>

Vous pouvez rajouter également rajouter des nodes qui seraient derrière un NAT, tel que votre ordinateur. Cependant, il est possible que les restrictions EPHEC ne vous le permettent pas de le faire lors du TP.

Pour voir si votre docker host fait bien partie d’un Docker Swarm, vous pouvez taper ceci:

docker info (et regardez dans la section 'swarm')

2.2. Gestion des Node

Vous avez donc des nodes ‘manager’ et des nodes ‘worker’. Seuls les nodes ‘manager’ gèrent le Swarm, il est impératif d’être sur un node ‘manager’ pour configurer des choses concernant le swarm.

Vous pouvez taper docker node ls pour lister les nodes. docker node promote ou docker node demote pour changer le type d’un node. Note: si vous avez rajouté votre propre ordi au cluster, évitez de le promouvoir (ou de le laisser promu à la fin du TP), ca pourrait vous jouer des tours (car les nodes ‘manager’ sont crutiaux pour le fonctionnement du cluster et s’il en manque trop, le cluster ne sais plus quoi faire).

Prenez un peu le temps de comprendre l’output de docker node ls.

  • Comment changer le type d’un node?
  • Quelles commandes docker node sont disponibles, et lesquelles pourraient vous être utiles ?

2.3. Docker Service

Un Service Swarm est une abstraction qui regroupe un ou plusieurs conteneurs identiques, appelés tâches, qui peuvent tourner sur un même node ou plusieurs.

Pour créer (ou modifier) un service, vous allez utiliser docker service, par exemple, pour créer un service appelé ‘web’ et répliqué 2 fois:

docker service create --name web -p 8080:80 --replicas 2 votre_user/votre_image:version

Sur quels nodes vont être exécuté ce service ? Explorer un peu cette question en utilisant les commandes suivante:

docker service ls docker service --pretty inspect <votre_service> docker ps # sur les différents VPS

Notez qu’on a publié un port, mais sur quel VPS ? Tous les VPS du cluster ou seulement sur les VPS qui font tourner ce Nginx ?

Pour modifier des paramètres de votre service, vous pouvez évidemment le supprimer (docker service rm votre_service) et le recréer avec les nouveaux paramètres (un réplicas de plus, une nouvelle image, …). Ca marchera mais ce n’est pas très efficace et surtout ca implique de devoir stopper votre service, de le rendre indisponible le temps du redémarage… Et ca, c’est exactement ce qu’on cherche à éviter !

Heureusement Docker Swarm à une solution pour ca: docker service update qui va vous permettre de mettre à jour un service en cours d’execution, par exemple :

 docker service scale <votre_service>=3 pour que votre_service passe à 3 replica ou

 docker service update --image=<votre_nouvelle_image> <votre_service>

pour mettre à jour votre image.

Par défaut, ces mises à jour auront lieu une à la fois et s’arrêtera si l’une des mises à jour ne s’est pas bien passé. Il y a moyen de configurer tout ça, comme par exemple de mettre en place des ‘checks’ qui permettront de s’assurer qu’une mise à jour s’est bien passée avant de passer à la suivante. Mais nous ne verrons pas cela dans le cadre de ce TP (il s’agit des ‘healthcheck’ et paramètres de ‘rolling update’ pour ceux/celles qui seraient intéressé·es).

Afin de manipuler tout ca, vous pouvez couper Docker sur votre VPS (plus pratique que d’éteindre le VPS ;) afin de voir comment votre service réagit. Pour couper Docker, il suffit de taper sudo systemctl stop docker (remplacez ‘stop’ par ‘start’ ou ‘status’ pour le redémarrer ou voir son status)

Prenez le temps de vous approprier cela. Explorez docker service ainsi que les options qu’il propose (superficiellement car c’est très large). Essayez de “re-scaler” un service ou le mettre à jour.

Que se passe-t’il si vous stoppez un node ? Et si vous aviez ‘scalé’ votre service à un seul replica et que vous stoppiez le node sur lequel il tourne ?

2.4. Résumé des commandes

docker swarm pour créer et rejoindre le cluster

docker node pour gérer les nœuds constituant le cluster

docker service pour gérer les services tournant sur votre cluster

3. DNS Round robin

Vous avez pu vous rendre compte de la résilience offerte par cette configuration si l’une des machines venait à disparaitre : le loadbalancer intégré à Docker Swarm permet d’accéder à votre service depuis n’importe quel noeud Docker du swarm, même si ce noeud n’exécute pas actuellement de container lié à ce service.

Grâce à cela, on peut définir n’importe quel noeud comme étant le point d’entrée du service, qu’il le fasse tourner ou non. Oui, mais … que ce passe t’il si ce point d’entrée est justement celui qui n’est plus accessible (ou trop surchargé pour répondre) ?

Tout d’abord, dans un cas réel, on s’arrangerait pour que ce “point d’entrée” soit le plus fiable possible, notamment en configurant ce node pour qu’aucune tâche ne lui soit attribuée. C’est d’ailleurs la configuration préconisée par Docker pour tout les nodes “manager” (afin qu’ils ne soient pas surchargés et qu’ils puissent remplir leur rôles de gestionnaire du Swarm).

Mais il existe d’autre méthodes. Parmi elles, une méthode assez simple (mais comportant des limitations) est le dns round-robin. Cela consiste simplement a avoir plusieurs RR de type A pour votre FQDN (avec des IP différente). Par exemple, on peut renseigner dans le DNS 3 IPs pour le service NTP ci-dessous :

fr.pool.ntp.org.        150     IN      A       88.191.228.144
fr.pool.ntp.org.        150     IN      A       193.55.167.2
fr.pool.ntp.org.        150     IN      A       5.135.152.40

Mettez en place un round-robin sur votre DNS.

4. Pour aller plus loin:

Cette partie revient sur des éléments qui, pour plus de facilité, ont été omis. Cette partie n’est pas obligatoire, mais sera certainement liée à des bonus.

4.1. Sécurité

Notre Docker swarm étant établi entre des VPS publics, accessibles de tous, il convient donc de sécuriser les échanges entre les nodes en utilisant --opt encrypted (cf documentation officielle).

4.2. Configuration (et secrets)

On a fait le choix, pour simplifier le TP, de construire une image avec nos configurations (ici la page html), mais il peut être intéressant de garder l’image docker la plus générique possible et de customiser la configuration séparément… Un peu comme lorsqu’on utilisait un ‘bind mount’, sauf qu’ici, Docker Sarm à une solution pour ça. Il s’agit de docker config (ou docker secret qui fonctionnent un peu sur le même principe mais hash les données pour plus de sécurité).

Rendez-vous sur la documentation officielle (et sinon essayez docker config [cmd] --help) pour comprendre comment ça marche et comment gérer votre config de la bonne manière.

4.3 Woodytoys

Vous pouvez aussi commencer à déployer woodytoy sur docker swarm. Quelles sont les limitations ou les difficultés rencontrées ?