← Journal technique

devops

La chaîne CI/CD, et le « vert » qui ne veut rien dire

La chaîne CI/CD, et le « vert » qui ne veut rien dire

Pas un pipeline monolithique — une chaîne de workflows dédiés à un objectif qui se déclenchent les uns les autres :

  • ci.yml à chaque push : lint back-end, typecheck, migrations, dérive de schéma, tests unitaires ; un job smoke pgBouncer séparé ; typecheck front-end, lint, build ; un job E2E Playwright complet — en parallèle quand c'est possible, avec un job notify qui dépend de tous, rapportant réussite/échec quel que soit le résultat.
  • build-push.yml après que la CI réussit sur main, poussant les images vers le registre.
  • deploy-production.yml après un build-push réussi — récupère les images, exécute prisma migrate deploy, démarre la stack, la health-checke, revient en arrière automatiquement en cas d'échec.
  • rollback-production.yml — un workflow manuel pour revenir en arrière après que le contrôle automatisé est déjà passé mais qu'un problème remonte plus tard.

Chaîner avec workflow_run plutôt qu'un seul job géant signifie que chaque étape peut être relancée ou déboguée seule.

Runners auto-hébergés

La CI et le déploiement de production tournent tous deux sur des runners auto-hébergés. Deux raisons : le coût, et le fait que le runner de production est la VM de production — donc « exécuter des commandes sur le runner » fait aussi office de « exécuter ces commandes Docker sur le serveur qui doit finir par faire tourner les nouveaux conteneurs », sans étape de déploiement SSH séparée. Le compromis, c'est d'être responsable de garder cette machine vivante et à jour ; si le runner tombe, la CI s'arrête silencieusement jusqu'à ce que quelqu'un répare le runner lui-même.

concurrency:
  group: deploy-production
  cancel-in-progress: false

Un seul déploiement de production à la fois — un second déclenchement se met en file plutôt que de courir contre le premier, parce que deux docker compose up simultanés contre la même stack est un vrai mauvais moment. cancel-in-progress: false signifie qu'un nouveau déploiement attend plutôt que de tuer l'actuel en plein vol.

Le tour dont je me souviens vraiment

Monter ça a pris sept tours dans une seule journée. Après que tout est passé au vert, rien n'avait été construit. Le chaînage workflow_run était silencieusement cassé par conception dans les conditions où ces jobs tournaient — il ne les lançait juste pas, et ne se plaignait pas. J'avais « vérifié » le pipeline en lisant les fichiers de workflow, ce qui, il s'avère, ne vaut approximativement rien. J'ai fusionné les jobs de build dans le pipeline principal au lieu de les chaîner.

Deuxième fois dans ce projet où « la config a l'air correcte » et « la chose s'est réellement passée » se sont révélées être des affirmations différentes.

Un choix de plus : les notifications se déclenchent aussi en cas de succès, pas seulement d'échec. Pour un développeur solo, une notification confirmée « déploiement réussi » est ce qui te permet de vraiment t'éloigner au lieu de rafraîchir anxieusement l'onglet Actions.