Who am I

Le couteau suisse à l'heure de l'IA

ArgoCD Plugin Filter : contrôler vos déploiements cluster par cluster

EN REVIEW

Un plugin ArgoCD pour activer ou désactiver finement vos déploiements sur chaque cluster via un simple fichier JSON versionné.

31 December 2024
argocdkubernetespythongitops

J’ai quatre clusters Kubernetes. Je veux déployer mon app sur prod-eu et prod-us, mais pas sur staging ni dev. Avec les ApplicationSets classiques, c’est du tout ou rien - soit on cible tous les clusters qui matchent un label, soit on hardcode la liste.

Le problème devient vite ingérable. Modifier les labels des clusters pour chaque app n’est pas réaliste. Et maintenir des listes statiques dans les ApplicationSets, c’est la garantie d’oublier un cluster ou de devoir toucher à la config centrale à chaque changement.

Ce que le plugin apporte

Le plugin permet à chaque équipe de contrôler ses propres déploiements sans toucher à la config ArgoCD centrale. Le contrôle se fait via un fichier .argocd.json dans le repo de l’application.

Concrètement, une équipe peut :

  • Activer un nouveau cluster pour son app avec une simple PR
  • Désactiver temporairement un déploiement sur staging pendant une migration
  • Spécifier des versions de values différentes par cluster
  • Garder l’historique complet des changements dans Git

Plus besoin de demander à l’équipe plateforme de modifier les ApplicationSets. Plus de coordination complexe pour un simple changement de cible de déploiement.

Comment ça marche

Le plugin s’intègre comme un generator dans les ApplicationSets. Au lieu de lister les clusters dans l’ApplicationSet, on délègue au plugin.

┌─────────────────────────────────────────────────────────────────┐
│                        ApplicationSet                           │
│                                                                 │
│  generators:                                                    │
│    - plugin:                                                    │
│        configMapRef: plugin-filter                              │
│        input:                                                   │
│          parameters:                                            │
│            repo: https://github.com/org/app-config              │
└───────────────────────────┬─────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│                     Plugin Filter (FastAPI)                     │
│                                                                 │
│  1. Clone le repo Git                                           │
│  2. Lit les fichiers .argocd.json                               │
│  3. Filtre les clusters avec enabled: true                      │
│  4. Renvoie la liste à ArgoCD                                   │
└───────────────────────────┬─────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│                          ArgoCD                                 │
│                                                                 │
│  Génère une Application par cluster retourné :                  │
│    - app-prod-eu                                                │
│    - app-prod-us                                                │
│    (staging ignoré car enabled: false)                          │
└─────────────────────────────────────────────────────────────────┘

Le plugin clone le repo, scanne les fichiers .argocd.json, et retourne uniquement les clusters marqués enabled: true. ArgoCD génère alors les Applications correspondantes.

Exemples concrets

Cas 1 : deux clusters, activation sélective

Je veux déployer argo-events sur in-cluster et staging, mais garder dev désactivé.

{
    "source": {
        "repoURL": "https://argoproj.github.io/argo-helm",
        "targetRevision": "2.4.16",
        "chart": "argo-events"
    },
    "project": "testing-apps",
    "destination": {
        "namespace": "argo-events"
    },
    "clusters": {
        "in-cluster": {
            "enabled": true,
            "valuesRevision": "main"
        },
        "staging": {
            "enabled": true,
            "valuesRevision": "main"
        },
        "dev": {
            "enabled": false
        }
    }
}

ArgoCD génère deux Applications : argo-events-in-cluster et argo-events-staging. Le cluster dev est ignoré.

Cas 2 : multi-cluster avec versions différentes

Mon app tourne sur 4 clusters. Je veux une version stable en prod, et la dernière version en staging pour tester.

{
    "source": {
        "repoURL": "https://github.com/org/my-app",
        "targetRevision": "v2.1.0",
        "path": "helm/my-app"
    },
    "project": "my-app",
    "destination": {
        "namespace": "my-app"
    },
    "clusters": {
        "prod-eu": {
            "enabled": true,
            "valuesRevision": "main",
            "chartRevision": "v2.1.0"
        },
        "prod-us": {
            "enabled": true,
            "valuesRevision": "main",
            "chartRevision": "v2.1.0"
        },
        "staging": {
            "enabled": true,
            "valuesRevision": "develop",
            "chartRevision": "v2.2.0-rc1"
        },
        "dev": {
            "enabled": false
        }
    }
}
  • prod-eu/prod-us : version stable v2.1.0, values de main
  • staging : release candidate v2.2.0-rc1, values de develop pour tester la nouvelle config
  • dev : désactivé (maintenance en cours)

Cas 3 : rollout progressif

Je déploie une nouvelle version sur prod. Je commence par un seul cluster pour valider.

{
    "source": {
        "repoURL": "https://argoproj.github.io/argo-helm",
        "targetRevision": "2.5.0",
        "chart": "argo-workflows"
    },
    "project": "platform",
    "destination": {
        "namespace": "argo"
    },
    "clusters": {
        "prod-eu": {
            "enabled": true,
            "chartRevision": "2.5.0"
        },
        "prod-us": {
            "enabled": true,
            "chartRevision": "2.4.3"
        },
        "prod-asia": {
            "enabled": true,
            "chartRevision": "2.4.3"
        }
    }
}

prod-eu est le canary avec la nouvelle version. Une fois validé, je mets à jour les autres clusters un par un via des commits successifs.

Les paramètres du fichier .argocd.json

Le fichier centralise toute la config de déploiement :

  • source : le chart Helm ou le repo à déployer (URL, version, chart)
  • project : le projet ArgoCD
  • destination.namespace : le namespace cible
  • syncPolicy : les options de synchronisation ArgoCD
  • clusters : la liste des clusters avec leur état enabled et leurs options

Pour chaque cluster, vous pouvez spécifier :

  • enabled : activer ou désactiver le déploiement
  • valuesRevision : la branche Git pour les values
  • chartRevision : la version du chart (si différente de la version par défaut)

Le code du plugin

Le plugin est une API FastAPI assez simple. L’endpoint principal /api/v1/getparams.execute reçoit les requêtes d’ArgoCD et retourne la liste des clusters actifs.

Le flow est le suivant :

  1. ArgoCD envoie une requête avec l’URL du repo et la révision
  2. Le plugin clone le repo dans un répertoire temporaire
  3. Il scanne tous les fichiers .argocd.json trouvés
  4. Pour chaque fichier, il parcourt la section clusters
  5. Seuls les clusters avec enabled: true sont retournés
# Extrait de app.py - traitement des clusters
for cluster_name, cluster_config in clusters_data.items():
    if cluster_config.get("enabled", False):
        # Construire les paramètres pour ce cluster
        param = {
            "name": cluster_name,
            "destination": {"name": cluster_name},
            "valuesRevision": cluster_config.get("valuesRevision", "main"),
            # ... autres paramètres
        }
        result_params.append(param)

Le plugin gère l’authentification Git via un PAT token injecté dans l’URL HTTPS. Les tokens sensibles ne sont jamais loggés - ils sont masqués en cas d’erreur.

L’authentification ArgoCD se fait via un Bearer token dans le header Authorization. Le middleware verify_token valide chaque requête avant traitement.

Déployer le plugin

Le plugin est une API FastAPI qui tourne dans votre cluster. Il a besoin de :

  • AUTH_TOKEN : le token d’authentification ArgoCD
  • PAT_TOKEN : un token Git pour cloner les repos privés
  • PORT : le port du serveur (8080 par défaut)
# Lancer en local pour tester
AUTH_TOKEN=my-token PAT_TOKEN=ghp_xxx python app.py

Pour la prod, le Dockerfile fourni crée une image Alpine légère :

task build   # Build multi-arch linux/amd64,arm64
task test    # Tests unitaires

Code source

Le code complet est disponible sur GitHub :

  • app.py - Plugin FastAPI
  • Dockerfile - Image Alpine
  • example/ - Exemple de configuration argo-events