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.
ssh eliashounnou@34.140.149.187SSH 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.
| Mot | Analogie | Exemple |
|---|---|---|
| Dockerfile | La recette | timemanager-api/Dockerfile |
| Image | Le plat préparé, emballé | ghcr.io/saliehsab/timemanager-api:latest |
| Conteneur | Le plat en train d'être servi | timemanager-back |
| Volume | Un disque qui survit au conteneur | pgdata (les données de la base) |
| Réseau | Un câble virtuel entre conteneurs | timemanager, internal |
| Registre | Le supermarché des images | ghcr.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
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 machineDocker 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.
services:
back:
image: ghcr.io/${GHCR_OWNER}/timemanager-api:latest
depends_on:
db:
condition: service_healthy
db:
image: postgres:17-alpinedocker 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 backDans 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 machineHTTPS 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.
- name: Install UFW
apt:
name: ufw
state: presentCette 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.
| Mot | Sens |
|---|---|
| Inventaire | La liste des machines (inventory.ini) |
| Groupe | Des machines rangées ensemble (prod, tooling) |
| Tâche | Une action (installer, copier, lancer) |
| Rôle | Un ensemble de tâches sur un sujet (docker, traefik) |
| Playbook | Quels rôles appliquer sur quels groupes (playbook.yml) |
| Variables | Les valeurs réutilisées (group_vars/) |
| Vault | Un fichier de variables chiffré, pour les secrets |
| Tag | Une é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.ymletgroup_vars/tooling.yml; - déchiffrés seulement au moment de lancer le playbook ;
- écrits sur les serveurs dans des fichiers
.envlisibles par leur seul propriétaire (0600).
Voir Secrets.