Skip to content

Aller plus loin avec Docker Swarm

swarm-deep-banner

Cela fait un petit moment que je n’ai pas écrit d’article, on va donc reprendre en douceur et se monter un petit cluster Swarm de 3 noeuds sur des VMs DigitalOcean. Nous monterons ensuite un cluster GlusterFS afin de partager les volumes de nos containers entre nos VMs puis finalement nos déploierons un site WordPress exposé en HTTPS grâce à Traefik.

I- Provisionner les machines virtuelles

Dans mon exemple, je vais utiliser des VMs de DigitalOcean grâce à leur outil en ligne de commande « doctl« . Vous pouvez bien sûr utiliser n’importe quel cloud-provider qui fournit des VMs Docker ou Ubuntu/Debian sur lesquels vous installerez Docker 1.12.x. Si vous avez déjà vos machines virtuelles, installez Docker et rendez-vous au point suivant.

On commence donc par récupérer la dernière version de doctl sur leur page Github : https://github.com/digitalocean/doctl/releases

wget https://github.com/digitalocean/doctl/releases/download/v1.5.0/doctl-1.5.0-linux-amd64.tar.gz
tar -zxvf doctl-1.5.0-linux-amd64.tar.gz
mv doctl /usr/local/bin

Il faut également créer un token dans l’interface de DO (DigitalOcean) dans la section API > Token > Add new token :

api-digitalocean

On initialise ensuite l’outil doctl :

doctl auth init

Dès cet instant, on peut lancer la création des VMs, je vous suggère d’ajouter votre clé SSH dans l’interface de DO afin de pouvoir vous connecter directement aux VMs provisionnées.

Nous pouvons maintenant créer nos 3 machines, dans 3 zones géographique différentes (par exemple) :

doctl compute droplet create swarm-node01 --region ams2 --image docker-16-04 --size 2gb --ssh-keys <SSH-FINGERPRINT>
doctl compute droplet create swarm-node02 --region ams3 --image docker-16-04 --size 2gb --ssh-keys <SSH-FINGERPRINT>
doctl compute droplet create swarm-node03 --region fra1 --image docker-16-04 --size 2gb --ssh-keys <SSH-FINGERPRINT>

Au bout de maximum 1 minute, vous pourrez accéder à vous machines en SSH. Pour voir leurs IPs, on peut les lister ainsi :

droplet-list

Maintenant qu’on peut se connecter à nos machines, on va faire en sorte de partager un dossier entre nos 3 VMs afin de pouvoir partager les données persistantes de nos containers pour qu’il puissent changer de nodes sans problèmes. Pour cela, on utilise GlusterFS.

II- Monter le partage GlusterFS

gluster_loves_docker

Nous allons installer GlusterFS server et client sur nos nodes, reproduisez donc ces commandes sur chacun de vos nodes :

apt-get update; apt-get -y install glusterfs-server glusterfs-client
systemctl enable glusterfs-server.service

Pour simplifier les choses, on va éditer le fichier /etc/hosts sur nos 3 VMs afin d’y pointer les IPs de nos 3 nodes, comme ceci :

139.58.20.0 node01
139.58.20.80 node02
139.58.12.162 node03

On va maintenant initialiser notre cluster Gluster  comme ceci (depuis le node01) :

gluster peer node02
gluster peer node03

On vérifie ensuite qu’on a bien 2 peers reliés à notre node :

gluster> peer status
Number of Peers: 2

On peut désormais créer notre volume de données. Dans le cas d’un petit cluster, on va faire un volume pour nos quelques services, mais si vous faites un gros cluster avec plusieurs applications sensibles, il est suggéré de créer un volume par groupe de données à traiter.

On créer donc ce dossier sur chacun de nos nodes :

mkdir -p /data/swarm-data
mkdir -p /mnt/swarm

Ensuite, sur le node01, on va lancer la création du volume :

gluster volume create swarm-data replica 3 transport tcp node01:/data/swarm-data node02:/data/swarm-data node03:/data/swarm-data force

gluster volume set swarm-data auth.allow 127.0.0.1

gluster volume start swarm-data

Votre volume devrait maintenant être créé et lancé, on restreint l’accès à localhost, pour éviter que n’importe qui puisse monter vos fichier.   Pour que nos containers puissent maintenant accéder à notre cluster de données, on va monter sur chacun de nos nodes, notre volume dans le dossier /mnt/swarm :

mount.glusterfs localhost:/swarm-data /mnt/swarm/

Vous pouvez désormais vérifier que le dossier est bien monté avec un df -h.

gluster-swarm-df

III- Créer notre cluster Swarm

Maintenant que nos containers peuvent partager des données entre nodes du cluster, on va pouvoir initialiser notre cluster Swarm. Je part du principe que vos VMs possèdent déjà Docker 1.12.x (car j’utilise une image Docker-16-04 sur DO). Si ce n’est pas le cas, installez simplement la dernière version de Docker sur vos machines virtuelles et vous pourrez continuer.

Dans le cas d’un petit cluster, je préfère que tout mes nodes soient au même niveau (pas de master-worker). Je vais donc créer 3 nodes manager qui pourront tous les 3 devenir leader et effectuer des déploiements. Si vous prévoyez de monter un plus gros cluster avec des notions de hautes disponibilités, il vous faudra 3 nodes master et 2 nodes worker au minimum.

Sur notre node01, on va initialiser le cluster :

docker swarm init
docker swarm join-token manager

Docker va vous retourner une commande permettant aux autres noeuds de rejoindre le cluster, lancer là sur vos deux autres nodes :

 docker swarm join \
 --token SWMTKN-1-1g7g96igr9gregerh0fsemdstb40nroluprv71i8tl72ds8u5haohy-6wn9imksl9t4ldlq9s2z5eh6y \
 139.58.20.0:2377

On peut ensuite vérifier que notre cluster possède bien 3 nodes :

node-list-swarm

Et voici, vous avez désormais un cluster Swarm opérationnel et prêt à recevoir vos containers.

IV – Accéder à nos services

Un des soucis majeur dans l’orchestration de containers et la problématique d’accès à nos services. Swarm propose par exemple d’exposer des services sur des ports spécifiés (élevé sur TCP par exemple). Il est cependant bien plus pratique d’utiliser un reverse-proxy qui va servir nos services en fonction d’un path défini ou d’un domaine précis permettant ainsi de servir des sites en HTTPS par exemple.

traefik-logo

Dans notre cas, nous allons utiliser Traefik, un reverse-proxy orienté micro-services qui supporte depuis peu le Swarm mode de Docker 1.12.x. Il va donc proxifier nos services déployés dans Swarm et permet même de générer automatique des certificats TLS via Let’s Encrypt (bien pratique).

Pour permettre de faire des tests efficaces, je vous conseille, au niveau DNS, de faire pointer par exemple *.swarm.example.com vers vos 3 nodes Swarm. Cela permet de faire du round-robin DNS et ainsi de  load-balancer les requêtes entre nos 3 VMs.

On peut désormais déployer Traefik  dans notre cluster et stocker sa configuration et les certificats dans notre cluster GlusterFS. Pour commencer, on va créer le dossier pour nos certificats et notre fichier de configuration :

mkdir -p /mnt/swarm/traefik/certs
vim /mnt/swarm/traefik/traefik.toml
defaultEntryPoints = ["http", "https"]

[entryPoints]
 [entryPoints.http]
 address = ":80"
 [entryPoints.https]
 address = ":443"
 [entryPoints.https.tls]

[acme]
email = "[email protected]"
storageFile = "/certs/acme.json"
entryPoint = "https"
onDemand = true


[[acme.domains]]
 main = "swarm.example.com"

[web]
address = ":8080"

Adaptez ce fichier selon vos besoins, changez l’adresse e-mail de contact et le domaine utilisé pour contacter notre cluster (acme.domains) qui servira à générer nos certificats.
Maintenant que nos fichiers sont prêt, on peut lancer la création de Traefik dans notre cluster Swarm. On commence par créer un réseau interne à Swarm (overlay) « traefik-net » puis on créer notre service :

docker network create --driver=overlay traefik-net

docker service create \
 --name traefik \
 --publish 80:80 --publish 443:443 --publish 8080:8080 \
 --mount type=bind,source=/var/run/docker.sock,target=/var/run/docker.sock \
 --mount type=bind,source=/mnt/swarm/traefik/traefik.toml,target=/etc/traefik/traefik.toml \
 --mount type=bind,source=/mnt/swarm/traefik/certs,target=/certs \
 --network traefik-net \
 --mode global \
 traefik:v1.1.0-rc1 \
 --docker \
 --docker.swarmmode \
 --docker.domain=swarm.example.com \
 --docker.watch \
 --logLevel=DEBUG \
 --web

Vous remarquerez les lignes « bind,source=/mnt/swarm… » qui permettent de linker nos fichiers dans GlusterFS à l’intérieur du container Traefik.  Il faut également veiller à remplacer swarm.example.com pour le domaine qui vous avez pointé vers votre cluster Swarm. Remarquez aussi le flag –mode global qui permet d’avoir une instance de notre service par node du cluster.

Avant de se lancer dans un déploiement plus complexe, on va vérifier que notre installation fonctionne bien, pour cela, un petit container de test par le créateur de Traefik fera l’affaire :

docker service create \
 --name whoami0 \
 --label traefik.port=80 \
 --network traefik-net \
 emilevauge/whoami

Une fois créé, Traefik devrait automatiquement diriger « whoami0.swarm.example.com » vers ce container. On va vérifier (depuis un de nos nodes ou depuis l’extérieur si vous avez mis un wildcard DNS comme conseillé) :

curl -H Host:whoami0.swarm.example.com node01

curl-whoami

Vous devriez voir l’ID du container comme dans la capture d’écran ci-dessus.

Ce qui est sympa, c’est qui si rajoute des containers dans notre service whoami0, ils seront automatiquement load-balancés. Faite le test :

docker service scale whoami0=3

V- Déployer et scaler nos services

Maintenant que l’on a un cluster avec partage de fichier et l’accès aux services routés par notre reverse-proxy, on va enfin pouvoir lancer le déploiement de notre premier service. Pour l’exemple, on va utiliser le cas d’un site WordPress décomposé en deux services, WordPress et MySQL.

docker-wordpress

On va commencer par préparer les dossiers qui vont recevoir les volumes de nos containers (pour qu’il soient persistants et puisse se recréer à volonté sans pertes de données) :

mkdir -p /mnt/swarm/wp1/db
mkdir -p /mnt/swarm/wp1/www

On commence donc par créer un network dédié à notre service « wordpress01 » :

docker network create --driver=overlay wordpress01

On peut désormais créer notre premier service, une base MySQL :

docker service create --name wordpress-db01 \
--replicas 1 \
--network wordpress01 \
-e MYSQL_ROOT_PASSWORD=pAssw0rd \
-e MYSQL_DATABASE=wordpress \
--mount type=bind,source=/mnt/swarm/wp1/db,target=/var/lib/mysql \
mysql:latest

On attends quelques secondes que notre base SQL démarre, puis on lance le déploiement de notre service WordPress :

docker service create --name wordpress01 \
--replicas 1 \
--network wordpress01 \
--network traefik-net \
--label traefik.port=80 \
--label traefik.frontend.rule=Host:example.com \
-e WORDPRESS_DB_HOST=wordpress-db01 \
-e WORDPRESS_DB_PASSWORD=pAssw0rd \
-e WORDPRESS_DB_USER=root \
--mount type=bind,source=/mnt/swarm/wp1/www,target=/var/www/html \
wordpress:latest

Vous pouvez constater que le domaine  que l’on souhaite pour notre site WordPress est mis en label lors de la création du service. Cela permet à Traefik d’exposer example.com plutôt que le classique wordpress01.swarm.example.com.  (assurez-vous bien sûr de pointer votre zone DNS avant de créer le service).

Il suffit ensuite de se rendre à l’url http://example.com pour lancer l’installation de WordPress. Vous pouvez également lancer une requête sur https://example.com afin de déclencher la création des certificats via Let’s Encrypt. Au bout de quelques secondes, vous accéderez à votre site en HTTPS :

https-example-swarm

wordpress-swarm

On a actuellement un container de base de données et un container applicatif (Apache+PHP). En cas de fort usage sur ce site WordPress nouvellement déployé, on va pouvoir réguler la charge en scallant notre container applicatif entre les nodes du cluster. Traefik fera office de load-balancer entre ses différents containers.

Cela se fait en une commande :

docker service scale wp01=5

On a désormais 5 containers applicatifs qui répondent aux requêtes dans notre cluster.

wordpress-swarm-scale

La base de données quand à elle ne peut être scallée car MySQL ne peut démarrer plusieurs instance sur le même dossier /var/lib/mysql. Si vous avez de forte charges en requêtes SQL, il faut s’orienter sur des solutions comme MariaDB Galera cluster par exemple, qui peut tout à fait être intégré dans votre cluster Swarm.

Pour conclure rapidement, je dirais que Swarm tout seul ne permet pas encore de faire tout ce qu’offre des orchestrateurs comme Kubernetes ou Mesos, cependant couplés à divers outils (GlusterFS, Traefik …) on peut arriver à quelque chose de viable pour gérer quelque service dans un cluster d’hôtes Docker.

Si vous avez des questions, n’hésitez pas, c’est fait pour ça !

Published inCloudDevOpsDockerSwarmTutorielWeb

15 Comments

  1. If you use UFW

    sudo ufw allow 24007/tcp
    sudo ufw allow 24008/tcp
    sudo ufw allow 49152/tcp # brick #1
    #sudo ufw allow 49153/tcp # brick #2

  2. Bonjour, juste pour info sur ma Debian 8 la commande gluster peer node02 ne marche pas :

    # gluster peer node02
    unrecognized word: node02 (position 1)

    Il faut faire ceci :
    # gluster peer probe node02
    peer probe: success.

    Je continue la mise en place

    • valentin valentin

      Merci pour ton commentaire, je modifie.
      N’hésite pas si autre chose ne va pas dans le tuto. 🙂

  3. Alexandre Alexandre

    Ce post tombe à pic. On vient de me montrer rapidement traefik que je ne connaissais pas, et je voulais tester swarm + gluster sur des VC1S chez Scaleway/Online (sur ubuntu 16.04 également). Là, y’a tout dedans, je vais tester tout ça ^^
    Une question : ça ne pose pas de soucis à traefik d’être déployé sur tous les nodes du cluster swarm comme ici ? J’ai cru comprendre qu’il lui fallait un cluster KV (type etcd) dans ce cas (en tout cas c’est ce que dit sa doc :))
    Et pour faire la fine bouche : il est indiqué que ça manage Let’s encrypt mais c’est pas démontré 😛
    En tout cas, merci pour ce bel article !

    • valentin valentin

      Salut Alexandre, désolé j’ai pas était notifié de ton commentaire..
      Pour ma part le fait d’utiliser le stockage des certs en json pour Traefik ne pose pas de problème avec une instance par hôte.
      Pour Let’s Encrypt, relit bien, les certificats sont générés automatiquement lors de la première requêtes https. 😉
      N’hésite pas si tu as d’autres questions ! 🙂
      A bientôt.

  4. Pascal Andy Pascal Andy

    Non, ça roule global 🙂

    > a ne pose pas de soucis à traefik d’être déployé sur tous les nodes du cluster swarm comme ici ?

  5. Pascal Andy Pascal Andy

    Ce type de deploiment, c’était avant Swarm 1.12. Maintenant ce n’est plus nécessaire 🙂

    > J’ai cru comprendre qu’il lui fallait un cluster KV (type etcd) dans ce cas (en tout cas c’est ce que dit sa doc :))

    • Alexandre Alexandre

      Farpait ! 😀 Merci pour cette précision !

  6. Bonjour,

    Comment tu gères la redirection du http vers https ? Je cherche à le définir au niveau d’un frontend car tous les sites hébergés sur mon serveur ne sont pas en https. Je ne peux donc pas le gérer globalement.

    Si tu as trouvé la bonne syntaxe au niveau des labels à passer à docker, cela m’intéresse !

    • valentin valentin

      Bonjour Nicolas,
      Après quelques recherches, on dirait que le fait de rewrite HTTP vers HTTPS avec un Label à la création d’un service n’est pas encore supporté.
      Faudrait peut-être ouvrir une Issue afin de faire remonter le besoin. Je le ferais à l’occasion.

      A bientôt.

  7. Flemzord Flemzord

    La solution semble bien, mais en cas de perte d’un des serveurs, tu te retrouve avec 1/3 eme de tes visiteurs qui arrive sur un serveur HS ?

    • Alexandre Alexandre

      Normalement non, le round-robin DNS est supporté par les navigateurs récents, et si une des IP ne réponds pas, le navigateur essaiera sur la suivante. Au pire, cela provoquera des latences à l’accès des ressources (dues au timeout des connexions vers le serveur HS)

    • valentin valentin

      Dans le cas de 3 nodes masters, Oui, mais par exemple si tu installes Keepalived sur les 3 nodes et pointe le DNS vers cette IP partagée, tu as un premier niveau de haute disponibilité.

Laisser un commentaire

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

Proudly hosted with Open-sources Softwares.