Skip to content

ADR 013 — GitOps avec ArgoCD : pull-based vs push-based (2026-06-11)

Statut

Accepté (2026-06-11). Issue #72.

Contexte

Le déploiement sur EKS était push-based : le job deploy de la CI faisait kubectl apply -k k8s/base/ directement sur le cluster (manuel, DEPLOY=true). Limites de cette approche :

  • Pas de source de vérité unique : l'état réel du cluster pouvait diverger de Git sans que rien ne le détecte (drift). Un kubectl edit manuel n'était jamais réconcilié.
  • Credentials cluster dans la CI : le runner détient un accès kubectl au cluster (kubeconfig généré via aws eks update-kubeconfig). Surface d'attaque élargie (le runner self-hosted est déjà un SPOF, cf. #35).
  • Déploiement impératif : kubectl apply ne supprime pas les ressources retirées de k8s/base/ (pas de prune natif), l'état dérive au fil des releases.
  • GitOps était annoncé dans le README depuis le Sprint 3 (« GitLab Agent for Kubernetes ») mais jamais livré.

Décision 1 — ArgoCD plutôt que GitLab Agent

Le plan initial (README Sprint 3) prévoyait le GitLab Agent for Kubernetes. On retient ArgoCD à la place :

Critère ArgoCD GitLab Agent
Adoption marché Standard de facto CNCF (incubating→graduated) Spécifique GitLab
UI Riche (arbre de ressources, diff, sync, health) Limitée
Visibilité entretiens Forte (compétence demandée) Faible
Découplage du forge Agnostique (lit n'importe quel repo Git) Couplé GitLab
Multi-cluster / app-of-apps Natif Moins mature

La visibilité en entretien et la portabilité (même outil sur EKS, homelab, platform) priment. Déviation assumée par rapport au README initial.

Décision 2 — Pull-based avec write-back CI

Le flux devient pull-based : ArgoCD réconcilie le cluster depuis Git, la CI n'accède plus au cluster.

1. commit applicatif sur develop
2. pipeline : build image :SHA → scan → promote (inchangé)
3. job update-image-tag : kustomize edit set image fastapi=$IMAGE_SHA
   → commit "ci: bump ... [skip ci]" → push sur develop
4. ArgoCD détecte le commit → sync → rollout

Le tag d'image est désormais commité dans k8s/base/kustomization.yaml (champ images:), versionné dans Git. ArgoCD déploie exactement ce que contient Git : Git devient la source de vérité unique.

Le job deploy (kubectl apply) est supprimé. La CI ne détient plus de kubeconfig, ne fait plus d'accès cluster au déploiement.

Décision 3 — App-of-apps

L'installation et la configuration ArgoCD sont posées par le bootstrap Ansible (MR !145, #72). Un root Application (apps) surveille k8s/platform/argocd-apps/ et gère les Application CRs qui s'y trouvent (dont fastapik8s/base/). Ajouter une future Application (observabilité #74) = déposer un fichier dans ce répertoire, ArgoCD le découvre. Pattern app-of-apps.

automated.prune: true + selfHeal: true : ArgoCD supprime ce qui disparaît de Git (résout le manque de prune du kubectl apply) et corrige tout drift manuel.

Le piège de la boucle CI

Le job update-image-tag pousse un commit sur develop. Sans précaution, ce commit relancerait un pipeline, qui re-bumperait, qui re-pousserait → boucle infinie. Le message de commit contient [skip ci] : GitLab n'instancie alors aucun pipeline pour ce commit. La chaîne s'arrête après un seul write-back.

Conséquences

  • Token de push : le job pousse sur develop (branche protégée). Nécessite un Project Access Token (rôle Maintainer, scope write_repository) en variable CI masquée GITLAB_PUSH_TOKEN, autorisé en push sur la règle de protection de develop. Le CI_JOB_TOKEN par défaut ne peut pas pousser.
  • Infra down : si le cluster est éteint (éphémère), le write-back écrit quand même le tag dans Git. Au prochain aws-start, ArgoCD réconcilie le dernier tag présent dans Git. Git reste la source de vérité, la convergence est différée.
  • Deux commits par release : le commit applicatif + le commit de bump [skip ci]. Fonctionnement nominal du write-back GitOps.
  • Teardown : les Applications ArgoCD doivent être supprimées en premier (le selfHeal recréerait l'HTTPRoute, donc l'ELB → orphelin bloquant terraform destroy, classe INC-016). Géré dans teardown.yml (MR !145).

Évolution possible

  • Image Updater ArgoCD : automatiserait le bump de tag sans job CI (ArgoCD scrute l'ECR). Écarté pour l'instant : le write-back CI garde la trace du tag dans Git (auditabilité) et évite de donner à ArgoCD un accès ECR.
  • Sync waves / hooks : ordonnancement fin des ressources si besoin (migrations Alembic avant rollout). Pas nécessaire au périmètre actuel.

Date : 2026-06-11 Sprint : 4 Issue : #72