← Tous les travaux
IaC · AnsibleSources disponibles

Déploiement cloud automatisé

L'écart entre une stack qui tourne sur votre poste et une stack qui tourne sur un serveur, c'est d'ordinaire un humain avec une session SSH et un souvenir qui s'efface de ce qu'il a tapé. Ceci comble cet écart : le serveur est décrit en code, et cette description est la seule chose qui le touche.

Réalisé avec Bilal Eddinaoui.

1
playbook, de la VM nue à l'application en service
3
ports entrants ouverts ; tout le reste refusé
0
étape manuelle sur le serveur cible

Ce que c'est

Un unique playbook Ansible, exécuté contre des hôtes déclarés dans un inventaire, qui transforme un serveur cloud neuf en stack web multi-services fonctionnelle. Il installe et durcit le système de base, met en place Docker, transfère la stack applicative, génère sa configuration, démarre les conteneurs et vérifie qu'ils tournent réellement.

La propriété qui compte est l'idempotence : l'exécuter deux fois équivaut à l'exécuter une fois. C'est ce qui rend sûr de le relancer sur un hôte en production pour corriger une dérive, au lieu d'en faire quelque chose qu'on n'ose lancer que sur une machine sacrifiable.

Provisionner dans l'ordre qui compte

Le pare-feu passe avant les services. Le rôle installe UFW, met la politique d'entrée par défaut à « refuser », puis ouvre exactement les trois ports nécessaires — SSH et les deux ports web. Le faire d'abord garantit qu'il n'existe jamais de fenêtre où un service fraîchement installé est exposé pendant que les règles s'écrivent encore.

Docker est installé depuis le dépôt de l'éditeur plutôt que celui de la distribution : il faut donc d'abord purger les anciens paquets conflictuels aux noms voisins, importer la clé de signature officielle, puis installer le moteur avec le plugin compose. Le Docker empaqueté par les distributions est souvent assez en retard pour que la syntaxe compose dont dépend la stack ne soit tout simplement pas supportée.

L'application n'est transférée et démarrée qu'ensuite — chaque conteneur lancé puis explicitement vérifié comme actif, au lieu de supposer qu'une commande de démarrage sortie en zéro signifie que le service est monté. Un conteneur qui démarre puis meurt aussitôt sort en zéro à l'aller.

  • Refus par défaut en entrée, avec trois ports ouverts volontairement et non héritées de l'image.
  • L'état des conteneurs est vérifié après chaque étape : le playbook échoue là où est la faute, pas trois rôles plus loin.
  • Versions épinglées pour la base et les images applicatives, pour qu'une reconstruction des mois plus tard produise la même stack.

Des secrets qui restent hors du dépôt

Le mot de passe root de la base est le détail qui décide si ce travail peut être publié. Il vit dans un coffre chiffré, n'est déchiffré qu'en mémoire pendant l'exécution, et injecté au moment où le fichier d'environnement est généré depuis son modèle — écrit avec des permissions restrictives pour ne pas être lisible par les autres comptes de l'hôte.

C'est ce qui permet au dépôt d'être public sans que l'identifiant y figure, et pourquoi le fichier d'environnement existe comme modèle plutôt que comme fichier versionné avec un gabarit que quelqu'un finit par remplir et committer par accident.

Résilience et reconstruction

La persistance vit dans des volumes nommés plutôt que dans les conteneurs : un conteneur peut donc être remplacé — montée de version, plantage, destruction volontaire — sans emporter les données. Les sauvegardes tournent à intervalles réguliers sur ces volumes.

Le test de l'ensemble est la reconstruction : pointer le playbook sur un serveur entièrement neuf, l'exécuter une fois, restaurer les volumes, et la stack est revenue. C'est la différence entre une infrastructure documentée et une infrastructure réellement reproductible.

Réalisé avec

  • Ansible
  • Ansible Vault
  • Docker
  • Docker Compose
  • Nginx
  • Cloud VPS

Non hébergé : ceci provisionne un serveur plutôt que de tourner sur un. Le playbook est le livrable.