Pipelines GitOps d'entreprise avec ArgoCD & Helm
Ce guide met en place un pipeline GitOps multi-environnements avec ArgoCD et Helm, avec une structure app-of-apps et des surcouches de valeurs par environnement, ainsi que des politiques de sync automatisées qui réconcilient en continu le cluster avec Git et corrigent le drift au lieu de se contenter de le détecter.
Le pattern app-of-apps
Au-delà de quelques services, vous ne voulez pas d'une Application par microservice ; vous voulez une seule Application racine qui gère elle-même toutes les autres Applications. Un seul commit Git sur le repo d'apps suffit pour intégrer, décommissionner ou repointer un environnement entier.
# root-app.yaml, le seul objet qu'un admin de cluster touche manuellement
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-apps
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/acme/gitops-apps.git
targetRevision: main
path: apps/production
directory:
recurse: true
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
automated:
prune: true
selfHeal: trueTout ce qui se trouve sous apps/production/ est un manifeste Application ArgoCD classique, un par service ou un par groupe logique. L'app racine surveille ce dossier ; ajoutez un fichier, obtenez une nouvelle app gérée, supprimez un fichier, obtenez un démontage propre.
Structure des charts Helm et surcouches par environnement
Sous la couche app-of-apps, chaque service est un chart Helm avec un fichier de valeurs par environnement, plutôt que des branches par environnement ou des repos forkés. Brancher vos manifestes est le meilleur moyen de finir avec un staging et une production qui divergent silencieusement, sans que personne ne le remarque avant le post-mortem.
charts/payments-api/
├── Chart.yaml
├── templates/
│ ├── deployment.yaml
│ ├── service.yaml
│ └── hpa.yaml
├── values.yaml # valeurs par défaut partagées
├── values-staging.yaml # surcouche
└── values-production.yaml # surcouche# values-production.yaml
replicaCount: 6
resources:
requests:
cpu: 500m
memory: 512Mi
limits:
cpu: "1"
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 6
maxReplicas: 24
env:
LOG_LEVEL: warn
FEATURE_FLAGS_SOURCE: launchdarkly-prodvalues.yaml ne définit jamais directement le nombre de replicas ou les limites de ressources ; chaque champ sensible à l'environnement vit dans la surcouche, et la différence entre staging et production est un diff entre deux fichiers YAML, pas entre deux versions de chart.
Relier la CRD Application à Helm avec une sync automatisée
Chaque Application enfant pointe vers le chart et la surcouche d'environnement, et active la sync automated avec prune et selfHeal.
# apps/production/payments-api.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payments-api
namespace: argocd
spec:
project: production
source:
repoURL: https://github.com/acme/gitops-apps.git
targetRevision: main
path: charts/payments-api
helm:
valueFiles:
- values.yaml
- values-production.yaml
destination:
server: https://kubernetes.default.svc
namespace: payments
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 10s
factor: 2
maxDuration: 3mprune: true signifie que les ressources retirées du chart sont retirées du cluster à la prochaine sync. Sans cela, les templates supprimés laissent des objets orphelins indéfiniment. selfHeal: true annule tout changement manuel sur un objet vivant et le ramène à ce qui est dans Git, automatiquement, à la prochaine passe de réconciliation (toutes les trois minutes par défaut, ou immédiatement si vous surveillez la ressource).
La correction ici est procédurale, pas technique : votre runbook d'incident a besoin d'une étape explicite pour soit committer le patch immédiatement, soit mettre la sync en pause (argocd app set <app> --sync-policy none) avant que quiconque ne touche une ressource vivante à la main.
Sync waves et hooks pour l'ordonnancement
Le rendu de templates de Helm n'a aucune notion de « applique ceci avant cela » entre charts séparés. Beaucoup de déploiements réels en ont pourtant besoin : les CRD avant les contrôleurs qui les surveillent, ou un Job de migration qui doit terminer avant que le Deployment dépendant du nouveau schéma ne démarre. Les sync waves d'ArgoCD résolvent cela avec une simple annotation.
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: postgresqls.acme.io
annotations:
argocd.argoproj.io/sync-wave: "-1"
---
apiVersion: batch/v1
kind: Job
metadata:
name: payments-db-migrate
annotations:
argocd.argoproj.io/sync-wave: "0"
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: payments-api
annotations:
argocd.argoproj.io/sync-wave: "1"Les waves les plus basses sont synchronisées en premier, et ArgoCD attend que les ressources de chaque wave soient Healthy avant de passer à la suivante. Combiné aux hooks PreSync pour les jobs ponctuels comme les migrations, cela remplace l'étape fragile du « exécute ce script avant cette release Helm ».
Détection de drift et workflow de dérogation manuelle
Même avec selfHeal activé, il vous faut un chemin documenté pour une intervention manuelle légitime. Quand un incident exige réellement un patch en direct plus rapide qu'un cycle PR-puis-merge, le workflow est le suivant : mettre en pause la sync automatique sur l'Application concernée, faire le changement, puis soit le revert, soit le committer en urgence dans Git dans la même fenêtre d'incident. Réactiver la sync automatique seulement une fois l'app confirmée en sync.
# désactiver temporairement la sync automatisée pendant l'incident
spec:
syncPolicy: {} # retirer le bloc `automated` ; sync manuelle uniquementEn dehors d'un incident actif, le drift apparaît dans l'UI et l'API ArgoCD comme OutOfSync. Il vaut la peine d'alerter directement dessus : plus de quelques minutes d'OutOfSync sur une app de production, sans incident en cours, signifie que quelqu'un a contourné le process.
Définissez revisionHistoryLimit sur chaque Application de manière délibérée (ArgoCD conserve 10 manifestes historiques par défaut). Sur un chart avec des CRD volumineuses ou de nombreuses ressources gérées, c'est cet historique qui rend argocd app rollback lent précisément pendant l'incident où vous en avez besoin rapidement.
Quelqu'un devra encore se connecter en urgence et patcher une ressource à la main pendant un incident. Ce qui change, c'est la suite : soit le patch atterrit dans Git et la réconciliation le confirme, soit selfHeal l'annule silencieusement et vous le découvrez en quelques minutes plutôt qu'au prochain déploiement sans rapport.
Envie de faire tourner ça en production ?
Ce tutoriel couvre les concepts et l'architecture. Si vous voulez l'implémenter dans votre propre infrastructure, ou monter en compétence pour posséder ce sujet durablement, je propose du mentorat individuel construit autour de votre environnement réel, pas une formation générique.
Ce tutoriel
- Concepts clés et architecture principale
- Extraits de code illustratifs
- Le raisonnement derrière chaque décision
Mentorat individuel
- Des sessions de travail sur votre propre environnement
- Des réponses directes aux cas particuliers que vous rencontrez
- Un retour sur votre implémentation réelle
- Un accompagnement continu pendant que vous la construisez