Ressources
Argo CD App-of-Apps et ApplicationSet : amorcer un cluster sans masquer les dépendances
ArgoCD ApplicationSet, App-of-Apps ou Applications directes : choisir le bootstrap d'un cluster, ordonner la santé, préparer suppression et reprise.
Par Corentin Mas, publié le · 25 min de lecture
Base d'expérience : Méthode et documentation officielle Argo CD 3.5.3 : structuration de bootstraps GitOps par couches plateforme et applications, sans dépôt ni client nommé.
Relecture factuelle : Claude Code (revue indépendante déléguée par Corentin Mas, 28/09/2026), le
Amorcer un cluster avec Argo CD revient à confier à quelques objets la création de tout le reste : projets, contrôleurs de plateforme, applications des équipes. App-of-Apps, ApplicationSet et de simples déclarations d'Application y parviennent tous, mais ne répartissent de la même manière ni les droits, ni l'ordre de démarrage, ni les effets d'une suppression. Une racine « Synced » peut coexister avec des enfants hors synchronisation, et une Application créée à la main peut échapper à tout diff.
Ce guide tranche le choix par des critères de gouvernance, puis traite ce que la documentation laisse au lecteur : frontière hors bande, protection de la racine, propriété par couche, ordre de démarrage face à la santé, suppression et reprise. Cette lecture est établie sur Argo CD 3.5.3, version stable publiée à la date du (la 3.6.0-rc1 reste une pré-version) ; les pages officielles citées et les sources du dépôt au tag v3.5.3 ont été vérifiées le .
Choisir le mécanisme et tracer la frontière du bootstrap
La page officielle de bootstrap s'adresse à des opérateurs qui ont déjà installé Argo CD. Elle admet qu'un script ou une création manuelle des Applications conviennent, puis recommande d'examiner les ApplicationSet et leur générateur de clusters, qui couvre « la plupart des scénarios typiques ». App-of-Apps y figure comme alternative, sous un avertissement : c'est un outil réservé aux administrateurs. Chaque mécanisme déplace en effet l'autorité, vers celui qui applique des manifestes, vers celui qui écrit dans le dépôt de la racine, ou vers celui qui contrôle les données d'un générateur.
Tableau de décision
| Critère | Applications directes | App-of-Apps | ApplicationSet |
|---|---|---|---|
| Forme du catalogue | Quelques Applications singulières, sans répétition | Enfants explicites et hétérogènes, relus fichier par fichier | Même motif répété sur des clusters, des dossiers, des dépôts ou des demandes de fusion |
| Qui écrit les Applications | L'opérateur ou la CI | L'Application racine, depuis son dépôt | Le contrôleur ApplicationSet, depuis les générateurs et le template |
| Droit critique | Créer des Applications dans le namespace d'Argo CD | Pousser dans le dépôt de la racine | Créer un ApplicationSet ; écrire dans la source des générateurs si project est templatisé |
| Revue avant effet | Diff de chaque Application | argocd app diff de la racine montre les Applications ajoutées ou modifiées | argocd appset generate ou argocd appset create --dry-run listent les Applications rendues |
| Ordre de démarrage | Aucun, hors procédure écrite | Sync waves de la racine, à condition de restaurer la santé de la ressource Application | Progressive Syncs (RollingSync), en bêta et à activer ; l'auto-sync des Applications générées est alors désactivé |
| Suppression | Finalizer de chaque Application | Prune de la racine, puis finalizer de chaque enfant | ownerReferences : supprimer l'ApplicationSet supprime ses Applications ; preserveResourcesOnDeletion et applicationsSync à décider |
| Risque typique | Copies qui divergent, Applications hors inventaire | Racine Synced avec des enfants OutOfSync ou Degraded | Changement d'étiquette ou de dossier qui retire des Applications et leurs workloads |
Les options se combinent : une racine App-of-Apps qui ne déclare que des AppProjects, quelques Applications de plateforme et des ApplicationSet pour les charges répétées garde un point d'entrée unique et relu. Reste à savoir, pour chaque objet, qui peut modifier la source de sa création.
Ce qui reste hors bande
Aucun des trois mécanismes ne réalise le premier démarrage. Installation d'Argo CD, accès au cluster, ancres de confiance TLS ou SSH, Secret du dépôt et Application racine relèvent d'une procédure versionnée des administrateurs, qui doit rester exécutable si le cluster ou son gestionnaire de secrets est indisponible.
# Exemple synthétique : amorçage hors bande, Argo CD 3.5.3
kubectl create namespace argocd
kubectl apply -n argocd --server-side --force-conflicts \
-f https://raw.githubusercontent.com/argoproj/argo-cd/v3.5.3/manifests/install.yaml
kubectl rollout status -n argocd deployment/argocd-server
# Secret de dépôt et ancres de confiance : chaîne de secrets, jamais Git en clair
kubectl apply -n argocd -f bootstrap/trust/
kubectl apply -n argocd -f bootstrap/admin-project.yaml
kubectl apply -n argocd -f bootstrap/root-application.yaml
argocd app diff bootstrap-root --hard-refresh
argocd app sync bootstrap-rootLe guide d'installation impose --server-side --force-conflicts : depuis la 3.3, la CRD ApplicationSet dépasse la limite de 262 144 octets de l'annotation posée par un kubectl apply côté client. argocd app diff renvoie par défaut un code non nul dès qu'une différence existe, ce qui arrête une procédure scriptée tant que le diff n'a pas été lu. Un SHA de commit rend diff et approbation reproductibles ; la documentation suggère aussi d'épingler ainsi les enfants, qui ne changent alors qu'avec la racine.
# Exemple synthétique : bootstrap/admin-project.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: bootstrap-admin
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
description: Racine administrative du cluster
sourceRepos:
- https://git.example.net/platform/argocd-bootstrap.git
destinations:
- server: https://kubernetes.default.svc
namespace: argocd
clusterResourceWhitelist: []
namespaceResourceWhitelist:
- group: argoproj.io
kind: AppProject
- group: argoproj.io
kind: Application
- group: argoproj.io
kind: ApplicationSet
orphanedResources:
warn: true
ignore:
- group: argoproj.io
kind: Application
name: bootstrap-root
- group: argoproj.io
kind: AppProject
name: bootstrap-admin
- group: argoproj.io
kind: AppProject
name: default
---
# Exemple synthétique : bootstrap/root-application.yaml, fichier distinct
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: bootstrap-root
namespace: argocd
spec:
project: bootstrap-admin
source:
repoURL: https://git.example.net/platform/argocd-bootstrap.git
targetRevision: "<sha-de-commit-relu>"
path: clusters/production/root
destination:
server: https://kubernetes.default.svc
namespace: argocd
syncPolicy:
syncOptions:
- FailOnSharedResource=trueLe projet de la racine est étroit mais administratif : un dépôt, le namespace d'Argo CD, trois kinds, aucun objet de portée cluster. Créer un AppProject enfant reste un pouvoir fort, puisque cet enfant définit ses propres autorisations. Le finalizer de l'AppProject empêche sa suppression tant qu'une Application le référence ; le bloc orphanedResources sert au premier écueil du troisième chapitre. Ni auto-sync ni prune ne sont activés : ces décisions attendent le scénario de suppression du cinquième chapitre.
Protéger la racine comme un composant administrateur
La documentation qualifie de capacité administrateur la création d'Applications dans des projets arbitraires. Seuls les administrateurs poussent dans le dépôt de la racine, les demandes de fusion y sont relues en examinant le champ project de chaque Application, et tout projet autorisé à déployer dans le namespace d'Argo CD donne un accès de niveau administrateur. Une identité humaine ou de CI capable de fusionner dans ce chemin détient donc ce pouvoir, même si son compte Argo CD est en lecture seule.
Ce qu'un AppProject borne, et ce qu'il ne borne pas
Un AppProject restreint les dépôts (sourceRepos), les destinations et les kinds déployables, par listes d'autorisation ou de refus, de portée cluster comme de portée namespace ; la documentation précise que les objets de portée namespace se restreignent d'ordinaire par liste de refus et ceux de portée cluster par liste d'autorisation, filtrable par nom, par exemple les Namespaces préfixés team1-. Le projet default naît avec la configuration la plus permissive et ne peut pas être supprimé ; la documentation fournit le manifeste qui lui retire toute permission, après quoi les Applications qui l'utilisent sont refusées. Sur un cluster partagé, cette neutralisation appartient à la couche zéro.
Le projet de la racine ne filtre pas ses enfants : chaque Application est évaluée contre son propre spec.project, éventuellement complété par un projet global déclaré dans argocd-cm. La revue résout donc, pour chaque enfant, le projet réellement référencé.
ApplicationSet : le générateur devient une source d'autorité
La page de sécurité des ApplicationSet est plus directe : seuls les administrateurs peuvent en créer, modifier ou supprimer. Un ApplicationSet crée des Applications dans des projets arbitraires, vite et en nombre, et le générateur Git peut lire des Secrets du namespace d'Argo CD pour les envoyer vers l'URL de son champ api. Avec un champ project templatisé, quiconque écrit dans la source d'un générateur peut viser un projet peu restreint et, depuis un projet sans restriction comme default, prendre la main sur Argo CD par sa ConfigMap RBAC : les administrateurs doivent alors contrôler toutes les sources. En 3.5.3, un générateur Git à projet templatisé n'offre pas de vérification de signature et n'accepte que des dépôts non rattachés à un projet. La 3.5 remplace d'ailleurs GnuPG par Source Integrity et déprécie spec.signatureKeys : un bootstrap signé se relit à la montée de version.
Séparer les droits Argo CD et les droits Kubernetes
Le RBAC d'Argo CD et celui de Kubernetes ne se recouvrent pas. Dans Argo CD, update et delete sur une Application portent sur l'objet, pas sur ses ressources, et create sur applicationsets revient à créer des Applications dans les projets désignés. Un rôle de CI peut se limiter à get et sync sur <projet>/*, sans override, qui synchronise des manifestes locaux arbitraires. Côté Kubernetes, quiconque peut créer une ressource applications.argoproj.io dans le namespace d'Argo CD contourne le dépôt de la racine : c'est l'origine du premier écueil du chapitre suivant.
Une demande de fusion sur le dépôt de la racine se relit avec une grille courte :
- Le
spec.projectde chaque Application ajoutée ou modifiée, et le projet effectivement résolu. - Les destinations, surtout vers le namespace d'Argo CD.
- La
syncPolicy, les finalizers et les annotationssync-options(Prune=confirm,Delete=false). - Le
targetRevisiondes enfants.
Donner un propriétaire à chaque couche
Une arborescence de dossiers ne désigne pas un responsable. La propriété se décide par couche, puis se vérifie ressource par ressource. Le schéma propose quatre couches ; les numéros de wave sont un exemple synthétique.
Quatre couches de bootstrap et leurs propriétaires
La couche 0 est posée hors bande ; la racine réconcilie ensuite les objets de contrôle, qui déploient la plateforme puis les applications produit.
Schéma défilable horizontalement ; sa version textuelle complète suit.
Lire le schéma sous forme textuelle
- La couche 0 s'exécute hors bande, dans l'ordre : installation d'Argo CD 3.5.3 en server-side apply, Secret de dépôt et ancres de confiance, AppProject
bootstrap-admin, Application racine épinglée à un commit relu. - La racine réconcilie la couche 1 : AppProjects de plateforme et de produit en wave -1, Applications de plateforme en waves 0 et 1, ApplicationSets produit en wave 2.
- Les AppProjects de la couche 1 bornent les Applications de plateforme et les Applications générées, sans hériter du projet de la racine.
- Les Applications de plateforme déploient la couche 2 : CRD et opérateurs, puis contrôleurs partagés (certificats, entrée réseau, secrets, observabilité).
- Les ApplicationSets produit génèrent la couche 3, une Application par cluster ou par dossier, qui déploie les workloads des équipes.
- Les contrôleurs partagés sont des prérequis des workloads, sans lien d'ordre automatique : cet ordre ne tient que par les waves de la racine et le relais de santé.
Argo CD lui-même peut rester dans la couche 0, mis à jour par la procédure hors bande, ou se gérer depuis la couche plateforme. Dans le second cas, la documentation impose ServerSideApply=true sur son Application, pour la même raison de taille de CRD ; un projet dédié et Prune=confirm évitent qu'un prune retire le contrôleur qui l'exécute. Ce découpage, avec un propriétaire et un critère de passage par couche, est aussi le point de départ d'une plateforme Kubernetes gouvernée.
Un registre par ressource, pas par dossier
Un registre minimal associe à chaque ressource partagée : groupe, kind, namespace, nom ou motif, Application et AppProject propriétaires, approbateur, stratégie de prune, sauvegarde et procédure de transfert. Namespaces, rôles partagés, webhooks, opérateurs et CRD demandent une attribution unique. Supprimer une CRD supprime tous ses objets personnalisés, et la recréer repart d'une liste vide. Dans le code 3.5.3, la suppression en cascade d'une Application écarte les CRD, mais le prune n'a pas d'exception équivalente : une CRD retirée de Git doit porter Prune=confirm ou Prune=false.
Argo CD rattache une ressource à une Application par l'annotation argocd.argoproj.io/tracking-id, méthode par défaut, de la forme <application>:<groupe>/<kind>:<namespace>/<nom>. FailOnSharedResource=true fait échouer la synchronisation si une ressource est déjà appliquée par une autre Application, garde-fou pour les seules ressources suivies. Côté produit, le générateur de clusters cible aussi le cluster local, sauf sélection par étiquettes : faute de Secret, celui-ci y échappe ; en déclarer un rend son inclusion explicite.
Premier écueil : l'Application créée à la main
Trois écueils découlent directement de ces mécanismes. Le premier : des Applications créées à la main par kubectl apply, hors du chemin lu par la racine, ne portent pas son identifiant de suivi (aucun, ou un identifiant propre qui désigne une autre Application). Absentes du diff du parent, elles survivent au retrait de leur manifeste dans Git et continuent de réconcilier leurs workloads, sans revue.
Deux contrôles les rendent visibles. Le premier liste les Applications avec leur identifiant de suivi et leur propriétaire : une ligne sans l'un ni l'autre, ou dont l'identifiant ne nomme pas la racine, désigne un objet hors gouvernance.
kubectl get applications.argoproj.io -n argocd \
-o custom-columns='NAME:.metadata.name,TRACKING:.metadata.annotations.argocd\.argoproj\.io/tracking-id,OWNER:.metadata.ownerReferences[0].name'
argocd app resources bootstrap-root --orphanedLe second est la surveillance des orphelins activée sur le projet de la racine. Une ressource refusée par le projet n'est jamais orpheline : avec une liste blanche limitée à trois kinds, l'avertissement se concentre sur eux ; les objets posés hors bande s'excluent par ignore, et les Applications générées, qui portent une ownerReference, ne sont pas candidates. La métrique argocd_app_orphaned_resources_count en fait une alerte.
La correction consiste à choisir un propriétaire : placer le manifeste dans le chemin de la racine, qui retrouve l'objet par sa clé et l'adopte à la synchronisation suivante s'il ne porte aucun identifiant de suivi ; s'il porte celui d'une autre Application, la racine signale une ressource partagée et, avec FailOnSharedResource=true, sa synchronisation échoue : retirer d'abord l'annotation argocd.argoproj.io/tracking-id de l'objet, ou le sortir de l'autre Application sans le laisser pruner (annotation argocd.argoproj.io/sync-options: Prune=false posée d'abord sur l'objet), puis laisser la racine l'adopter. L'autre voie consiste à le supprimer explicitement après lecture de son finalizer. La prévention relève du RBAC Kubernetes : créer des applications, applicationsets ou appprojects dans le namespace d'Argo CD se réserve aux administrateurs et à une procédure d'urgence tracée.
Ordonner sans confondre synchronisation et santé
Argo CD distingue le statut de synchronisation (l'état vivant correspond-il à la cible ?), le statut de l'opération (a-t-elle réussi ?) et la santé (l'application fonctionne-t-elle ?) ; « Synced », « Succeeded » et « Healthy » ne se déduisent pas l'un de l'autre. La page de bootstrap le montre : une fois synchronisé, le parent apparaît Synced alors que ses enfants ne le sont pas.
Ce que font réellement phases et waves
Une synchronisation ordonne les ressources par phase, wave croissante, kind puis nom. Argo CD applique la première wave contenant une ressource OutOfSync ou non saine, attend, puis recommence. Ressources et hooks sont en wave 0 par défaut, et un délai de 2 secondes, réglable par ARGOCD_SYNC_WAVE_DELAY, sépare deux waves. La documentation prévient qu'une ressource non saine dans une première wave peut empêcher l'Application d'atteindre l'état sain ; dans le moteur 3.5.3, une ressource appliquée qui passe Degraded fait échouer l'opération, une ressource Progressing la fait attendre, et les waves suivantes ne sont pas appliquées.
Un hook PreSync en échec arrête l'opération ; un échec en phase Sync la marque Failed et déclenche les hooks SyncFail ; PostSync attend une application réussie et des ressources Healthy, et son échec marque lui aussi l'opération Failed. Une synchronisation sélective n'exécute aucun hook : un contrôle indispensable ne doit pas reposer sur un hook contournable.
Relayer la santé des enfants vers la racine
La vérification de santé intégrée de la ressource argoproj.io/Application a été retirée en 1.8. Sans elle, un enfant n'a pas de santé aux yeux de la racine : sa wave se termine dès que l'objet est appliqué. La documentation fournit le bloc à ajouter dans argocd-cm pour ordonner un App-of-Apps par waves :
data:
resource.customizations.health.argoproj.io_Application: |
hs = {}
hs.status = "Progressing"
hs.message = ""
if obj.status ~= nil then
if obj.status.health ~= nil then
hs.status = obj.status.health.status
if obj.status.health.message ~= nil then
hs.message = obj.status.health.message
end
end
end
return hsLe bloc relaie status.health, c'est-à-dire la pire santé des ressources immédiates de l'enfant ; il ne crée ni dépendance métier ni preuve fonctionnelle. Avec l'opérateur argocd-operator, ces personnalisations se déclarent dans sa ressource, qui remplace celles de argocd-cm. Côté enfant, quelques métadonnées suffisent :
# Exemple synthétique : métadonnées d'un enfant de la couche plateforme
metadata:
name: platform-certificats
namespace: argocd
labels:
app.kubernetes.io/part-of: bootstrap-root
annotations:
argocd.argoproj.io/sync-wave: "0"
argocd.argoproj.io/sync-options: Prune=confirm
finalizers:
- resources-finalizer.argocd.argoproj.ioL'étiquette part-of fait reconnaître l'enfant par l'interface, la wave l'ordonne, Prune=confirm impose une confirmation avant que la racine ne le supprime, et le finalizer fixe ce que sa suppression emportera.
Ordonner les Applications générées
Pour un ApplicationSet, l'équivalent s'appelle Progressive Syncs : une fonction en bêta depuis la 3.3.0, à activer explicitement, par exemple par applicationsetcontroller.enable.progressive.syncs: "true" dans argocd-cmd-params-cm. RollingSync groupe les Applications générées par étiquettes ; chaque étape attend que ses Applications soient Healthy, maxUpdate borne les mises à jour simultanées, et une étape à maxUpdate: 0 ne met à jour aucune des Applications qu'elle sélectionne. RollingSync désactive l'auto-sync des Applications générées, une Application qu'aucune étape ne sélectionne n'est jamais synchronisée par la stratégie, et deletionOrder: Reverse supprime les groupes en ordre inverse.
Lire la santé sans tout masquer
La santé d'une Application est la pire de ses ressources immédiates, dans l'ordre Healthy, Suspended, Progressing, Missing, Degraded, Unknown. Depuis la 3.4, une Application n'est Missing que si toutes ses ressources manquent : une alerte qui guettait Missing pour repérer une ressource absente doit surveiller OutOfSync.
Deuxième écueil : des statuts « Degraded » alarmants mais sans gravité, et une dérive permanente qui rend l'alerte inutile. La documentation donne un cas type : depuis la 3.2, un CronJob dont le dernier Job a échoué peut rendre l'Application Degraded, avec des oscillations possibles vers Healthy tant que des Jobs sont actifs. Avec le relais de santé, cet état remonte à la racine et bloque les waves suivantes pendant une synchronisation. La réponse documentée est étroite : l'annotation argocd.argoproj.io/ignore-healthcheck: "true" sur ce CronJob seul. Retirer le relais, ou couper l'alerte de la racine, éteindrait le signal de tous les enfants.
La dérive permanente suit la même logique : un contrôleur ou un webhook de mutation qui réécrit un champ laisse l'Application OutOfSync après chaque synchronisation. Une dérive de ce type sur des CRD se corrige par une règle d'exclusion limitée aux CRD concernées, pas par une mise en sourdine globale. ignoreDifferences se restreint par groupe, kind, nom et namespace, et vise un champ par pointeur JSON, expression jq ou gestionnaire de managedFields :
# Exemple synthétique : règle étroite dans l'Application qui porte les CRD
spec:
ignoreDifferences:
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
name: politiques.example.net
jqPathExpressions:
- .spec.conversion.webhook.clientConfig.caBundle
syncPolicy:
syncOptions:
- RespectIgnoreDifferences=trueRespectIgnoreDifferences=true étend l'exclusion à l'étape de synchronisation, pour une ressource déjà présente dans le cluster. La clé resource.customizations.ignoreDifferences.all, qui s'applique à toutes les Applications de l'instance, est au contraire la sourdine globale à éviter.
Préparer échec, suppression et restauration
Synchronisation automatique, prune et suppression en cascade restent trois décisions séparées jusqu'à la validation d'un scénario écrit. Les confondre ouvre la voie à l'incident que ce motif rend possible : une ligne retirée du dépôt de la racine qui supprime, par cascade, les workloads d'un enfant.
Supprimer une Application enfant
Le finalizer resources-finalizer.argocd.argoproj.io déclenche une suppression en cascade au premier plan (foreground) : chaque ressource reste présente jusqu'à la suppression de ses dépendants, et l'Application jusqu'à la disparition de ses ressources ; avec le suffixe /background, les ressources de premier niveau disparaissent aussitôt, l'Application est retirée dès qu'elles ont disparu et leurs dépendants (Pods, ReplicaSets…) sont nettoyés ensuite par le ramasse-miettes. Sans finalizer, les ressources restent en place. argocd app delete APP --cascade=false retire le finalizer et ne supprime que l'objet Application. Par ressource, Delete=false conserve un objet, tandis que Delete=confirm et Prune=confirm exigent une approbation, donnée par l'interface, la CLI ou l'annotation horodatée argocd.argoproj.io/deletion-approved.
Ce que devient une Application enfant retirée de Git
Le parcours suit un manifeste d'enfant retiré du dépôt de la racine, du prune jusqu'à la suppression en cascade ou au blocage du finalizer.
Schéma défilable horizontalement ; sa version textuelle complète suit.
Lire le schéma sous forme textuelle
- Le point de départ est le retrait, dans Git, du manifeste d'une Application enfant.
- Si l'objet n'est pas suivi par la racine, parce qu'il a été créé à la main, il reste hors du diff et rien n'est supprimé.
- S'il est suivi mais que la racine ne demande pas de prune, automatique ou manuel, la racine passe OutOfSync et l'enfant est conservé.
- Si le prune est demandé et que l'enfant porte
Prune=confirm, la synchronisation attend une confirmation ; sans cette option, ou après confirmation, l'Application enfant est supprimée. - Sans finalizer, ses ressources sont conservées mais ne sont plus réconciliées.
- Avec finalizer, le contrôleur lit d'abord le projet de l'Application ; s'il est illisible, l'Application reçoit une condition DeletionError et son finalizer reste bloqué.
- Si le projet est lisible et que le cluster de destination n'est plus connu d'Argo CD, le contrôleur retire le finalizer et les ressources restent en place, hors de toute gestion.
- Si le cluster est connu et que son état est lisible, la suppression en cascade s'engage, au premier plan ou en arrière-plan : les ressources sont supprimées, sauf les CRD, les objets en
Delete=falseouhelm.sh/resource-policy: keep; les objets enDelete=confirmattendent l'approbation. - Si l'état du cluster est illisible, l'Application reçoit aussi une condition DeletionError et son finalizer reste bloqué : dans les deux cas, il faut réparer la cause, ou supprimer sans cascade puis nettoyer à la main.
Ordre du prune et place des projets
Au prune, l'ordre des waves s'inverse : les waves hautes partent d'abord, et un échec arrête le traitement des waves inférieures. Des AppProjects placés dans une wave inférieure à celle des Applications sont donc créés avant elles et supprimés après. PruneLast=true repousse le prune dans une dernière wave implicite, où le moteur 3.5.3 regroupe toutes les suppressions sans ordre inversé : l'exemple de racine ne l'active pas. Le finalizer de l'AppProject reste le garde-fou : sans lui, un projet supprimé avant ses Applications bloque leur suppression, le contrôleur ne pouvant plus lire le projet.
Troisième écueil : le finalizer bloqué
Troisième écueil : des finalizers bloqués par des erreurs de comparaison. La FAQ officielle indique qu'Argo CD ne peut pas supprimer une Application s'il ne peut pas générer ses manifestes : il faut réparer le dépôt, ou supprimer avec --cascade=false puis nettoyer à la main. Dans le code 3.5.3, la cascade s'appuie sur les objets vivants suivis ; elle échoue avec une condition DeletionError si le projet ou l'état du cluster est illisible, attend tant qu'une ressource gérée reste bloquée derrière son propre finalizer, et s'arrête sur un hook PreDelete en échec. Si le projet est lisible et que le cluster de destination n'est plus déclaré dans Argo CD, le même code retire au contraire le finalizer sans rien supprimer.
# Lire le finalizer et les conditions avant toute intervention
kubectl get application -n argocd platform-certificats \
-o jsonpath='{.metadata.finalizers}{"\n"}{range .status.conditions[*]}{.type}{": "}{.message}{"\n"}{end}'
argocd app resources platform-certificats --output tree=detailed
# Abandon délibéré de la cascade : ressources à inventorier puis supprimer à la main
argocd app delete platform-certificats --cascade=falseLa bonne réponse répare la cause : dépôt, projet, accès au cluster, ou finalizer de la ressource dépendante levé par son propre contrôleur. Retirer le finalizer de l'Application par kubectl patch équivaut à une suppression sans cascade : ses ressources restent hors de toute gestion, ce qui reproduit le premier écueil sous une autre forme.
ApplicationSet : ownerReferences et politiques
Chaque Application générée porte une ownerReference vers son ApplicationSet et, sauf preserveResourcesOnDeletion: true, le finalizer de cascade : supprimer l'ApplicationSet supprime ses Applications, puis leurs workloads. kubectl delete applicationset NOM --cascade=orphan conserve les Applications, mais leur finalizer gouverne toujours une suppression ultérieure.
La politique applicationsSync borne ce que le contrôleur fait pendant sa réconciliation : create-only, create-update, create-delete ou sync, par défaut. L'argument --policy du contrôleur l'emporte sur ce champ, sauf si applicationsetcontroller.enable.policy.override est activé. create-only et create-update n'empêchent pas le ramasse-miettes de supprimer les Applications par ownerReference quand l'ApplicationSet disparaît ; la documentation demande alors un finalizer sur l'ApplicationSet et une suppression en arrière-plan.
Le risque quotidien reste le changement de sélection : retirer une étiquette d'un Secret de cluster ou renommer un dossier lu par un générateur Git fait sortir des Applications du rendu, que les politiques sync et create-delete suppriment avec leurs workloads. Avant toute fusion qui touche un générateur ou ses données, argocd appset generate ou argocd appset create --dry-run listent les Applications rendues, à comparer avec l'existant.
Restaurer le plan de contrôle, pas les données
D'après le code 3.5.3, argocd admin export contient les ConfigMaps d'Argo CD (argocd-cm, RBAC, hôtes SSH connus, certificats TLS), ses Secrets, dont les identifiants de dépôts et de clusters, ainsi que les AppProjects, Applications et ApplicationSets : un fichier sensible, à chiffrer et à placer sous contrôle d'accès. La procédure officielle exécute l'export et l'import avec l'image de la version d'Argo CD en service, et signale que l'export n'échoue pas s'il vise un mauvais namespace. argocd admin import accepte --dry-run, et --prune supprime les Secrets, Applications et projets absents de la sauvegarde. Rien de cela ne restaure un volume ou une donnée applicative : un retour Git reconstruit des déclarations, pas des données.
Campagne d'essais avant production
Sur un environnement jetable, chaque scénario se joue, résultat conservé, avant d'activer auto-sync et prune en production :
| Scénario | Résultat attendu d'après la documentation et le code 3.5.3 |
|---|---|
| Enfant Degraded dans une wave basse | Opération de la racine en échec, waves suivantes non appliquées |
Enfant retiré de Git avec Prune=confirm | Synchronisation en attente de confirmation |
| Suppression foreground, background, puis sans cascade | Ressources et dépendants supprimés avant le retrait de l'Application (foreground) ; ressources de premier niveau supprimées avant le retrait, dépendants nettoyés après (background) ; conservées sans cascade |
| Étiquette retirée d'un cluster sélectionné | Applications générées supprimées sous sync ou create-delete |
ApplicationSet supprimé avec --cascade=orphan | Applications conservées, finalizers toujours présents |
| Accès au cluster d'un enfant rompu, puis suppression | DeletionError, finalizer bloqué ; reprise par réparation ou --cascade=false |
| Projet lisible, cluster d'un enfant retiré d'Argo CD, puis suppression | Finalizer retiré, ressources conservées hors gestion |
| Export, puis import à blanc sur une instance de même version | Liste des objets restaurés conforme à l'inventaire |
La recette se clôt quand chaque écart observé a une décision et un responsable.
Sources officielles et limites de lecture
Faits datés
Les affirmations de ce guide renvoient à la documentation stable d'Argo CD, construite depuis le tag v3.5.3, et au code du même tag quand la documentation se tait ; ces sources ont été vérifiées le . Les pages « stable » changent à chaque version : une procédure de bootstrap doit citer la version installée. La 3.6.0-rc1, publiée le 16 septembre 2026, annonce déjà une santé des ressources en suppression qui liste leurs finalizers, et des Progressive Syncs qui attendent le rafraîchissement de toutes les Applications.
Vérifié le
Ce guide ne mesure pas la charge des contrôleurs, ne traite ni les Applications hors du namespace d'Argo CD ni Flux, et ne remplace pas une recette fonctionnelle : Healthy n'établit pas qu'un service répond. Les manifestes et commandes sont synthétiques et ne décrivent aucun déploiement client. Sur la propriété des champs partagés entre Git et une console, voir « Piloter la configuration Keycloak en GitOps : adoption, dérive et suppression de champs » ; la santé et les orphelins au-delà du bootstrap, ainsi que la place de ce découpage dans une plateforme complète, relèvent d'autres guides en préparation.
Sources
- Cluster Bootstrapping, Argo CD (documentation stable, v3.5.3), https://argo-cd.readthedocs.io/en/stable/operator-manual/cluster-bootstrapping/, consulté le 28/09/2026.
- Projects, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/projects/, consulté le 28/09/2026.
- Declarative Setup (Projects, App of Apps, Manage Argo CD Using Argo CD), Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/declarative-setup/, consulté le 28/09/2026.
- Getting Started, Argo CD, https://argo-cd.readthedocs.io/en/stable/getting_started/, consulté le 28/09/2026.
- Sync Phases and Waves, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/sync-waves/, consulté le 28/09/2026.
- Sync Options, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/sync-options/, consulté le 28/09/2026.
- Resource Health, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/health/, consulté le 28/09/2026.
- Core Concepts, Argo CD, https://argo-cd.readthedocs.io/en/stable/core_concepts/, consulté le 28/09/2026.
- v3.1 to 3.2 (CronJob Health), Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/3.1-3.2/, consulté le 28/09/2026.
- v3.2 to 3.3 (ApplicationSet CRD et client-side apply), Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/3.2-3.3/, consulté le 28/09/2026.
- v3.3 to 3.4 (Applications with Missing health status), Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/3.3-3.4/, consulté le 28/09/2026.
- v3.4 to 3.5 (Source Integrity, Helm 4), Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/upgrading/3.4-3.5/, consulté le 28/09/2026.
- App Deletion, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/app_deletion/, consulté le 28/09/2026.
- Application Pruning & Resource Deletion (ApplicationSet), Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Application-Deletion/, consulté le 28/09/2026.
- Controlling if/when the ApplicationSet controller modifies Application resources, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Controlling-Resource-Modification/, consulté le 28/09/2026.
- Progressive Syncs, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Progressive-Syncs/, consulté le 28/09/2026.
- ApplicationSet Security, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Security/, consulté le 28/09/2026.
- Generators, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Generators/, consulté le 28/09/2026.
- Cluster Generator, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Generators-Cluster/, consulté le 28/09/2026.
- Git Generator, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/applicationset/Generators-Git/, consulté le 28/09/2026.
- Resource Tracking, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/resource_tracking/, consulté le 28/09/2026.
- Diffing Customization, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/diffing/, consulté le 28/09/2026.
- Orphaned Resources Monitoring, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/orphaned-resources/, consulté le 28/09/2026.
- RBAC Configuration, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/rbac/, consulté le 28/09/2026.
- Metrics, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/metrics/, consulté le 28/09/2026.
- FAQ (I've deleted/corrupted my repo and can't delete my app), Argo CD, https://argo-cd.readthedocs.io/en/stable/faq/, consulté le 28/09/2026.
- Disaster Recovery, Argo CD, https://argo-cd.readthedocs.io/en/stable/operator-manual/disaster_recovery/, consulté le 28/09/2026.
- argocd appset generate Command Reference, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_appset_generate/, consulté le 28/09/2026.
- argocd app diff Command Reference, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_app_diff/, consulté le 28/09/2026.
- argocd app delete Command Reference, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_app_delete/, consulté le 28/09/2026.
- argocd app resources Command Reference, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_app_resources/, consulté le 28/09/2026.
- argocd admin import Command Reference, Argo CD, https://argo-cd.readthedocs.io/en/stable/user-guide/commands/argocd_admin_import/, consulté le 28/09/2026.
- controller/appcontroller.go au tag v3.5.3 (suppression en cascade, DeletionError, cluster de destination inconnu, finalizer d'AppProject, ressources orphelines), argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/blob/v3.5.3/controller/appcontroller.go, consulté le 28/09/2026.
- gitops-engine/pkg/sync/sync_context.go au tag v3.5.3 (santé des ressources en cours de synchronisation, ordre du prune, PruneLast), argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/blob/v3.5.3/gitops-engine/pkg/sync/sync_context.go, consulté le 28/09/2026.
- cmd/argocd/commands/admin/backup.go au tag v3.5.3 (contenu de l'export et de l'import), argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/blob/v3.5.3/cmd/argocd/commands/admin/backup.go, consulté le 28/09/2026.
- Releases et tags v3.5.3, v3.6.0-rc1 et stable, argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/releases, consulté le 28/09/2026.
- v3.5 to 3.6 (notes de montée de version au tag v3.6.0-rc1), argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/blob/v3.6.0-rc1/docs/operator-manual/upgrading/3.5-3.6.md, consulté le 28/09/2026.
- Extend the Kubernetes API with CustomResourceDefinitions (Delete a CustomResourceDefinition), Kubernetes, https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/, consulté le 28/09/2026.
- server/application/application.go au tag v3.5.3 (suppression sans cascade et retrait du finalizer), argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/blob/v3.5.3/server/application/application.go, consulté le 28/09/2026.
- controller/cache/cache.go au tag v3.5.3 (lecture des objets vivants et erreur de synchronisation du cache de cluster), argoproj/argo-cd sur GitHub, https://github.com/argoproj/argo-cd/blob/v3.5.3/controller/cache/cache.go, consulté le 28/09/2026.