Procédure d'ajout ou de mise à jour des services

Cette procédure vaut pour mettre un jour n'importe quel service, que ce soit un service interne ou un service externe (exemple : Traefik, Mattermost, Etherpad…).

La page est organisée est plusieurs sections.

  • La première est le canevas général applicables à tous les services. C'est ce canevas qui doit être suivi lors de tous les déploiements de nouveaux services ou lors des mises à jour.
  • La deuxième liste les cas particuliers, qui ajoutent des étapes au canevas. Ces étapes passées, il faut revenir au canevas.

Pour déployer une nouvelle version d'un service, après les tests, on se rend sur la machine de production qui fait tourner le service (pica01 ou pica02). Bien entendu, on ne fait pas une mise à jour n'importe comment, il faut s'assurer :

  • Que l'on a une backup récente de la potentielle base de données.
  • Que le service n'est pas trop utilisé. On ne fait pas un déploiement à 19H, la coupure va déranger tout le monde;
  • Que les autres bénévoles sont au courant de la mise à jour. Même si la coupure de service est courte, un⋅e sysadmin qui voit que le service est tombé va s'affoler pour rien :)

Principe général

Afin de mettre une jour un service, plusieurs étapes sont nécessaires.

Tout d'abord, il faut des images Docker : trois cas de figure se présentent alors :

  • Construction de l'image directement sur la machine. C'est la procédure classique pour les tests, fortement déconseillée en production.
  • Récupération de l'image déjà construite depuis un registre externe. Sauf cas particulier, et hors tests, déconseillé pour des raisons de sécurité (on ne maîtrise pas l'image).
  • Construction des images et push sur un registre privé appartenant à Picasoft. Ainsi, n'importe quelle machine de Picasoft pourra utiliser ces images.

La première section de cet article détaille un peu plus ces trois possibilités.

Il n'est pas nécessaire de stocker toutes les images sur le registre de Picasoft : en effet il est inutile de le surcharger avec des copies conformes à celles d'autres registry. Seules les images construites depuis un Dockerfile ont vocation à l'être.

L'avant dernière étape est le test de la nouvelle image, sur la machine de test.

La dernière étape est la mise en production. Il faut se rendre sur la machine dans laquelle se trouve le service en question, arrêter les conteneurs concernés et en lancer avec les nouvelles images.

Cas général

La première étape consiste à obtenir l'image que l'on souhaite déployer. Deux cas se présentent alors, comme évoqué.

Cas 1 : construction des images

Cas d'utilisation : on a nous même écrit un Dockerfile (stocké sur le dépôt des Dockerfiles maintenus par Picasoft) ou on récupère un Dockerfile déjà écrit par quelqu'un d'autre. C'est le cas des images Mattermost, que l'on construit nous même à partir du Dockerfile présent sur le dépôt officiel.

Exemple :

$ git clone <dépot où se trouve le Dockerfile>
$ cd <dossier où se trouve le Dockerfile>
$ docker build -t <nom à donner à l'image> .

Cas 2 : récupération d'une image existante

Cas d'utilisation : une image existe déjà, sur notre registre privé ou sur un registre public :

  • Cas A : on fait des tests, et dans ce cas on est autorisé à récupérer une image sur un registre public (qu'on ne maîtrise pas), par exemple le Hub officiel Docker par défaut.
  • Cas B : on a déjà construit et poussé une image sur notre registre privé, que l'on récupère sur la machine cible.

Pour télécharger ces images sur le serveur, la commande docker pull doit être utilisée :

# Cas A : on télécharge l'image depuis un registre extérieur. Exemple pour l'image officielle de WeKan :
$ docker pull quay.io/wekan/wekan:v1.07
# Cas B : on télécharge l'image depuis le registre de Picasoft. Exemple pour l'image Mattermost que l'on a construit nous-même à partir du Dockerfile officiel :
docker pull registry.picasoft.net/mattermost:5.11.0

Cette section n'est valable que pour les images que l'on souhaite pousser sur notre registre privé. Une image importée d'un registre public à des fins de tests n'a pas vocation à terminer sur notre registre privé, comme expliqué plus haut.

Il faut ensuite étiqueter les images, c'est-à-dire leur donner un nom et une étiquette. Le nom est unique, les étiquettes peuvent être multiples. Une bonne pratique est d'utiliser la version du service comme étiquette.

Par défaut, lorsqu'une image est construite, elle utilise l'étiquette latest, qui est à proscrire, pour des raisons détaillées ici.

Le nommage et l'étiquette des images utilisent la commande docker tag. Le nom de l'image finale est arbitraire et devrait rester court et simple.

# Le nom de l'image locale est accessible avec la commande "docker images".
$ docker tag <image locale> registry.picasoft.net/<nom souhaité pour le registre>:<étiquette (version)>
# Exemple, si docker images m'informe qu'une image se nomme mattermost_docker_web :
$ docker tag mattermost_docker_web registry.picasoft.net/mattermost-web:5.11.0

Les nouveaux alias des images doivent à présent être visibles via un docker images. En reprenant l'exemple ci-dessus, on aura à la fois l'image locale et l'étiquette que l'on vient de créer.

# Les images ne sont pas dupliquées : ce ne sont que des alias.
$ docker images
REPOSITORY                                 TAG         CREATED             SIZE
mattermost_docker_web                      latest      2 days ago          700MB
registry.picasoft.net/mattermost-web       5.11.0      2 days ago          700MB

Il faut pousser l'image sur le registre privé de Picasoft avant le déploiement, car les images sont régulièrement nettoyées sur les machines, tandis que les images du registre sont plus pérennes. Ceci se fait grâce à la commande docker push.

# En reprenant l'exemple donné plus haut :
docker push registry.picasoft.net/mattermost-web:5.11.0

Il est possible que vous obteniez une erreur d'autorisation. En effet, le registre privé de Picasoft nécessite de s'identifier, ce qui est possible avec la commande docker login. La gestion des identifiants est détaillée ici. Si vous n'y avez pas accès, rapprochez vous de la team technique sur Mattermost.

La dernière étape est celle du déploiement, à effectuer d'abord sur l'environnement de test, puis sur l'environnement de production. La procédure est similaire pour les deux environnements.

Maintenant que l'image est accessible depuis toutes les machines, on commence par mettre à jour le docker-compose.yml situé dans /DATA/docker :

  • Remplacement du nom et/ou du tag de l'ancienne image
  • Ajout de nouveaux paramètres de configuration

Docker Compose est un système d'orchestration et de gestion des services. Si vous n'êtes pas familiers avec, jetez un œil ici.

Attention !! On utilise uniquement les images ayant pour tag le numéro d'une version.

Pour la suite des commandes, on utilise le nom des services du docker-compose.yml, et pas le nom des images ni des conteneurs.

Prenons l'exemple suivant :

# 'app' est le nom du service, 'registry.picasoft.net/pica_app:5.9.0' est le nom de l'image.
app:
    image: registry.picasoft.net/pica_app:5.9.0
    container_name: app_container

Supposons que l'on vienne de passer app en version 5.10.0, et qu'on l'a poussée sur le registre privé de Picasoft avec le tag 5.10.0. La section du docker-compose devient :

app:
    image: registry.picasoft.net/pica_app:5.10.0
    container_name: app_container

Note : si l'on est sur la machine de test et que l'image n'est pas sur le registre privé, on ajoutera simplement un service avec le nom de l'image sur le registre public.

Si l'on ajoute un nouveau service, on peut passer cette étape.

Les conteneurs à mettre à jour doivent tout d'abord être stoppés (docker-compose stop app) avant d'être effacés (docker-compose rm app).

cd /DATA/docker/ && docker-compose stop -t 60 app && docker-compose rm app

Il est important de stopper les conteneurs avant de les effacer pour minimiser les risque de corruption. L'option -t 60 indique un timeout de 60 secondes, pour laisser le temps aux conteneurs de faire les sauvegardes nécessaires dans les éventuels volumes.

En particulier, dans le cas de conteneurs qui gèrent une base de données, il est indispensable de laisser un délai de 60 secondes avant l'arrêt du conteneur. Dans le cas d'un couple application/base de données, il est également préférable de ne lancer le conteneur applicatif qu'après avoir laissé un peu de temps à la base de données de se lancer.

Enfin, il faut créer les nouveaux conteneurs avec docker-compose up -d app :

docker-compose up -d app

On s'assurera que les conteneurs sont bien déployés :

  1. Si le docker-compose.yml précise un healthcheck, on pourra s'assurer que le conteneur tourne bien en regardant son statut avec la commande docker container ls. Si le conteneur n'est pas listé, alors il a probablement crashé, ce qui est une mauvaise nouvelle.
  2. La commande docker-compose logs -f <service> permet de lire les logs envoyés sur stdout depuis le conteneur, et de suivre les nouvelles entrées. On peut voir si tout se passe bien au moment du lancement.

Une fois que l'on a vérifié que la nouvelle version du service tourne correctement, on peut nettoyer les anciennes images de la machine de production pour gagner de la place (commande docker image rm). Avec notre exemple précédent :

$ docker image rm registry.picasoft.net/pica_app:5.9.0

Si le déploiement n'a pas fonctionné, il est important de revenir rapidement à la dernière version fonctionnelle. Pour ce faire, on déroule la procédure en sens inverse :

  • Changement du numéro de version dans le docker-compose.yml
  • Extinction des conteneurs
  • Création des conteneurs avec l'ancienne version

Cas particuliers

Lors de la mise à jour de Tellform et de Wekan, il faut faire attention à la validité du patch pour Tellform et du sed pour Wekan. De plus, faute de procédure d'installation du Wekan, le Dockerfile pica-wekan est presque identique à l'original (dernière update v2.75) à l'exception des premiers RUN. Il faut faire attention s'il y a eu une quelconque modification.

Pour Tellform, le patch se trouve dans les Dockerfiles, dans le dossier pica-tellform et se nomme tellform-patch.patch.

Comment créer un patch ?

  • Liste à puceDans un répertoire externe au serveur Picasoft (typiquement une machine personnelle), cloner le service en question :
 git clone https://github.com/service_en_question/service_en_question.git 
  • Créer une copie de ce répertoire, qui contiendra les modifications que nous voulons appliquer au service.
 cp -a service_en_question service_en_question_modif 
  • Faire les modifications nécessaires dans les fichiers appropriés, dans le dossier service_en_question_modif
  • Retourner dans le dossier contenant service_en_question et service_en_question_modif
  • Appliquer le patch. Attention, l'ordre des paramètres est très important.
 diff -Naur service_en_question service_en_question_modif > nom_du_service.patch 

Le fichier contenant le patch est créé, il ne reste plus qu'à l'appliquer dans le Dockerfile, après avoir cloné le service que l'on souhaite modifier.

Comment appliquer ce patch ?

  • Dans le Dockerfile, intégrer le patch en le copier dans le même répertoire où il sera appliqué (/opt dans cet exemple)
 COPY nom_du_service.patch /opt 
  • Appliquer le patch
 patch -p0 < nom_du_service.patch 

Images Docker

Pour déployer Mattermost, Picasoft utilise 2 images Docker : une image pour l'application (que l'on appellera app) et une image pour la base de données PostgreSQL (que l'on appellera db).

Récupération du code mis à jour

On va récupérer le dépôt Git qui pointe sur l'upstream maintenue par Mattermost.

On modifie le fichier docker-compose.yml du repository pour permettre de builder la version libre de Mattermost. Normalement, les lignes suivantes ne doivent pas être commentées :

[...]

  app:
    build:
      context: app
      # comment out 2 following lines for team edition
      args:
        - edition=team
        - PUID=5000
        - PGID=5000
[...]

Pour finir, on vérifie que le repository va bien builder la version que l'on souhaite de Mattermost. On peux vérifier avec la commande suivante:

cat app/Dockerfile | grep "ENV MM_VERSION"

Si ce n'est pas la dernière version, alors il faut ouvrir une PR sur l'upstream pour demander la mise à jour.

Build et tag des images

On lance le build avec la commande docker-compose build db app. Le build peut durer un certain temps, une fois terminé on obtient deux images (visibles avec docker images) :

  • mattermost-docker_app
  • mattermost-docker_db

On tag comme d'habitude.

Déploiement

On va simplement couper le conteneur de l'application Mattermost, puis de sa base de données. On relance ensuite directement les deux services (dans l'ordre inverse).

On peut vérifier rapidement que tout s'est bien passé en se connectant sur le Mattermost de Picasoft, que ça tourne bien. Dans le menu, l'onglet “À Propos” permet de vérifier la version du serveur.

En cas de soucis, on relance les dernières versions fonctionnelles. Si cela crash toujours, on fait un rollback de la base de données.

Si tout va bien, on fait un petit message sur le channel Général pour annoncer que la MAJ s'est bien passée, en ajoutant un petit lien vers le changelog de Mattermost.

Réindexation de la base de donnée

Il est arrivé qu'après une procédure d'upgrade “violente”, la base de données Postgresql ne conserve plus ses propriétés intrinsèques. La base se retrouve corrompue et les contraintes d'intégrités ne sont plus respectées. Cela donne lieu à des problèmes de connexions au sein de Mattermost.

Pour corriger ce problème, une réindexation de la base de données est nécessaire.

Attention avant toute opération de ce genre, veuillez effectuer une sauvegarde de la base de données

root@pica01:~# docker-compose exec  mattermost-db bash
bash-4.3# psql -U postgres
psql (9.4.15)
Type "help" for help.
postgres=# \c mattermost
You are now connected to database "mattermost" as user "postgres".
mattermost=# reindex DATABASE mattermost;
NOTICE:  table "pg_catalog.pg_class" was reindexed
[...]
REINDEX
mattermost=# <ctrl d>
exit
  • services/services_upgrade.txt
  • Dernière modification: 2019/09/18 21:58
  • par qduchemi