Deux environnements, un seul ApplicationSet

La plupart des montages GitOps que je reprends se ressemblent : une application ArgoCD par environnement, un fichier de values par environnement, et une production mise à jour à la seconde où quelqu’un fusionne sur la bonne branche. Le pipeline dit honnêtement ce qu’il fait. Il ne dit pas honnêtement ce que coûte une erreur.

Sur ma propre plateforme, je voulais trois choses en même temps : une seule définition du déploiement, un environnement de développement qui avance seul, et une production qui ne peut pas changer sans qu’un humain le décide.

Un ApplicationSet, deux environnements

Toute la livraison tient dans un ApplicationSet avec un générateur list :

generators:
  - list:
      elements:
        - env: development
          namespace: interview-challenger-development
          valuesFile: envs/development/values.yaml
        - env: production
          namespace: interview-challenger-production
          valuesFile: envs/production/values.yaml

Chaque élément produit un nom d’application, un namespace et le fichier de values à appliquer. Ajouter un environnement, c’est une entrée de liste, pas un manifeste de plus à copier puis à laisser diverger.

Le chart vit dans le dépôt applicatif, à côté du code qu’il déploie. Les values vivent dans un dépôt de configuration séparé, parce qu’elles changent pour des raisons que le code ignore : un nouveau tag d’image, un nombre de réplicas, un feature flag.

Cette séparation impose une application multi-source :

sources:
  - repoURL: https://github.com/…/interview-challenger.git
    targetRevision: main
    path: deploy/charts/interview-challenger
    helm:
      valueFiles:
        - $configrepo/envs/development/values.yaml
  - repoURL: https://github.com/…/interview-challenger-gitops.git
    targetRevision: main
    ref: configrepo

ref: configrepo, c’est le détail que tout le monde oublie. Sans lui, le chart ne peut pas lire les values d’un autre dépôt, et les deux dépôts finissent par refusionner.

Où se trouve le garde-fou

Les deux applications synchronisent automatiquement, avec prune et selfHeal. Dit comme ça, c’est irresponsable pour la production — jusqu’à ce qu’on regarde où se trouve l’approbation.

La production n’est pas protégée en bloquant la synchronisation. Elle est protégée parce que la seule chose qui modifie la production est une pull request sur le dépôt de configuration, et que cette pull request doit être fusionnée par un humain. Une fois fusionnée, ArgoCD fait ce qu’il sait faire : amener le cluster à l’état du fichier.

Je préfère ça au sync manuel dans ArgoCD, et je défends le choix :

  • Le sync manuel cache la dérive. Un cluster non synchronisé ressemble à un cluster à jour, dans tous les tableaux de bord que vous possédez.
  • Le sync manuel déplace le garde-fou dans un outil qui ne se relit pas. Une approbation enfouie dans une interface ne laisse ni diff, ni auteur, ni raison.
  • Une pull request laisse les trois. Qui, quoi, pourquoi — et elle se revert.

La règle que j’applique : protéger le changement, pas le mécanisme qui l’applique.

Ce que le pipeline fait avant que la PR existe

Le workflow de release construit les images, les tague avec le SHA du commit — jamais latest —, les pousse dans le registre, puis ouvre lui-même les pull requests de déploiement. Le développement est en auto-merge. La production est ouverte et laissée en attente.

Rien n’est déployé par un humain qui tape un tag dans un formulaire. Le tag est un fait sur le code, et la pull request est le seul endroit où la décision se prend.

Quand c’est trop

Deux environnements, un chart et un dépôt de config, c’est à peu près la bonne taille pour un produit avec de vrais utilisateurs et une seule équipe. C’est trop pour un projet personnel qui déploie une fois par mois : là, un docker compose up et une sauvegarde sont plus honnêtes.

Le schéma vaut le coup quand trois conditions sont réunies : plus d’un environnement, plus d’une personne capable de fusionner, et un coût réel à se tromper en production. Si l’une des trois est fausse, la cérémonie n’achète rien.

← Tous les articles