Aller au contenu principal
GitOpsArgoCDKubernetesCI/CD

ArgoCD avancé : sync policies et multi-cluster

30 min de lecture GitOps & ArgoCD — Chapitre 4

Sync policies en détail, gestion multi-cluster, ApplicationSet pour scaler, workflows complets et bonnes pratiques production ArgoCD.

Tu as installé ArgoCD, tu as déployé ta première Application CRD. Maintenant on passe aux choses sérieuses : sync policies fines, orchestration avec les waves, déploiement multi-cluster, et ApplicationSet pour gérer des dizaines d’apps sans copier-coller. C’est ce qui sépare un PoC d’un ArgoCD production-ready.

Sync Policies : contrôler le quand et le comment

La sync policy détermine comment ArgoCD réagit quand Git et le cluster divergent. Trois modes existent : manual (tu cliques), automated (ArgoCD sync tout seul), et automated+prune (il supprime aussi les ressources orphelines).

🔥 En production, le combo automated + selfHeal + prune est le standard. Le self-heal corrige tout drift manuel en quelques secondes — plus personne ne peut faire de kubectl edit sauvage sans que ça soit écrasé.

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp-production
  namespace: argocd
spec:
  project: production
  source:
    repoURL: https://github.com/org/gitops-repo.git
    targetRevision: main
    path: environments/production
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
      - ServerSideApply=true
      - PruneLast=true
      - PrunePropagationPolicy=foreground
      - RespectIgnoreDifferences=true

Ignore Differences

Certains champs sont gérés par Kubernetes lui-même (replicas via HPA, clusterIP). Sans ignoreDifferences, ArgoCD les détecte comme du drift et boucle en sync infini.

spec:
  ignoreDifferences:
    - group: apps
      kind: Deployment
      jsonPointers:
        - /spec/replicas        # Géré par HPA
    - group: ""
      kind: Service
      jqPathExpressions:
        - .spec.clusterIP       # Auto-assigné par K8s

💡 Utilise jqPathExpressions plutôt que jsonPointers pour les cas complexes — la syntaxe jq est plus puissante et lisible.

Sync Waves et Hooks : orchestrer le déploiement

Un déploiement réel n’est pas un kubectl apply en vrac. La base de données doit exister avant la migration, la migration avant l’app, l’app avant l’ingress. Les sync waves ordonnent tout ça via une simple annotation.

# Wave -1 : Namespace (en premier)
apiVersion: v1
kind: Namespace
metadata:
  name: production
  annotations:
    argocd.argoproj.io/sync-wave: "-1"
---
# Wave 0 : ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  annotations:
    argocd.argoproj.io/sync-wave: "0"
data:
  DATABASE_URL: "postgres://db:5432/app"
---
# Wave 1 : Migration Job (hook PreSync)
apiVersion: batch/v1
kind: Job
metadata:
  name: db-migrate
  annotations:
    argocd.argoproj.io/sync-wave: "1"
    argocd.argoproj.io/hook: PreSync
    argocd.argoproj.io/hook-delete-policy: BeforeHookCreation
spec:
  template:
    spec:
      containers:
        - name: migrate
          image: ghcr.io/org/myapp:latest
          command: ["./migrate", "up"]
      restartPolicy: Never
---
# Wave 2 : Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
  annotations:
    argocd.argoproj.io/sync-wave: "2"
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp
          image: ghcr.io/org/myapp:latest

Les hooks complètent les waves. PreSync exécute un job avant le sync (migration, health check). PostSync lance les smoke tests après. SyncFail notifie Slack si ça casse. Chaque hook est un Job Kubernetes classique avec une annotation en plus.

⚠️ Oublie pas hook-delete-policy: BeforeHookCreation — sans ça, le Job précédent bloque le nouveau sync parce que Kubernetes refuse de créer un Job avec le même nom.

Multi-cluster : un ArgoCD pour les gouverner tous

ArgoCD gère nativement plusieurs clusters depuis une seule instance. Tu enregistres les clusters distants, et chaque Application pointe vers son destination.server.

# Ajouter un cluster distant
argocd cluster add production-eu \
    --kubeconfig ~/.kube/production-eu.yaml \
    --name production-eu

# Vérifier les clusters enregistrés
argocd cluster list
# SERVER                          NAME            STATUS
# https://kubernetes.default.svc  in-cluster      Successful
# https://k8s.eu.company.com      production-eu   Successful
# https://k8s.us.company.com      production-us   Successful

🎯 L’architecture recommandée : un management cluster dédié qui héberge ArgoCD et pilote tous les clusters applicatifs. Ça isole le plan de contrôle GitOps du workload.

En pratique, ArgoCD stocke les credentials de chaque cluster dans un Secret Kubernetes du namespace argocd. Le app-controller se connecte ensuite à chaque cluster pour réconcilier. Attention à la latence réseau et aux firewalls — le management cluster doit pouvoir atteindre l’API server de chaque cluster cible.

ApplicationSet : scaler sans copier-coller

Quand tu gères 5 apps sur 3 clusters, ça fait 15 Applications à maintenir. À la main, c’est ingérable. L’ApplicationSet génère automatiquement des Applications à partir de templates et de générateurs.

Git Directory Generator

Le plus courant : une Application par dossier dans le repo.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: all-apps
  namespace: argocd
spec:
  generators:
    - git:
        repoURL: https://github.com/org/gitops-repo.git
        revision: main
        directories:
          - path: apps/*
  template:
    metadata:
      name: '{{path.basename}}'
    spec:
      project: default
      source:
        repoURL: https://github.com/org/gitops-repo.git
        targetRevision: main
        path: '{{path}}'
      destination:
        server: https://kubernetes.default.svc
        namespace: '{{path.basename}}'
      syncPolicy:
        automated:
          prune: true
          selfHeal: true
        syncOptions:
          - CreateNamespace=true

Tu ajoutes un dossier apps/new-service/ dans Git → ArgoCD crée automatiquement l’Application correspondante. Tu supprimes le dossier → l’Application disparaît.

Matrix Generator : le produit cartésien

Le Matrix combine deux générateurs. Clusters × Apps = déploiement automatique de chaque app sur chaque cluster.

apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: multi-cluster-apps
  namespace: argocd
spec:
  generators:
    - matrix:
        generators:
          - clusters:
              selector:
                matchLabels:
                  env: production
          - git:
              repoURL: https://github.com/org/gitops-repo.git
              revision: main
              directories:
                - path: apps/*
  template:
    metadata:
      name: '{{name}}-{{path.basename}}'
    spec:
      project: production
      source:
        repoURL: https://github.com/org/gitops-repo.git
        targetRevision: main
        path: '{{path}}'
      destination:
        server: '{{server}}'
        namespace: '{{path.basename}}'

💡 Le Pull Request Generator est aussi très puissant : il crée un environnement preview éphémère pour chaque PR labelisée. La PR est mergée ou fermée → l’environnement est automatiquement détruit.

Cas entreprise : workflow production complet

Une fintech avec 20 microservices sur 3 clusters (EU, US, staging). Avant ArgoCD avancé : chaque équipe avait ses propres scripts de déploiement, pas de visibilité centralisée, du drift partout.

Leur setup après migration :

  • 1 ApplicationSet Matrix : 20 apps × 3 clusters = 60 Applications générées automatiquement
  • Sync waves : namespace → secrets (External Secrets) → DB → migration → app → ingress
  • Sync windows : déploiements bloqués entre 22h et 6h, et le weekend sur les clusters prod
  • PostSync hooks : smoke tests automatiques après chaque déploiement
  • SyncFail hooks : notification Slack + PagerDuty si un sync échoue

Résultat : le temps de déploiement est passé de 45 minutes (scripts custom) à 3 minutes (push Git → sync automatique). Le nombre d’incidents liés au drift a chuté de 80%.

Pièges classiques et résumé

⚠️ Le app-controller OOM — Avec 100+ Applications, le app-controller consomme beaucoup de RAM. Augmente ses resources limits et active le sharding : --application-controller-shard répartit la charge sur plusieurs replicas.

⚠️ Le prune qui supprime trop — Un fichier YAML supprimé par erreur du repo = ressource supprimée en prod. Solution : active PruneLast et configure des sync windows qui imposent un délai. Utilise aussi argocd app sync --dry-run pour prévisualiser.

⚠️ Les secrets dans Git — ArgoCD ne résout pas le problème des secrets. Utilise External Secrets Operator (récupère depuis Vault/AWS SM), Sealed Secrets (chiffrement asymétrique), ou SOPS avec age/KMS. Jamais de secret en clair dans le repo.

🔥 Le webhook plutôt que le polling — Par défaut, ArgoCD poll Git toutes les 3 minutes. Configure un webhook GitHub/GitLab pour un sync quasi-instantané : https://argocd.company.com/api/webhook avec un shared secret.

🎯 Les sync policies (automated, prune, selfHeal) sont le cœur d’ArgoCD — elles garantissent que le cluster reflète Git en permanence.

Les sync waves ordonnent les déploiements complexes. Les hooks (PreSync, PostSync, SyncFail) ajoutent de la logique autour du sync.

Le multi-cluster est natif : une instance ArgoCD pilote tous tes clusters depuis un management cluster dédié.

L’ApplicationSet est indispensable pour scaler. Git Generator pour les dossiers, Matrix Generator pour le produit clusters × apps, PR Generator pour les environnements preview.

En production, combine tout : ApplicationSet + sync waves + sync windows + hooks + ignoreDifferences. C’est la recette d’un GitOps robuste et maintenable.

🖥️ Pratique sur ton propre serveur

Pour suivre GitOps & ArgoCD en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.

Obtenir 200$

Articles liés