Skip to content

Les bases à connaître ​

Les notions DevOps utilisées dans le projet, expliquées à partir de zéro.

Un serveur, c'est un ordinateur à distance ​

Une machine virtuelle (VM) est un ordinateur loué chez un hébergeur, ici Google Cloud. Il n'a ni écran ni clavier : on s'y connecte avec SSH pour taper des commandes.

bash
ssh eliashounnou@34.140.149.187

SSH utilise une paire de clés : une clé privée gardée sur ton ordinateur (~/.ssh/id_ed25519) et une clé publique installée sur le serveur. Pas de mot de passe à taper, et rien à voler sur le réseau.

Docker : emballer une application ​

Sans Docker, pour lancer l'API il faudrait installer Elixir, Erlang, les bonnes versions des bibliothèques... sur chaque serveur. Avec Docker, on construit une image qui contient l'application et tout ce dont elle a besoin. On la lance ensuite partout de la même façon.

MotAnalogieExemple
DockerfileLa recettetimemanager-api/Dockerfile
ImageLe plat préparé, emballéghcr.io/saliehsab/timemanager-api:latest
ConteneurLe plat en train d'être servitimemanager-back
VolumeUn disque qui survit au conteneurpgdata (les données de la base)
RéseauUn câble virtuel entre conteneurstimemanager, internal
RegistreLe supermarché des imagesghcr.io

Un conteneur peut être détruit et recréé à tout moment : seules les données dans un volume sont gardées.

Les commandes de base ​

bash
docker ps                      # les conteneurs qui tournent
docker logs -f timemanager-back  # les journaux d'un conteneur, en direct
docker exec -it timemanager-db sh  # ouvrir un terminal dans un conteneur
docker images                  # les images présentes sur la machine

Docker Compose : plusieurs conteneurs ensemble ​

L'application, c'est trois conteneurs (site, API, base) qui doivent se connaître. Docker Compose les décrit dans un fichier YAML et les lance d'une seule commande.

yaml
services:
  back:
    image: ghcr.io/${GHCR_OWNER}/timemanager-api:latest
    depends_on:
      db:
        condition: service_healthy
  db:
    image: postgres:17-alpine
bash
docker compose up -d       # tout lancer en arrière-plan
docker compose pull back   # télécharger la dernière image de back
docker compose ps          # l'état des services
docker compose logs back   # les journaux de back

Dans un même Compose, les conteneurs se trouvent par leur nom : l'API joint la base à l'adresse db.

Un reverse proxy : l'aiguilleur ​

Les trois sites (web, API, Jenkins) sont sur la même machine, mais un seul programme peut écouter le port 443. Traefik écoute ce port, regarde le nom de domaine demandé, et transmet la requête au bon conteneur. Il s'occupe aussi des certificats HTTPS.

time.jostud.com      →  timemanager-front:8080
api.time.jostud.com  →  timemanager-back:4000
ci.time.jostud.com   →  Jenkins sur l'autre machine

HTTPS et Let's Encrypt ​

HTTPS chiffre les échanges entre le navigateur et le serveur. Il faut un certificat qui prouve que le serveur est bien time.jostud.com. Let's Encrypt en délivre gratuitement, pour 90 jours. Traefik les demande et les renouvelle tout seul.

Ansible : configurer des serveurs par fichiers ​

Préparer un serveur, c'est installer des paquets, créer des utilisateurs, copier des fichiers, lancer des services. À la main, c'est long, et on oublie toujours une étape. Ansible lit des fichiers YAML qui décrivent l'état voulu et l'applique par SSH.

yaml
- name: Install UFW
  apt:
    name: ufw
    state: present

Cette tâche ne dit pas « installe UFW » mais « UFW doit être installé ». Si c'est déjà le cas, Ansible ne fait rien. On peut donc relancer un playbook autant de fois qu'on veut : c'est ce qu'on appelle l'idempotence.

MotSens
InventaireLa liste des machines (inventory.ini)
GroupeDes machines rangées ensemble (prod, tooling)
TâcheUne action (installer, copier, lancer)
RôleUn ensemble de tâches sur un sujet (docker, traefik)
PlaybookQuels rôles appliquer sur quels groupes (playbook.yml)
VariablesLes valeurs réutilisées (group_vars/)
VaultUn fichier de variables chiffré, pour les secrets
TagUne étiquette pour ne lancer qu'une partie (--tags traefik)

CI/CD : le robot qui teste et déploie ​

  • CI (intégration continue) : à chaque changement, un robot teste et construit le code.
  • CD (déploiement continu) : si tout passe, il le met en ligne.

Le robot ici est Jenkins. Il lit des pipelines : une suite d'étapes (tests, build, scan, push, déploiement). Si une étape échoue, les suivantes ne sont pas lancées, et la production ne change pas.

Un pare-feu ​

UFW (Uncomplicated Firewall) bloque tous les ports entrants sauf ceux qu'on autorise. Sur tm-prod : 22, 80 et 443. Sur tm-tooling : 22 seulement.

Les secrets ​

Un mot de passe de base de données ne doit jamais être écrit en clair dans Git. Les secrets sont :

  • chiffrés avec Ansible Vault dans group_vars/prod.yml et group_vars/tooling.yml ;
  • déchiffrés seulement au moment de lancer le playbook ;
  • écrits sur les serveurs dans des fichiers .env lisibles par leur seul propriétaire (0600).

Voir Secrets.