Stack Labs Blog moves to Dev.to | Le Blog Stack Labs déménage sur Dev.to 🚀

7 avril 2018 | Devops | Laurent Noireterre

Déployer des services DevOps avec Docker Swarm

Temps de lecture estimé : 7 minutes

S’il y a un outil plébiscité par les DevOps ces dernières années, c’est bien Docker, que ce soit pour maintenir un parc d’applications (Kafka, Spark, Microservices…) ou déployer ses propres services DevOps (GitLab, Ansible, Artifactory, …).

Le but de cet article n’est pas de lister les avantages de Docker ou même de présenter les outils et les pratiques autour de DevOps (de nombreux articles le font déjà sur internet), mais de montrer comment nous pouvons déployer et administrer simplement un ensemble d’outils et services DevOps avec Docker Swarm, et les bénéfices que cela apporte.

Pourquoi Docker Swarm ?

Les avantages d’utiliser un cluster de type Docker Swarm par rapport au déploiement simple de conteneurs sont multiples. Pour n’en citer que quelques-uns :

  • Administration : Cela nous permet d’administrer et deployer l’ensemble de nos services à partir d’un seul noeud (manager)

  • Scaling : Le scaling de nos services et la répartition de charge sont assurés en natif par Docker Swarm
  • Sécurité : Docker Swarm permet la création d’un réseau overlay chiffré pour la communication entre nos services au sein du cluster. Nous n’avons plus qu’a mettre en place un reverse proxy (par exemple Nginx) auquel nous ajouterons un certificat ssl (type Let’s Encrypt) pour les accès sécurisés depuis l’exterieur.

D’accord, mais pourquoi pas Kubernetes ?

Un maître mot: simplicité. Depuis sa version 1.12, Docker a grandement modifié et simplifié la création d’un cluster Swarm ainsi que le déploiement des services grâce aux Stack.

Kubernetes a certes plusieurs avantages tel que l’auto scaling par exemple ou une communauté plus active, mais les capacités et fonctionnalités offertes par Docker Swarm sont amplement suffisantes pour notre utilisation.

Par ailleurs, un cluster Kubernetes est réputé complexe à mettre en place et à maintenir, surtout sur une architecture “On Premise”.

Aperçu de notre architecture DevOps

Voici le type d’architecture que nous pouvons mettre en place :

Le cluster est composé d’un noeud manager (vm-devops-01) et x noeuds worker (vm-devops-02, vm-devops-03 et vm-devops-04 dans notre exemple), nous permettant ainsi de répartir nos outils sur plusieurs machines.

Notre serveur Nginx joue le role de reverse proxy pour servir l’ensemble des services. Des outils de monitoring peuvent être ajoutés (Prometheus, Grafana…) afin de surveiller le cluster et lever des alertes sur son état (service down, utilisation CPU, utilistation filesystem…)

Implémentation

Remarque : L’implémentation et les exemples ci-desssous sont donnés pour une architecture “On Premise”, mais peuvent être adaptés pour un déploiement sur une architecture Cloud.

Mise en place de l’infrastructure

Nous allons déployer notre cluster swarm sur un ensemble de VM que nous avons préalablement créé et sur lequel est installé un Docker Engine (version 1.12 minimum).

Remarque : si vous n’avez pas de VM à disposition, vous pouvez demander à docker-machine de vous en créer automatiquement grâce au driver virtualbox (cf. ci-après lors de la création des machines). De même si vous souhaitez créer votre cluster dans un environnement cloud, vous pouvez alors passer directement au chapitre suivant

Docker Swarm a besoin d’un accès root à chaque VM du cluster. Nous allons donc créer un user d’administration des services sur chacune des VM et l’ajouter au groupe docker :

sudo adduser devopsadm
sudo usermod -aG docker devopsadm

Il nous faut aussi le rendre sudoer (sans mot de passe) sur chacune de nos machines. Pour cela on édite le fichier /etc/sudoers et on ajoute la ligne suivante :

devopsadm ALL=(ALL) NOPASSWD: ALL

Notre user est créé et configuré. Il nous faut maintenant générer une clé ssh sur notre noeud maître et la copier sur chacune des VM du cluster. Pour cela, il suffit de se connecter à la VM maître (vm-devops-01) avec le user devopsadm et générer la clé grâce à la commande suivante:

ssh-keygen

Important : laissez la passphrase à vide lors de la création de la clé

Une fois la clé ssh générée, nous allons copier sa partie publique sur chacune des VM du cluster (répétez la commande en remplaçant xxx par le nom de la VM)

ssh-copy-id -i ~/.ssh/id_rsa.pub devopsadm@vm-devops-xxx

Création des machines du cluster

Maintenant que l’infrastructure est en place nous allons nous intéresser au cluster Swarm lui-même.

Nous allons tout d’abord créer les machines composant le cluster en utilisant Docker Machine. Docker Machine est un outil permettant de provisionner et d’administrer des serveurs “dockerisés”, c’est-à-dire ayant un Docker Engine d’installé.

Nous nous connectons donc à notre VM maître (vm-devops-01) avec le user devopsadm et créons chaque machine grâce au driver generic (remplacez xxx et xx par l’adresse IP et le nom de la VM):

docker-machine create \
--engine-env 'DOCKER_OPTS="-H unix:///var/run/docker.sock"' \
--driver generic --generic-ip-address xxx.xxx.xxx.xxx --generic-ssh-key
~/.ssh/id_rsa --generic-ssh-user devopsadm vm-devops-xx

Remarque : le driver generic permet de créer une machine sur un serveur/VM existant. Si vous n’en disposez pas vous pouvez utiliser le driver virtualbox qui va créer localement les machines (voir la documentation Docker sur Virtualbox). De même, vous pouvez créer les machines directement dans le cloud (AWS, Google Cloud Platform, Microsoft Azure…) en utilisant les différents drivers supportés par Docker (voir les drivers disponibles)

Nous vérifions ensuite la création des machines:

docker-machine ls

Initialisation des noeuds du cluster

Nous allons tout d’abord créer le noeud maître. Pour cela connectons nous sur la VM vm-devops-01 avec le user devopsadm et positionnons le contexte Docker Machine sur celle-ci:

eval "$(docker-machine env vm-devops-01)"

Nous initialisons ensuite notre noeud et ainsi notre cluster :

docker swarm init \
--listen-addr $(docker-machine ip vm-devops-01) \
--advertise-addr $(docker-machine ip vm-devops-01)

Nous pouvons maintenant attacher chacun des workers au cluster. Récupérons tout d’abord le token d’identification du cluster :

token=$(docker swarm join-token -q worker)

Et pour chaque worker à ajouter (remplacer xx par le nom de la machine) :

eval "$(docker-machine env vsrv-devops-xx)"
docker swarm join --token $token $(docker-machine ip vm-devops-01):2377

Une petite vérification des noeuds créés s’impose :

eval "$(docker-machine env vm-devops-01)"
docker node ls

Voilà, notre cluster est prêt ! Si vous faites abstraction du “blabla explicatif”, vous remarquerez que nous avons créé notre cluster en quelques commandes seulement ! :)

Déploiement des services

Nous allons tout d’abord créer un réseau de type overlay auquel tous nos services seront rattachés, leur permettant ainsi de communiquer. Nous allons utiliser l’option encrypted afin de permettre à Docker de chiffrer automatiquement tous les échanges.

docker network create \
-d overlay \
--attachable \
--opt encrypted \
swarmnet

Nous pouvons maintenant déployer nos services. Pour cela nous utiliserons la fonctionnalité stack deploy de docker.

Avec Docker Swarm, nous ne lançons plus directement des conteneurs (docker run) mais créons des services (docker service create). La fonctionnalité stack nous permet de déployer un ensemble de services formant une application (pour faire une analogie, il s’agit du Docker Compose des conteneurs porté aux services Docker Swarm). Docker nous facilite d’ailleurs la tâche et nous permet d’utiliser directement un ficher docker-compose.yml (à quelques adaptations près).

Nous allons ici prendre l’exemple de Nginx pour illustrer un déploiement mais le principe est le même pour chacun de nos services DevOps.

Voici notre fichier docker-compose.yml:

version: '3'

services:

  nginx:
    image: nginx
    ports:
      - 80:80
      - 443:443
      - 2222:22
    volumes:
      - nginx-config:/etc/nginx/conf.d
      - nginx-sites:/etc/nginx/sites-enabled
    deploy:
      placement:
        constraints:
          - node.role == manager
    networks:
      - swarmnet

volumes:
  nginx-config:
  nginx-sites:

networks:
  swarmnet:
    external:
      name: swarmnet

Par rapport à un fichier Docker Compose, nous voyons apparaitre une section deploy. Celle-ci va nous permettre d’indiquer à Docker Swarm comment déployer notre service (réplication, placement, politique de redemarrage du service…). Se référer à la documentation Docker pour la liste exhaustive.

Pour notre exemple, nous restreindrons seulement le déploiement du service à un noeud maître grâce à l’instruction - node.role == manager

Voilà, nous pouvons alors simplement déployer et lancer notre stack grâce à la commande deploy :

docker stack deploy --compose-file docker-compose.yml reverseproxy

Un arrêt de la stack s’effectue grâce à la commande down :

docker stack down reverseproxy

Pour aller plus loin

Dans notre exemple, nos services sont fortement liés aux noeuds sur lesquels ils sont déployés à cause des volumes de données.

Pour y remédier, nous pouvons mettre en place des systémes de fichiers distribués (tel que NFS ou GlusterFS) pour permettre à nos services d’accéder à leur données quelque soit le noeud sur lesquels ils sont déployés (cela nous permettra aussi de les scaler).

De même sur une architecture cloud, nous pourrons utiliser des services de stockages en ligne type Amazon S3, Google Cloud Storage ou autre, grâce aux storage drivers.


Sources & Crédits Images :