ApplicationSet : des applications en série
Pourquoi
À la leçon 4, chaque environnement de Signalements avait son fichier d'Application dans le dépôt gitops, presque identique à son voisin. Avec deux environnements, c'est supportable. Avec dix applications et trois environnements, ce sont trente fichiers qui ne diffèrent que par deux mots, et qui finissent par dériver comme les copies de workflows du cours GitHub Actions.
L'ApplicationSet remplace ces copies par un modèle et un générateur : le générateur produit une liste de jeux de paramètres (un par environnement, par cluster, par demande de fusion...), et le contrôleur crée une Application par jeu, à partir du modèle. Ajouter un environnement devient ajouter un répertoire ; un environnement d'aperçu par demande de fusion devient possible sans écrire une ligne de script.
C'est aussi un outil puissant au sens propre : un ApplicationSet crée et supprime des applications de lui-même, avec leurs ressources. Cette leçon montre ce que cela permet, et ce que cela détruit si l'on n'y prend pas garde.
Les concepts
Générateur, paramètres, modèle
flowchart LR
G["Générateur<br/>(répertoires Git, liste,<br/>demandes de fusion...)"] -->|"paramètres<br/>{path: environnements/recette}<br/>{path: environnements/production}"| T["Modèle<br/>d'Application"]
T --> A1["signalements-recette"]
T --> A2["signalements-production"]
| Générateur | Produit un jeu de paramètres par... | Exemple d'usage |
|---|---|---|
list | élément d'une liste écrite dans l'ApplicationSet | un petit nombre de valeurs fixes |
git (répertoires) | répertoire correspondant à un motif | un environnement par répertoire |
git (fichiers) | fichier de configuration (JSON, YAML) | une application par fichier de description |
cluster | cluster déclaré dans Argo CD | une application par cluster (leçon 7) |
pullRequest | demande de fusion ouverte | un environnement d'aperçu par demande de fusion |
scmProvider | dépôt d'une organisation | une application par dépôt |
matrix, merge | combinaison de deux générateurs | applications × environnements |
clusterDecisionResource, plugin | ressource ou service externe | cas avancés |
Le modèle s'écrit de préférence en modèles Go (goTemplate: true), avec l'option missingkey=error : une faute de frappe dans un paramètre fait alors échouer la génération, au lieu de produire silencieusement un champ vide.
Le cycle de vie
Le contrôleur d'ApplicationSet est lui-même une boucle de réconciliation : il régénère périodiquement la liste des paramètres, crée les Applications nouvelles, met à jour les existantes, et supprime celles qui ne sont plus générées. Les Applications générées lui appartiennent (référence de propriétaire), et, par défaut, elles portent le finalizer de suppression en cascade : supprimer une Application générée, c'est supprimer ses ressources.
En pratique
Un environnement par répertoire
L'ApplicationSet qui remplace les deux fichiers de la leçon 4 utilise le générateur de répertoires Git sur le dépôt de déploiement :
# gitops/applications/signalements.yaml
# Une application par répertoire de environnements/ dans le dépôt de déploiement.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: signalements
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- git:
repoURL: http://forgejo.forge.svc.cluster.local:3000/plateforme/signalements-deploiement.git
revision: main
directories:
- path: environnements/*
template:
metadata:
name: 'signalements-{{ .path.basename }}'
spec:
project: default
source:
repoURL: http://forgejo.forge.svc.cluster.local:3000/plateforme/signalements-deploiement.git
targetRevision: main
path: chart
helm:
releaseName: signalements
valueFiles:
- '../{{ .path.path }}/values.yaml'
destination:
server: https://kubernetes.default.svc
namespace: 'signalements-{{ .path.basename }}'
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- RespectIgnoreDifferences=truePour chaque répertoire environnements/<nom>, le générateur fournit .path.path (le chemin complet) et .path.basename (le dernier élément, recette ou production). Le modèle en tire le nom de l'application, le fichier de valeurs et le namespace.
Migrer sans redémarrer
Remplacer deux Applications par un ApplicationSet qui génère les mêmes noms doit être invisible pour le cluster : les Applications changent de propriétaire, pas de contenu. On note l'heure de démarrage des pods avant, pour vérifier après :
$ for e in recette production; do kubectl -n signalements-$e get pods -l app=signalements \
-o jsonpath='{range .items[*]}{.metadata.name} {.status.startTime}{"\n"}{end}'; done > pods-avant.txt
Pendant la préparation de ce cours, la première tentative de cette migration a mal tourné, de façon instructive : le commit a supprimé les deux fichiers d'Application sans ajouter le nouveau (le répertoire applications/, vidé, avait disparu, et l'écriture du fichier suivant a échoué). L'application racine, en élagage automatique, aurait pu supprimer les deux environnements. Elle n'a rien supprimé :
$ argocd app get racine -o json | jq -r '.status.conditions[]?|"\(.type): \(.message)"'
ComparisonError: Failed to load target state: failed to generate manifest for source 1 of 1: rpc error: code = Unknown desc = applications: app path does not exist
Un chemin de source qui n'existe plus est une erreur de rendu, pas un rendu vide : l'application passe à Unknown et rien n'est élagué. Les deux environnements ont continué de tourner. Le commit suivant a ajouté l'ApplicationSet :
$ git add applications && git commit -qm "Signalements : l'ApplicationSet" && git push -q origin main
$ argocd app get racine --refresh | grep -E "^Sync Status|ApplicationSet| Application"
Sync Status: Synced to main (81768c7)
argoproj.io Application argocd signalements-production Succeeded Pruned pruned
argoproj.io Application argocd signalements-recette Succeeded Pruned pruned
argoproj.io ApplicationSet argocd signalements Synced Healthy applicationset.argoproj.io/signalements created
$ kubectl -n argocd get applications -o custom-columns='NOM:.metadata.name,PROPRIETAIRE:.metadata.ownerReferences[0].kind'
NOM PROPRIETAIRE
racine <none>
signalements-production ApplicationSet
signalements-recette ApplicationSet
$ for e in recette production; do kubectl -n signalements-$e get pods -l app=signalements \
-o jsonpath='{range .items[*]}{.metadata.name} {.status.startTime}{"\n"}{end}'; done > pods-apres.txt
$ diff pods-avant.txt pods-apres.txt && echo "aucun pod redémarré"
aucun pod redémarré
La racine a élagué les deux anciennes Applications (sans finalizer de cascade, leurs ressources sont restées), l'ApplicationSet les a recréées sous les mêmes noms, et elles ont retrouvé leurs ressources grâce à l'annotation de suivi, qui porte le nom de l'application. Aucun pod n'a redémarré.
Ajouter et retirer un environnement
Note
Les lignes qui commencent par # dans les blocs suivants résument ce qu'a affiché une boucle de relevé (un kubectl get à intervalles réguliers), omise pour la lisibilité.
Ajouter un environnement de démonstration, c'est créer un répertoire :
$ mkdir -p environnements/demo
$ printf 'image:\n tag: "1.2.0"\nreplicas: 1\nenvironnement: demo\n' > environnements/demo/values.yaml
$ git add environnements && git commit -qm "Environnement de démonstration" && git push -q origin main
# application signalements-demo créée après ~155 s
$ ./version.sh demo
{"environnement":"demo","version":"1.2.0"}
Deux minutes et demie : le générateur Git réinterroge le dépôt toutes les trois minutes par défaut (un webhook le rend immédiat). Et le retirer, c'est supprimer le répertoire... avec une conséquence qu'il faut voir de ses yeux :
$ kubectl -n argocd get application signalements-recette -o jsonpath='finalizers : {.metadata.finalizers}{"\n"}'
finalizers : ["resources-finalizer.argocd.argoproj.io"]
$ git rm -rq environnements/demo && git commit -qm "Fin de l'environnement de démonstration" && git push -q origin main
# application supprimée après ~175 s
$ kubectl -n signalements-demo get all
No resources found in signalements-demo namespace.
Les Applications générées portent le finalizer de cascade. Retirer le répertoire a supprimé l'Application, et toutes ses ressources. Pour un environnement de démonstration, c'est le comportement voulu. Pour la production, cela veut dire qu'un git rm malencontreux, ou un déplacement de répertoire, détruit la production trois minutes plus tard.
Protéger les environnements
Deux réglages de l'ApplicationSet s'en chargent :
spec:
# Protections : ne jamais supprimer en cascade, ne jamais supprimer une application générée.
syncPolicy:
preserveResourcesOnDeletion: true
applicationsSync: create-update
goTemplate: true
# ...preserveResourcesOnDeletion: truen'ajoute plus le finalizer aux Applications générées : supprimer une Application laisse ses ressources en place.applicationsSync: create-updateinterdit au contrôleur de supprimer une Application qui n'est plus générée (il peut toujours en créer et en modifier). Les autres valeurs sontcreate-only,create-deleteetsync(la valeur par défaut, tout est permis).
Le même essai, avec ces protections :
$ kubectl -n argocd get application signalements-production -o jsonpath='finalizers production : {.metadata.finalizers}{"\n"}'
finalizers production :
$ git rm -rq environnements/demo && git commit -qm "Fin de l'environnement de démonstration" && git push -q origin main
$ kubectl -n argocd get application signalements-demo
signalements-demo Synced Healthy
$ kubectl -n signalements-demo get deploy,svc
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/signalements 1/1 1 1 4m23s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/signalements ClusterIP 10.96.18.87 <none> 80/TCP 4m25s
Le générateur ne produit plus que deux applications (son journal le dit : generated 2 applications), mais l'Application signalements-demo est conservée, ressources comprises. La suppression devient un geste explicite : kubectl -n argocd delete application signalements-demo, sans cascade puisque le finalizer n'est plus posé, puis le namespace.
Ces protections ne couvrent pas la suppression de l'ApplicationSet lui-même : ses Applications lui appartiennent (références de propriétaire), et Kubernetes les supprime avec lui. Avec preserveResourcesOnDeletion, leurs ressources restent en place, mais les Applications disparaissent. Pour retirer un ApplicationSet en gardant ses Applications, la documentation indique kubectl delete applicationset <nom> --cascade=orphan.
Un environnement d'aperçu par demande de fusion
Le générateur de demandes de fusion interroge l'API de la forge. Forgejo expose une API compatible avec celle de Gitea, que le générateur prend en charge :
# gitops/applications/apercus.yaml
# Un environnement d'aperçu par demande de fusion ouverte sur le dépôt de déploiement.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: apercus
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- pullRequest:
gitea:
owner: plateforme
repo: signalements-deploiement
api: http://forgejo.forge.svc.cluster.local:3000
requeueAfterSeconds: 30
template:
metadata:
name: 'apercu-{{ .number }}'
spec:
project: default
source:
repoURL: http://forgejo.forge.svc.cluster.local:3000/plateforme/signalements-deploiement.git
targetRevision: '{{ .head_sha }}'
path: chart
helm:
releaseName: signalements
valueFiles:
- ../environnements/recette/values.yaml
valuesObject:
environnement: 'apercu-{{ .number }}'
replicas: 1
postgresql:
enabled: false
destination:
server: https://kubernetes.default.svc
namespace: 'apercu-{{ .number }}'
syncPolicy:
automated:
prune: true
syncOptions:
- CreateNamespace=truetargetRevision: '{{ .head_sha }}': l'aperçu déploie exactement le dernier commit de la demande de fusion, et suit chaque nouveau commit.valuesObjectsurcharge les valeurs de la recette : une réplique, pas de base de données, un nom d'environnement propre à l'aperçu.requeueAfterSeconds: 30: la forge est interrogée toutes les 30 secondes.- Pas de
preserveResourcesOnDeletionici : un aperçu doit disparaître complètement avec sa demande de fusion.
Une développeuse ouvre une demande de fusion qui ajoute une sonde de vivacité au chart :
$ git switch -c fonction/sonde-vivacite
$ # ... ajout de livenessProbe dans chart/templates/deployment.yaml
$ git commit -qam "Sonde de vivacité" && git push -q origin fonction/sonde-vivacite
$ curl -sf ... -X POST .../repos/plateforme/signalements-deploiement/pulls \
-d '{"title":"Sonde de vivacité","head":"fonction/sonde-vivacite","base":"main"}'
demande de fusion n° 3 ouverte
# application apercu-3 créée 6 s après l'ouverture
$ argocd app list -o name
argocd/apercu-3
argocd/racine
argocd/signalements-production
argocd/signalements-recette
$ kubectl -n apercu-3 get deploy signalements -o jsonpath='{.spec.template.spec.containers[0].livenessProbe.httpGet.path}{"\n"}'
/sante
$ ...
{"environnement":"apercu-3","version":"1.2.0","stockage":"memoire"}
Six secondes après l'ouverture, un environnement complet tourne avec le chart de la demande de fusion : la personne qui relit peut tester le changement, pas seulement lire son diff. À la fusion :
$ curl -sf ... -X POST .../pulls/3/merge -d '{"Do":"merge","delete_branch_after_merge":true}'
fusion : HTTP 200
# aperçu supprimé 21 s après la fusion
$ kubectl -n apercu-3 get deploy
No resources found in apercu-3 namespace.
$ kubectl get namespace apercu-3
NAME STATUS AGE
apercu-3 Active 48s
L'aperçu a disparu, ressources comprises, mais le namespace est resté : Argo CD ne supprime pas les namespaces créés par CreateNamespace. Pour des aperçus, on ajoute un nettoyage (un hook PostDelete, ou une tâche planifiée qui supprime les namespaces apercu-* vides), ou l'on fait du namespace une ressource du chart, élaguée comme les autres.
Combiner : la matrice
Pour plusieurs applications sur plusieurs environnements, le générateur matrix combine deux générateurs. Avec templatePatch, une partie du modèle peut dépendre des paramètres, ici la synchronisation automatique, réservée à la recette :
# Toutes les combinaisons application × environnement.
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: plateforme
namespace: argocd
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- matrix:
generators:
- list:
elements:
- application: signalements
- application: annuaire
- list:
elements:
- environnement: recette
automatique: true
- environnement: production
automatique: false
template:
metadata:
name: '{{ .application }}-{{ .environnement }}'
spec:
project: default
source:
repoURL: 'http://forgejo.forge.svc.cluster.local:3000/plateforme/{{ .application }}-deploiement.git'
targetRevision: main
path: chart
helm:
valueFiles:
- '../environnements/{{ .environnement }}/values.yaml'
destination:
server: https://kubernetes.default.svc
namespace: '{{ .application }}-{{ .environnement }}'
templatePatch: |
{{- if .automatique }}
spec:
syncPolicy:
automated:
selfHeal: true
{{- end }}Avant d'appliquer un ApplicationSet, on vérifie ce qu'il générerait, sans rien créer :
$ kubectl apply --dry-run=server -f matrice.yaml
applicationset.argoproj.io/plateforme created (server dry run)
$ argocd appset generate matrice.yaml -o json | jq -r '.[] | "\(.metadata.name) \(.spec.destination.namespace) automatique=\(.spec.syncPolicy.automated != null)"'
signalements-recette signalements-recette automatique=true
signalements-production signalements-production automatique=false
annuaire-recette annuaire-recette automatique=true
annuaire-production annuaire-production automatique=false
La première commande valide le schéma ; la seconde exécute réellement les générateurs et montre les quatre Applications, avec la synchronisation automatique sur les seules recettes. C'est le réflexe à prendre avant toute modification d'un ApplicationSet en production.
Sous le capot
Le contrôleur d'ApplicationSet rend chaque générateur en une liste de paramètres, applique le modèle à chacun, puis compare la liste des Applications voulues à celle des Applications qu'il possède (par référence de propriétaire). Les différences donnent les créations, les mises à jour et les suppressions, filtrées par la politique applicationsSync. Les générateurs Git et de demandes de fusion sont rafraîchis périodiquement (trois minutes par défaut pour Git, requeueAfterSeconds pour les demandes de fusion), ou immédiatement par un webhook.
La documentation indique que la politique applicationsSync d'un ApplicationSet n'est prise en compte que si l'option enable-policy-override du contrôleur est activée, et la présente comme désactivée par défaut. Le code de la version 3.5.3 dit autre chose (ligne 303 de applicationset_controller.go, abrégée) :
command.Flags().BoolVar(&enablePolicyOverride, "enable-policy-override",
env.ParseBoolFromEnv("ARGOCD_APPLICATIONSET_CONTROLLER_ENABLE_POLICY_OVERRIDE", policy == ""), ...)La valeur par défaut est policy == "", évaluée à partir de la variable ARGOCD_APPLICATIONSET_CONTROLLER_POLICY, alimentée par la clé applicationsetcontroller.policy de argocd-cmd-params-cm : la politique de chaque ApplicationSet est respectée tant que l'administrateur n'a pas fixé de politique globale. C'est ce que confirme l'essai plus haut. Si une politique globale est fixée, elle s'impose à tous les ApplicationSet, sauf activation explicite de la surcharge.
Avec missingkey=error, une référence à un paramètre absent fait échouer la génération pour tout l'ApplicationSet, avec une condition ErrorOccurred=True : aucune Application n'est modifiée ni supprimée tant que l'erreur n'est pas corrigée. Sans cette option, le paramètre absent devient la chaîne <no value>, ce qui peut produire des noms ou des namespaces inattendus.
Pièges courants
Un environnement supprimé par un git rm. Les Applications générées portent par défaut le finalizer de cascade, et le contrôleur supprime les applications qui ne sont plus générées. Protégez les environnements durables avec preserveResourcesOnDeletion et applicationsSync: create-update.
Une Application générée « revient » après une modification manuelle. Le contrôleur d'ApplicationSet réécrit les Applications selon le modèle : une modification faite à la main sur une Application générée est annulée. On modifie le modèle, ou on exclut des champs (ignoreApplicationDifferences).
Le nouvel environnement n'apparaît qu'après trois minutes. Le générateur Git est rafraîchi périodiquement. Webhook, ou patience.
Les namespaces d'aperçu s'accumulent. CreateNamespace ne supprime pas ce qu'il crée. Prévoyez le nettoyage.
Deux générateurs produisent le même nom d'Application. La génération échoue pour éviter que deux jeux de paramètres se disputent une même Application. Incluez assez de paramètres dans le nom.
<no value> dans un nom ou un chemin. Un paramètre mal orthographié avec les modèles par défaut. goTemplate: true et missingkey=error.
Sécurité
Seuls les administrateurs devraient créer des ApplicationSet. C'est la recommandation explicite de la documentation : un ApplicationSet peut générer des Applications dans n'importe quel projet que son modèle désigne, y compris un projet privilégié, et un générateur peut contacter des API externes avec des secrets. Le dépôt qui les contient (gitops ici) doit être relu par l'équipe plateforme.
Le générateur de demandes de fusion déploie du code non relu. Par construction, un aperçu exécute le contenu d'une demande de fusion avant sa relecture. Sur un dépôt où n'importe qui peut ouvrir une demande de fusion (un dépôt public, une bifurcation), c'est l'équivalent de la pwn request du cours GitHub Actions : quelqu'un fait exécuter ce qu'il veut dans votre cluster. Restreignez le générateur (étiquettes de demande de fusion, filtres sur les branches ou le titre), placez les aperçus dans un projet aux droits très limités (leçon 9), dans des namespaces isolés par des politiques réseau, et sans accès aux secrets de production.
Ne jamais rendre le projet paramétrable. Un champ project: '{{ .projet }}' alimenté par une source que d'autres contrôlent permet de choisir le projet le plus privilégié.
En production
Chez Lyneko, chaque application a aujourd'hui son Application écrite à la main, ce qui suffit à cette échelle. L'ApplicationSet devient intéressant avec les environnements d'aperçu, ou si les applications passent à plusieurs environnements chacune ; le générateur de répertoires Git ou la matrice remplacent alors les copies.
Les aperçus coûtent des ressources. Chaque demande de fusion ouverte occupe un namespace et des pods. Sur un petit cluster comme celui de Lyneko, où la mémoire et le disque sont comptés, on limite les aperçus (une étiquette apercu à poser explicitement sur la demande de fusion, filtrée par le générateur) et on les réduit au minimum (une réplique, pas de base, ou une base partagée de démonstration).
La synchronisation progressive. En bêta depuis la 3.3, la stratégie RollingSync d'un ApplicationSet synchronise les applications générées par groupes successifs (d'abord la recette, puis une région, puis le reste), en attendant que chaque groupe soit sain. Elle s'active explicitement dans la configuration du contrôleur, et désactive la synchronisation automatique des Applications générées : c'est l'ApplicationSet qui décide quand chaque groupe se synchronise.
Exercices
1. Transformez l'ApplicationSet signalements pour qu'il n'utilise que la synchronisation automatique en recette, et une synchronisation manuelle en production.
Solution
Retirer automated du modèle et l'ajouter par templatePatch selon le répertoire :
templatePatch: |
{{- if eq .path.basename "recette" }}
spec:
syncPolicy:
automated:
prune: true
selfHeal: true
{{- end }}Vérifier avec argocd appset generate avant de pousser.
2. Pour le générateur de demandes de fusion, faites en sorte que seules les demandes de fusion portant l'étiquette apercu créent un environnement.
Solution
Le fournisseur Gitea du générateur accepte une liste d'étiquettes (champ labels, sous gitea:) :
- pullRequest:
gitea:
owner: plateforme
repo: signalements-deploiement
api: http://forgejo.forge.svc.cluster.local:3000
labels:
- apercu
requeueAfterSeconds: 30Seules les demandes de fusion portant l'étiquette créent un aperçu ; retirer l'étiquette supprime l'aperçu. Poser une étiquette demandant en général un droit sur le dépôt, c'est aussi une barrière contre les demandes de fusion de personnes extérieures.
3. Avec les protections de cette leçon, comment supprime-t-on réellement un environnement devenu inutile ?
Solution
Supprimer son répertoire ne suffit plus. Après l'avoir retiré de Git : supprimer l'Application à la main (kubectl -n argocd delete application signalements-<nom>, sans cascade puisque le finalizer n'est plus posé), puis supprimer le namespace et ce qu'il contient. Si l'on veut une suppression complète par Argo CD, on peut poser temporairement le finalizer de cascade sur l'Application avant de la supprimer. C'est volontairement en plusieurs gestes : la suppression d'un environnement doit être une décision.
4. Le générateur de répertoires utilise environnements/*. Que se passe-t-il si quelqu'un crée environnements/archives/ancienne-recette/values.yaml ? Et environnements/notes.md ?
Solution
* ne traverse pas les / : environnements/archives est un répertoire correspondant, et devient une application signalements-archives, qui échouera à trouver environnements/archives/values.yaml (ComparisonError). notes.md est un fichier, pas un répertoire : ignoré. On peut exclure des répertoires avec une entrée exclude: true dans directories.
5. Pourquoi la migration de deux Applications vers l'ApplicationSet n'a-t-elle redémarré aucun pod ? Qu'est-ce qui aurait changé si le modèle avait produit signalements-env-recette au lieu de signalements-recette ?
Solution
Les Applications générées portent les mêmes noms que les anciennes ; les ressources, marquées par une annotation de suivi qui contient le nom de l'application, sont reconnues comme les leurs, et leur contenu est identique : rien à appliquer. Avec un autre nom, la nouvelle Application aurait trouvé des ressources marquées au nom d'une autre application : elle les aurait considérées comme ne lui appartenant pas, puis réécrit leur annotation à la synchronisation, et les anciennes Applications, si elles avaient encore existé avec leur finalizer, auraient pu les supprimer. Garder les noms est la clé d'une migration sans interruption.
Récapitulatif
- Un ApplicationSet = un générateur (liste, répertoires Git, demandes de fusion, clusters, matrice...) et un modèle d'Application ; écrivez les modèles en Go avec
missingkey=error. - Remplacer des Applications par un ApplicationSet qui génère les mêmes noms ne redémarre rien.
- Par défaut, les Applications générées portent le finalizer de cascade, et le contrôleur supprime celles qui ne sont plus générées : un
git rmpeut détruire un environnement. preserveResourcesOnDeletion: trueetapplicationsSync: create-updateprotègent les environnements durables (respecté par défaut tant qu'aucune politique globale n'est fixée).- Le générateur de demandes de fusion crée un aperçu par demande, détruit à la fermeture ; il exécute du code non relu, à cloisonner.
argocd appset generatemontre ce qu'un ApplicationSet produirait, avant de l'appliquer.
Pour aller plus loin
- Argo CD, Generators : tous les générateurs et leurs paramètres.
- Argo CD, ApplicationSet Security : les risques et les recommandations.
- Leçon suivante : Plusieurs clusters.
Sources
- Argo CD, ApplicationSet Controller
- Argo CD, Generators (Git, List, Matrix, Pull Request)
- Argo CD, Pull Request Generator (Gitea)
- Argo CD, Application Deletion (ApplicationSet)
- Argo CD, Controlling Resource Modification (applicationsSync)
- argoproj/argo-cd v3.5.3, cmd/argocd-applicationset-controller (valeur par défaut de enable-policy-override)
- Argo CD, ApplicationSet Security
- Argo CD, Go Template et templatePatch