Skip to content

chore(upgrade-argocd): bump ArgoCD chart to 10.7.2 / ArgoCD v3.5.2 - #1097

Open
iliesmrf wants to merge 4 commits into
mainfrom
chore/upgrade-argocd
Open

iliesmrf wants to merge 4 commits into
mainfrom
chore/upgrade-argocd

Conversation

@iliesmrf

@iliesmrf iliesmrf commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

Issues liées

Issues numéro : #1098

Quel est le comportement actuel ?

Le release Argo CD du cluster workload est sur le chart 8.5.6 (Argo CD v3.1.7).

Le repo-server embarque un initContainer maison helm-login qui remplace le binaire helm par un wrapper bash, et un Secret helm-docker-registry-secret qui porte les credentials Docker Hub pour ce wrapper.

Aucune NetworkPolicy n'existe dans le namespace Argo CD.

Quel est le nouveau comportement ?

Bump du chart Argo CD du cluster workload de 8.5.6 (v3.1.7) à 10.7.2 (v3.5.2), soit une chaîne de releases mineures au sein de la même ligne majeure (3.x). argocdInfra est hors périmètre : il reste en 8.5.6 et sera traité séparément.

Trois ajustements de nos templates accompagnent le bump, un par commit pour que la review se fasse commit par commit :

Commit Fichier Effet
chore(upgrade-argocd) releases.yaml argocd.chartVersion 8.5.6 → 10.7.2
refactor(argocd) values/00-main.j2 −71 : suppression du shim helm-login
refactor(argocd) templates/helm-docker-registry-secret.yml.j2 −11 : suppression du Secret devenu mort
chore(argocd) values/10-networkpolicy.j2 +13 : global.networkPolicy.create repassé à false

Le détail et la justification de chaque décision sont en fin de description.

Cette PR introduit-elle un breaking change ?

Pas pour la configuration de ce repo. Oui pour le rollout, sur un point précis.

1. Le Deployment haproxy de redis-ha doit être recréé à la main. Le chart 9.1.0 ajoute component: haproxy au selector.matchLabels du Deployment <release>-redis-ha-haproxy. Un selector de Deployment est immuable : le sync échouera sur field is immutable tant que l'ancien objet n'est pas supprimé. Procédure détaillée plus bas. Pas de coupure Redis : le Service haproxy sélectionne sur app + release uniquement, sans component, avant comme après — les anciens pods orphelins et les nouveaux servent le trafic en parallèle le temps de la bascule.

2. La CRD ApplicationSet dépasse la limite d'un apply client-side (1,03 Mo → 1,39 Mo, breaking change de la 3.3). Vérifié sur cluster : nos Applications synchronisent déjà avec ServerSideApply=true, et la CRD en place ne porte aucune annotation last-applied-configuration (0 octet, unique field manager : argocd-controller / Apply). Le cas est donc déjà couvert. En cas de 409 au premier sync, ajouter ponctuellement Force=true.

3. Point d'attention hors breaking change : le défaut timeout.reconciliation passe de 180s à 120s, avec un jitter de 60s. Nous ne le surchargeons pas, donc nous héritons du nouveau défaut : environ 50 % de réconciliations en plus. Volontairement non figé dans cette PR — c'est un arbitrage de charge, voir la question ouverte en fin de description.

Autres informations

Journal des décisions

Le bump lui-même

argo_app_version n'est codé en dur nulle part : roles/gitops/rendering-apps-files/tasks/preliminary.yml le dérive de la version de chart.

helm search repo -l argo --version 8.5.6   → argo/argo-cd  8.5.6   v3.1.7
helm search repo -l argo --version 10.7.2  → argo/argo-cd  10.7.2  v3.5.2

Toutes les images qui s'appuient dessus suivent donc automatiquement le chart. C'est ce qui rend le point suivant nécessaire.

Suppression du shim helm-login — la version longue

Le repo-server portait un initContainer maison qui copiait le binaire helm hors de l'image Argo CD, l'enrobait d'un script bash, et montait ce wrapper par-dessus /usr/local/bin/helm. Il a été introduit par f62a90c (avril 2025) et il n'était pas gratuit : il réglait deux vrais problèmes.

Problème A — helm registry login recevait un chemin au lieu d'un hôte. Argo CD v3.1.7, util/helm/cmd.go:79 :

func (c *Cmd) RegistryLogin(repo string, creds Creds) (string, error) {
	args := []string{"registry", "login"}
	args = append(args, repo)        // l'URL COMPLÈTE du dépôt

Notre secret oci-dockerhub-creds vaut url: registry-1.docker.io + name: bitnamicharts, ce qui produisait helm registry login registry-1.docker.io/bitnamicharts. Helm refuse : il attend un hôte de registre, pas un hôte + chemin. Le wrapper interceptait exactement cette forme d'argv et la réécrivait en hôte nu.

Problème B — les builds de dépendances n'avaient pas les credentials. L'initContainer faisait aussi un helm registry login anticipé dans /helm-working-dir (HELM_CONFIG_HOME, partagé avec le repo-server) pour que helm dependency build puisse s'authentifier sur les charts tenants dépendant de oci://registry-1.docker.io/bitnamicharts/*.

Les deux sont corrigés en amont aujourd'hui.

Problème A — Argo CD 3.3 a ajouté getHelmRegistry(), dont le commentaire décrit mot pour mot ce que fait notre wrapper :

"extracts the registry host from a Helm repository URL. This is because it is required for the helm registry login command to use the registry host rather than the full URL."

Vérifié : absent en v3.2.6, présent en v3.3.9, v3.4.6, v3.5.2. En v3.5.2, RegistryLogin devient :

registry, err := c.getHelmRegistry(repo)
args = append(args, registry)

Problème B — DependencyBuild() (util/helm/helm.go:80, v3.5.2) parcourt tous les dépôts configurés et encadre le build de dépendances par un RegistryLogin / RegistryLogout pour chaque dépôt OCI disposant d'un username et d'un password. Notre oci-dockerhub-creds remplit la condition.

Et le conserver deviendrait nuisible. Le chart passe à Argo CD v3.5.2, qui embarque Helm 4.2.1. La 3.5 a aussi changé l'invocation : --password-stdin au lieu de --password, plus un --plain-http conditionnel. Ces appels transiteraient par un script bash écrit pour la signature Helm 3, avec une expansion d'arguments en ${args[@]} non quoté et un binaire copié qui masque le vrai. C'est du risque nouveau, pris pour contourner un bug qui n'existe plus.

Périmètre d'impact. L'authentification Docker Hub est inchangée : elle passe désormais uniquement par oci-dockerhub-creds, rendu inconditionnellement dans repo-creds.yml.j2, qui lit le même chemin Vault dockerAccount. Les variables de proxy du repo-server ne bougent pas : elles viennent de 10-proxy.j2 (repoServer.env: *extraEnvVars), jamais de l'initContainer.

Suppression de helm-docker-registry-secret

L'initContainer en était le seul consommateur : il en lisait username/password vers HELM_USER / HELM_PASSWORD. Le shim retiré, plus rien ne le référence — ni dans ce rôle, ni dans les repos gitops générés (vérifié par grep sur les deux). Le laisser maintiendrait une copie redondante des credentials Docker Hub dans le namespace Argo CD, alors qu'ils sont déjà exposés à Argo CD par oci-dockerhub-creds, qui lit le même chemin Vault.

Note de rollout : les Applications qui déploient ce chart tournent avec prune activé, le Secret disparaît donc des clusters au premier sync.

Commit isolé volontairement, pour pouvoir le revert seul si l'on préfère conserver le Secret.

NetworkPolicies laissées désactivées

Le chart 10.0.0 bascule global.networkPolicy.create de false à true. Le défaut amont est sain, mais c'est un changement de posture réseau sans rapport avec le bump de version, et il atterrirait sur tous les clusters gérés dans le même sync que quatre releases mineures d'Argo CD. Si un flux casse ensuite, on veut savoir laquelle des deux causes est en jeu.

Constaté sur cluster : le namespace Argo CD n'a aujourd'hui aucune NetworkPolicy ni CiliumNetworkPolicy. On passerait donc de « tout ouvert » à « filtré » en une étape.

Repassé à false dans un 10-networkpolicy.j2 dédié, avec les flux à valider documentés en commentaire dans le template, pour que l'activation ultérieure soit un diff court et relisible. Un opérateur peut toujours l'activer par environnement via dsc.argocd.values, que le rôle combine fusionne en dernier.

Mesuré : le rendu du chart 10.7.2 avec nos values produit 4 NetworkPolicies sans ce fichier, 0 avec.

Pour mémoire, ce que le chart poserait si on l'activait : le argocd-server reste en ingress: [{}] donc non restreint, les ports metrics restent scrapables depuis n'importe quel namespace, et le seul vrai resserrage porte sur le gRPC du repo-server, limité à server / application-controller / applicationset-controller.

Revue des breaking changes amont (3.1 → 3.5)

Chacun confronté à ce que nous configurons réellement :

Changement amont Nous concerne ?
9.0.0 — tous les défauts configs.params retirés Pas de changement de comportement. applicationsetcontroller.policy passe de sync à non défini, or sync est le défaut du contrôleur lui-même
9.1.0 — selector haproxy redis-ha incompatible avec l'immuabilité Oui — étape manuelle au rollout, voir ci-dessous
10.0.0 — networkPolicy.create à true Oui — traité dans cette PR
3.3 — CRD ApplicationSet au-delà de la limite client-side apply Déjà couvert : ServerSideApply=true et aucune annotation last-applied-configuration sur la CRD en place
3.4 — format de version de cluster vMajor.Minor.Patch Non — nos générateurs sont git + list, pas des cluster generators indexés sur la version k8s
3.4 — sémantique du statut de santé Missing Pas d'impact de configuration, mais les dashboards et alertes qui lisent la santé des Applications sont à relire après rollout
3.4 — conventions sémantiques OTEL mises à jour Les panels Grafana bâtis sur des noms de métriques OTEL peuvent demander un rafraîchissement
3.4 — Dex 2.45 Non — dex.enabled: false, on attaque Keycloak en OIDC direct
3.4 — go-oidc, ordre de vérification des tokens inversé Cas limite seulement : token expiré et clé JWKS déjà tournée → redirection vers la page de login au lieu du SSO
3.5 — Helm 4.2.1, OCI plus strict Nos deux dépôts OCI sont en HTTPS, aucun insecureOCIForceHttp nécessaire
3.5 — React 19, extensions UI à recompiler Non — nous n'installons aucune extension UI
3.5 — known_hosts SSH pour les dépôts sans credentials Non — dépôts HTTPS avec credentials
3.5 — GnuPG remplacé par Source Integrity Non — aucun signatureKeys nulle part
3.5 — impersonation étendue aux opérations serveur Non — aucun destinationServiceAccounts configuré
3.5 — type de réponse gRPC des API d'événements changé Non — la console consomme l'API REST, inchangée
argocd-cm — timeout.reconciliation 180s → 120s + jitter 60s Oui, hérité : voir la question ouverte en fin de description

Étape manuelle au rollout : haproxy redis-ha

Par cluster, une fois que le sync a échoué sur field is immutable :

# 1. orphelinage de l'ancien Deployment : les 3 pods continuent de servir
kubectl -n <ns-argocd> delete deploy <release>-redis-ha-haproxy --cascade=orphan

# 2. relancer le sync, puis vérifier le nouveau selector
kubectl -n <ns-argocd> get deploy <release>-redis-ha-haproxy \
  -o jsonpath='{.spec.selector.matchLabels}{"\n"}'      # contient désormais component: haproxy
kubectl -n <ns-argocd> rollout status deploy/<release>-redis-ha-haproxy --timeout=180s

# 3. nettoyer le ReplicaSet orphelin. Argo CD ne le prunera PAS : il ne porte pas
#    le label app.kubernetes.io/instance, il n'est donc pas suivi
kubectl -n <ns-argocd> get rs -l app=redis-ha-haproxy \
  -o custom-columns='NAME:.metadata.name,OWNER:.metadata.ownerReferences[0].name'
kubectl -n <ns-argocd> delete rs <celui-sans-owner>

Ne pas chercher à désactiver ServerSideDiff sur l'Application au préalable, comme le suggère la note amont : l'annotation provient de l'ApplicationSet, elle-même pilotée en GitOps, donc tout patch est réécrit. L'orphelinage suffit.

Vérifications effectuées

  • Les deux versions de chart rendues localement avec les values réelles, puis diffées manifeste par manifeste : aucune ressource ne disparaît, les 6 ServiceMonitors survivent, les ingress sont identiques, les ClusterRoles inchangés. Les seuls ajouts sont les 4 NetworkPolicies (désactivées ici) et des règles de leader election sur le Role de l'applicationset-controller.
  • Changement de selector haproxy confirmé par le rendu, et selector actuel confirmé sur cluster.
  • Selector du Service haproxy confirmé identique entre les deux versions — d'où l'absence de coupure.
  • CRD ApplicationSet : taille mesurée sur les deux rendus, et CRD en place inspectée (annotation last-applied-configuration et field managers).
  • Présence de getHelmRegistry bisectée sur v3.2.6 / v3.3.9 / v3.4.6 / v3.5.2.
  • Templates modifiés validés en YAML, lignes de contrôle Jinja retirées : repoServer ne porte plus que replicas: 3.

Ce que les relecteurs devraient regarder en premier

  1. Est-on d'accord que le shim est réellement obsolète ? L'argument repose sur getHelmRegistry() (3.3+) et sur DependencyBuild() qui fait lui-même le registry login. C'est de la lecture de code amont, pas une exécution : à valider sur un cluster de test en synchronisant un chart tenant qui tire une dépendance oci://registry-1.docker.io/bitnamicharts/*, avant d'aller en production.
  2. Laisser les NetworkPolicies désactivées est-il le bon arbitrage, ou veut-on les activer dans le même changement ?
  3. timeout.reconciliation à 120s : on accepte la charge supplémentaire, ou on le refige à 180s dans 00-main.j2 ?

@iliesmrf iliesmrf self-assigned this Sep 4, 2026
@omiladi
omiladi force-pushed the chore/upgrade-argocd branch from 9a610a6 to 8dc5b54 Compare September 21, 2026 13:27
@omiladi omiladi self-assigned this Sep 21, 2026
@omiladi
omiladi requested a review from KepoParis September 21, 2026 13:33
@omiladi
omiladi marked this pull request as ready for review September 21, 2026 13:34
@iliesmrf iliesmrf assigned KepoParis and unassigned iliesmrf and omiladi Oct 1, 2026
@KepoParis
KepoParis force-pushed the chore/upgrade-argocd branch from 8dc5b54 to 2c31c7e Compare October 7, 2026 12:56
iliesmrf and others added 4 commits October 8, 2026 18:21
Bumps the workload-cluster ArgoCD release from chart 8.5.6 (ArgoCD
v3.1.7) to 10.7.2 (v3.5.2), a chain of minor releases within the same
major line (3.x). argocdInfra is out of scope (not managed here).

Reviewed against the official upgrade guides (3.1->3.2, 3.2->3.3,
3.3->3.4, 3.4->3.5): none of the breaking changes touch our config
(RBAC policy.csv, oidc.config, resource.exclusions, OCI/Harbor repo
auth). timeout.reconciliation default drops 180s->120s (not
overridden here, more frequent reconciliation, non-breaking).

Operational note for rollout: the ApplicationSet CRD now exceeds the
client-side apply size limit (breaking change in 3.3), may need
server-side apply with --force-conflicts on first sync since ArgoCD
manages its own CRDs here when crds.install: true (argo_infra_ownership
is false on this release).
…n 3.3

The repo-server carried a custom `helm-login` initContainer that copied the
helm binary out of the Argo CD image, wrapped it in a bash script and mounted
that wrapper over /usr/local/bin/helm. It was introduced in f62a90c
(April 2025) to work around two Argo CD limitations, both of which are now
fixed upstream.

1. The wrapper rewrote argv[3] of `helm registry login`. In Argo CD v3.1.7
   (util/helm/cmd.go:79) RegistryLogin appended the full repository URL:

       args := []string{"registry", "login"}
       args = append(args, repo)

   With our `oci-dockerhub-creds` secret (url: registry-1.docker.io,
   name: bitnamicharts) that produced `helm registry login
   registry-1.docker.io/bitnamicharts`, which helm rejects because it wants a
   registry host, not a host+path. Argo CD 3.3 added getHelmRegistry(), whose
   own doc comment states the intent verbatim: "extracts the registry host
   from a Helm repository URL. This is because it is required for the `helm
   registry login` command to use the registry host rather than the full URL."
   Verified absent in v3.2.6, present in v3.3.9, v3.4.6 and v3.5.2.

2. The initContainer also ran an eager `helm registry login` into
   /helm-working-dir (HELM_CONFIG_HOME, shared with the repo-server) so that
   `helm dependency build` could authenticate for tenant charts depending on
   oci://registry-1.docker.io/bitnamicharts/*. Argo CD does this itself now:
   DependencyBuild() (util/helm/helm.go:80 in v3.5.2) walks every configured
   repository and calls RegistryLogin/RegistryLogout around the dependency
   build for each OCI repo that has a username and password.

Keeping the shim across this bump would actively hurt. The chart moves to
Argo CD v3.5.2, which bundles Helm 4.2.1, and 3.5 changed the invocation to
`--password-stdin` plus a conditional `--plain-http`. Those calls would be
funnelled through a bash wrapper written for the Helm 3 signature, expanding
arguments through an unquoted ${args[@]}, with a copied binary shadowing the
real one. That is new risk taken on to work around a bug that no longer
exists.

Docker Hub authentication is unchanged: it now flows solely through the
`oci-dockerhub-creds` repo-creds secret, which is rendered unconditionally in
repo-creds.yml.j2 and reads the same Vault dockerAccount path. Repo-server
proxy variables are unaffected, they come from 10-proxy.j2
(repoServer.env: *extraEnvVars), not from the initContainer.
The `helm-login` initContainer removed in the previous commit was the only
consumer of this Secret: it read username/password from it into HELM_USER and
HELM_PASSWORD. With the shim gone nothing references it, in this role or in
the generated gitops repositories.

Leaving it in place would keep a second copy of the Docker Hub credentials
sitting in the Argo CD namespace for no reason. The credentials are already
available to Argo CD through `oci-dockerhub-creds` in repo-creds.yml.j2,
which reads the very same Vault path (global/values#dockerAccount).

Note for rollout: the Argo CD Applications that deploy this chart run with
prune enabled, so the Secret is removed from the clusters on the first sync
after this change.
argo-cd chart 10.0.0 flips global.networkPolicy.create from false to true.
That is a sensible upstream default, but it is a network posture change that
has nothing to do with the version bump, and it would land on every managed
cluster in the same sync as four minor Argo CD releases. If a flow breaks we
want to know whether it is the upgrade or the policies.

Checked on the cpin-console-hp cluster: the dso-argocd namespace has no
NetworkPolicy and no CiliumNetworkPolicy today, so this would go from
unrestricted to filtered in one step.

Pinned back to false here, with the flows to validate documented in the
template so enabling it later is a small, reviewable change. Operators can
still opt in per environment through dsc.argocd.values, which the combine
role merges last.

Rendered chart 10.7.2 with our values: 4 NetworkPolicies without this file,
0 with it.
@KepoParis
KepoParis force-pushed the chore/upgrade-argocd branch from 2c31c7e to c487fd9 Compare October 8, 2026 16:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants