Pourquoi migrer nos déploiements vers Argo CD ?
Contexte
Au sein d’une équipe chargée du déploiement et de la maintenance des clusters EKS, nous travaillons quotidiennement au maintien à jour et à l’amélioration des services Kubernetes assurant les fonctions de scaling, de sécurité ou encore d’observabilité.
La mise à jour de ces services est assurée par un pipeline CI/CD qui s’appuie sur une stack Terragrunt. Cette stack compte une vingtaine de modules Terraform.
Constat
Bien que robuste et fiable, ce mode de gestion des clusters EKS présente plusieurs difficultés :
- Complexité de maintenance : Les dépendances entre services rendent les mises à jour fastidieuses et risquées.
- Difficultés à travailler en parallèle : Le pipeline centralisé limite l’agilité des équipes, notamment pour le développement de nouvelles fonctionnalités.
- Manque de visibilité : L’absence d’une vue centralisée et en temps réel des déploiements complique le suivi et le debug.
Décision : Adoption du GitOps avec Argo CD
Pour répondre à ces enjeux, nous avons opté pour une migration vers une approche GitOps, en choisissant Argo CD comme solution cible. Ce choix s’est accompagné des orientations suivantes :
- Déploiement distribué : Une instance d’Argo CD par cluster pour une gestion plus granulaire et autonome.
- Conservation du pipeline CI/CD existant : Celui-ci reste dédié au déploiement des briques d’infrastructure (le cluster EKS lui-même) et des services prérequis pour Argo CD :
- Karpenter pour le provisionnement des nœuds
- Cilium pour la CNI
- Nginx et AWS Load Balancer Controller pour l’accès à l’interface graphique.
La suite de ce REX détaillera les trois grandes phases de la mise en œuvre de cette stratégie GitOps :
Conception d’une Architecture Modulaire avec Argo CD
La première étape de la migration a consisté à repenser l’organisation des services pour les adapter à une approche GitOps. L’objectif était de passer d’une gestion centralisée via Terragrunt à une architecture modulaire, décloisonnée et auto-documentée, tout en préservant la cohérence des déploiements.
Design des applications ArgoCD
Argo CD déploie des ressources Kubernetes à travers des applications. Ces applications sont elles-mêmes des objets Kubernetes définis par une custom ressource (CRD) Argo.
Une application référence une ou plusieurs sources pouvant être des registres de chart helm ou dépôts git publics ou privés.
On distingue :
- Les applications “simples” [single chart applications] :
Contenant une source unique, un chart Helm ou une configuration kustomize, qui déploient une seule application ou microservice.
Idéal pour les déploiements simples où chaque application est autonome, sans dépendances complexes.
- Les applications “complexes” [multi-charts applications] :
Contenant plusieurs sources, multiples charts Helm ou multiples projets Git Kustomize, ayant des dépendances entre eux.
Idéal pour les applications comportant plusieurs composants (front, back , database) devant être déployés ensemble mais pas nécessairement comme un unique gros monolithe.
Utile lorsque chaque composant a sa propre helm chart.
- Les App-of-Apps [Hierarchical Applications] :
Une application parent contenant plusieurs applications enfants, pouvant être simple ou complexe. Ces applications enfants ayant leur propre application Argo CD.
Permet de gérer des services complexes et multi-chart ou de regrouper plusieurs applications au sein d’une même structure organisationnelle.
Idéal pour les environnements à grande échelle ou des configurations multi-clusters.
Organisation des services
Regroupement par fonctionnalité
Pour structurer nos déploiements, nous avons opté pour une architecture hiérarchique basée sur des App-of-Apps Argo CD. Chaque application parent regroupe des services par domaine fonctionnel, avec des applications enfants dédiées à des composants spécifiques. Voici les groupes identifiés :
- kube-core-infra : services infrastructure (ingress, storage, …)
- kube-scaling : hpa, vpa, down-scaling
- kube-security: validation/mutation webhook, backup, secrets
- kube-dynatrace : dynatrace
- kube-monitoring : metrics, logs managements
- kube-tools : on-demand service for testing or debugging purpose
Gestion des services multi-composants : l’exemple de Kyverno
Certains services, comme Kyverno, nécessitent le déploiement de plusieurs charts Helm et de manifestes Kubernetes (ex : kyverno-operator, policy-reporter, et des politicies personnalisées).
Initialement, un seul module Terraform gérait l’ensemble des composants, ce qui rendait les déploiements complexes, notamment la gestion des dépendances entre CRD et objets Kubernetes.
Regrouper tous ces éléments dans une seule application Argo CD aurait nécessité de multiples sources et rendu la configuration difficile à maintenir. Nous avons choisi de :
- Séparer les composants en applications enfants distinctes (ex : une application pour kyverno-operator, une autre pour policy-reporter, et une troisième pour les policies).
- Regrouper ces applications enfants au sein d’une même App-of-Apps dédiée à la sécurité.
Cette approche s’aligne sur les recommandations d’Argo CD. La documentation indique que même s’il n’y a pas de limites techniques au nombre de sources que l’on peut ajouter dans une application Argo CD, il est déconseillé d’en abuser.

Standardisation des applications
Pour garantir la cohérence et la maintenabilité, chaque application (parent ou enfant) suit un modèle standardisé :
Charts Helm :
- Source du chart : provenant d’un registre privé (ECR) ou d’un dépôt Git.
- Fichiers values communs : stockés dans un dépôt Git partagé entre tous les clusters.
- Fichiers values spécifiques : stockés dans un dépôt Git dédié au cluster cible.
Manifests Kubernetes :
- Une seule source (dépôt Git) contenant les fichiers YAML.
Ce modèle permet de découpler la configuration générique de celle spécifique à un cluster, tout en conservant une structure prévisible et reproductible.

Refonte des Services Kubernetes : de Terraform à Helm
Réécriture des templates terraform en fichiers de configuration YAML/Helm
Un défi de compatibilité et de modularité
La migration vers Argo CD a nécessité la transformation des templates Terraform — historiquement adaptés pour assurer la compatibilité des services Kubernetes avec l’ensemble des clusters — en manifestes Kubernetes ou en fichiers de configuration YAML/Helm. L’enjeu était double :
- Préserver l’historique des configurations existantes
- Adapter les mécanismes de variabilisation pour qu’ils soient compatibles avec une approche GitOps.
Gestion des values Helm : Une approche hiérarchisée
Contrairement à Terraform, où les variables et templates permettent une variabilisation dynamique, Helm impose une structure plus rigide. Pour contourner cette limitation, nous avons mis en place une ségrégation des fichiers values selon leur portée :
- Globale:
- Configuration : commune à tous les clusters (ex : versions par défaut, paramètres génériques).
- Localisation : projet Git dédié aux App-of-Apps – fichier values.yaml.
- Environnement (Cloud Provider, région):
- Configuration : partagée par tous les clusters de type EKS, GKE, au sein d’une même région.
- Localisation : projet Git dédié aux App-of-Apps – fichier values-aws.yaml et values-gcp.yaml.
- Cluster :
- Configuration : spécifique à un cluster (ex : adresses IP, noms de domaines internes).
- Localisation : projet Git dédié au cluster cible.
Mécanisme de préséance
Les fichiers values sont appliqués dans un ordre précis (du plus global au plus spécifique) via les sources de l’application Argo CD. Chaque fichier surcharge les valeurs du précédent, garantissant ainsi une personnalisation progressive et contrôlée.
Configuration Dynamique des Services
Les templates Terraform utilisaient des boucles, des conditions, et des fonctions avancées pour générer dynamiquement des configurations. Helm, bien que puissant, ne propose pas les mêmes mécanismes. Nous avons donc dû repenser les logiques de génération :
- Remplacer les boucles Terraform par des boucles Helm (range) ou des listes statiques pré-défini.
- Adapter les conditions (if) en utilisant des blocs {{- if }} ou des valeurs par défaut dans les values.


Un défi majeur : Préserver la sécurité des secrets
L’un des points critiques de la migration a été la gestion des secrets.
Dans l’ancienne architecture Terraform, ceux-ci étaient :
- Stockés dans AWS Secrets Manager.
- Récupérés dynamiquement via des variables Terraform masquées.
- Injectés dans les templates sans jamais apparaître en clair dans les fichiers de configuration.
Avec Argo CD, il était hors de question d’exposer ces secrets en clair dans les fichiers values ou les dépôts Git.
Une des solutions couramment utilisée est Hashicorp Vault et le plugin argocd-vault-plugin.
Nous avons opté pour une approche native AWS avec :
- AWS Secret Manager, déjà en place dans notre infrastructure
- External Secret Operator (ESO) pour synchroniser les secrets AWS et les secrets Kubernetes.
Avec cette solution les secrets ne transitent jamais dans les dépôts Git ou les fichiers values.

Gestion des ressources AWS
Contexte : Des dépendances AWS incontournables
La plupart des services Kubernetes déployés sur Amazon EKS nécessitent des ressources AWS externes pour fonctionner correctement :
- Rôles et politiques IAM (pour les permissions des pods ou des contrôleurs).
- Buckets S3 (pour le stockage des logs, sauvegardes, etc.).
- Clés KMS (pour le chiffrement des données sensibles).
Dans l’ancienne architecture, ces ressources étaient créées et gérées par des modules Terraform, intégrés au pipeline CI/CD Terragrunt.
Comment concilier une approche GitOps (Argo CD) avec la gestion de ces dépendances AWS ?
Plusieurs outils permettent de gérer des ressources AWS directement depuis Kubernetes, en s’intégrant à Argo CD :
- KRO
- Kubernetes Resource Operator (projet AWS Labs) pour gérer des ressources AWS via des CRDs.
- Intégration native avec AWS
- Limites : Non adapté à la production (au moment de l’étude)
- Crossplane
- Plateforme open-source pour provisionner et gérer des ressources cloud via des CRDs.
- Flexible, multi-cloud, communauté active
- Controller ACK
- AWS Controllers for Kubernetes : contrôleurs officiels AWS pour gérer des ressources via CRDs (Controller utilisé par Crossplane pour gérer les ressources AWS).
Décision stratégique : Conservation des modules Terraform
Après une analyse comparative, Crossplane a été identifié comme la solution la plus mature pour une intégration GitOps.

Cependant, une évaluation de la charge de travail a révélé que la migration de l’ensemble des ressources AWS vers Crossplane aurait nécessité un effort significatif, avec des risques de complexité accrue. De plus, la stabilité et la rapidité de rollback étaient des priorités pour la première phase de migration.
Nous avons donc décidé de :
- Conserver les modules Terraform pour la gestion des ressources AWS, en parallèle d’Argo CD.
- Utiliser une mécanique d‘activation à la demande (feature flipping) du déploiement des ressources kubernetes dans ces modules
- Découpler les responsabilités :
- Terraform/Terragrunt : Gestion des ressources AWS (IAM, S3, KMS, etc.).
- Argo CD : Déploiement des services Kubernetes, avec des références aux ressources AWS existantes.
Cette approche garantit :
- La possibilité de rollback immédiat vers Terragrunt en cas d’incident.
- Une migration par étapes, sans rupture brutale.
- Pas de réécriture complète des modules AWS en manifests Kubernetes.
Perspectives d’évolution
À moyen terme, une migration progressive vers Crossplane ou ACK pourrait être envisagée pour :
- Unifier la gestion des ressources AWS et Kubernetes sous GitOps.
- Réduire les dépendances aux pipelines Terraform.
- Bénéficier d’une gestion déclarative cohérente pour l’ensemble de l’infrastructure.
Industrialisation du Déploiement avec Argo CD
Prérequis : Structurer Argo CD pour le déploiement
Argo CD synchronise les ressources d’un cluster Kubernetes avec une ou plusieurs sources de vérité (dépôts Git, registres Helm, etc.). Cependant, avant d’activer cette synchronisation, il est nécessaire de configurer trois éléments clés dans Argo CD :
- Une application :
- Définit les sources à synchroniser (ex : dépôt Git, chart Helm) et la cible (namespace, cluster).
- Un projet :
- Regroupement logique d’applications avec des règles RBAC, des restrictions, …
- Un repository :
- Connexion aux sources externes, (registres Helm, dépôt Git, …)
Plusieurs approches existent pour configurer ces éléments :
- GUI Argo CD :
- Création manuelle via l’interface web
- Simple pour des tests ou des cas ponctuels
- Non reproductible, non versionnée
- CLI Argo CD :
- Utilisation de la ligne de commande (argocd CLI) ou intégration dans un pipeline CI/CD
- Automatisable, scriptable
- Gestion centralisée complexe
- API kubernetes :
- Déploiement via kubectl (manifestes YAML) ou dans un pipeline CI/CD
- Intégration native avec Kubernetes
- Requiert une bonne maîtrise de l’API
- Infrastructure as Code (IaC) :
- Utilisation de Terraform (providers kubernetes ou argocd) pour une gestion déclarative
- Reproductible, versionnée, intégrée à la stack existante
- Courbe d’apprentissage pour le provider argocd
Choix technique : Intégration via Terraform et le provider Kubernetes
Pour garantir reproductibilité, traçabilité et cohérence avec notre stack existante, nous avons opté pour une approche Infrastructure as Code en étendant notre stack Terragrunt avec :
- Un module Terraform dédié pour créer les projets, applications et repositories Argo CD.
- Des templates pour standardiser la définition des applications et projets.
- Le provider kubernetes (plutôt que le provider argocd) pour déployer les ressources, car :
- Il offre une stabilité éprouvée (le(s) provider(s) argocd étai(en)t encore en développement actif au moment de l’étude).
- Il permet une intégration transparente avec nos modules Terraform existants.
- Les ressources sont définies dans un fichier de settings YAML, simplifiant la maintenance.
Connexion à la registry privée
Enjeu : Maintenir un accès sécurisé et continu à l’ECR
Dans une approche GitOps, ArgoCD s’assure en continu que l’infrastructure cible correspond à l’état souhaité défini dans Git. En cas de divergence, les ressources kubernetes peuvent être redéployées. Ces mécanismes impliquent une connexion permanente de l’instance Argo CD avec le registre ECR privé contenant les charts et images. Cependant, la durée de vie maximale d’un token ECR est de 12h. Il faut donc mettre en place un mécanisme de renouvellement automatiquement des tokens, avec une fréquence inférieure ou égale à 12h.
Nous avons utilisé External Secrets Operator (ESO) pour automatiser cette gestion, grâce à sa fonctionnalité dédiée aux tokens ECR.
ESO surveille une ressource (CRD) de type ECRAuthorizationToken, qui déclenche automatiquement le renouvellement du token avant son expiration.
Avantages :
- Pas de rupture de service : le token est renouvelé de manière transparente.
- Sécurité : le token n’est jamais stocké en clair dans les dépôts Git ou les configurations Argo CD.
- Intégration native : utilisation de l’infrastructure AWS existante (IAM, ECR).

Impacts sur la stratégie de branche et l’adaptation du GitFlow
Transition du modèle push-based au pull-based
Avec Terragrunt, le déploiement suit un modèle dit push-based :
- Les modifications d’une branche feature sont poussées vers un environnement de test, puis vers la production, avant ou après fusion sur la branche main (selon le GitFlow choisi).
- Ce modèle est adapté au déploiement via un pipeline de CI/CD

Avec Argo CD, le déploiement devient pull-based :
- Le contrôleur tire le contenu d’une branche Git fixe pour synchroniser le cluster.
- La branche cible ne change pas : les évolutions sont fusionnées vers cette branche pour être déployées automatiquement.
- Conséquence : Le GitFlow classique (branches feature → main → déploiement) n’est plus adapté.

Stratégie de branchement adaptée au GitOps
Généralement, sur les projets GitOps, on va trouver :
- une branche pérenne par environnement
- des branches feature/Fix qui seront fusionnées vers la branche de l’environnement cible
Dans notre cas d’usage, le découpage production/non production n’était pas le plus pertinent. A la place, nous avons aligné la stratégie de branches sur notre plan de release trimestriel, basé sur les versions Kubernetes :
- Release courante : ex. 1.31
- Release à venir ou en cours de déploiement: ex. 1.32
- Release en cours de préparation: ex: 1.33
Workflow de déploiement
Développement :
- Les branches feature ou fix sont fusionnées vers la branche de la release en préparation (ex: 1.33).
- Les clusters de test synchronisent automatiquement cette branche pour validation.
Upgrade Kubernetes :
- Une fois la release validée, les clusters de production sont basculés de la branche courante 1.31 vers la release suivante 1.32.
- La branche de développement 1.33 devient la nouvelle release à venir, et une nouvelle branche de développement 1.34 est créée pour la prochaine itération.

Avantages :
- Alignement avec le cycle de release : chaque branche correspond à une version Kubernetes et un état stable du code.
- Stabilité : les clusters de production restent synchronisés sur une branche immuable pendant tout le trimestre.
- Flexibilité : les tests et validations sont isolés sur la branche de préparation, sans impact sur la production.
Bilan
La mise en œuvre d’une stratégie GitOps pour le déploiement des services Kubernetes sur notre parc EKS a soulevé de nombreux défis, chacun nécessitant une solution adaptée. Argo CD, en tant qu’outil central de cette migration, bénéficie d’un écosystème riche (plugins, intégrations, bonnes pratiques) permettant d’adresser chaque problématique de manière flexible.
Il n’existe pas de solution universelle : les choix techniques dépendent étroitement du contexte, des contraintes et des objectifs de chaque organisation.
Un critère décisif dans nos choix a été la continuité opérationnelle pour les équipes en charge du Run. Pour minimiser les perturbations, nous avons privilégié des solutions proches de l’existant :
- Réutilisation des modules Terraform pour la gestion des ressources AWS.
- Conservation de la stack Terragrunt pour le déploiement de l’infrastructure.
- Intégration transparente avec le pipeline CI/CD existant.
- Migration progressive pour permettre un rollback simple en cas de besoin.
Ces décisions ont permis de :
- Réduire la courbe d’apprentissage pour les équipes.
- Maintenir la stabilité des environnements pendant la transition.
- Capitaliser sur les outils maîtrisés (Terraform, AWS, etc.).
- Réaliser un premier pas vers une cible full GitOps
Les solutions présentées ici sont le fruit d’un compromis entre innovation et pragmatisme. Elles ne seront pas nécessairement optimales pour d’autres contextes, où des contraintes différentes (ex : multi-cloud, équipes dédiées DevOps, etc.) pourraient orienter vers d’autres outils ou stratégies.
