C’est quoi GitOps ?
GitOps, c’est une méthode de gestion d’infrastructure et de déploiement où Git est la source de vérité unique. Tout l’état désiré de ton cluster Kubernetes est décrit dans un repo Git. Un opérateur dans le cluster surveille ce repo et réconcilie automatiquement l’état réel avec l’état désiré.
Les 4 principes GitOps (selon OpenGitOps)
- Déclaratif — L’état désiré est décrit, pas les étapes pour y arriver
- Versionné et immuable — Git stocke l’historique complet des changements
- Tiré automatiquement — Les agents dans le cluster pull les changements
- Réconciliation continue — L’état réel est constamment rapproché de l’état désiré
Push vs Pull : la différence fondamentale
Push-based (CI/CD classique) :
Dev → Git Push → CI Pipeline → kubectl apply → Cluster
Le pipeline pousse les changements vers le cluster. Il a besoin de credentials pour accéder au cluster.
Pull-based (GitOps) :
Dev → Git Push → Git Repo ← Agent dans le cluster → Réconciliation
L’agent dans le cluster tire les changements depuis Git. Pas besoin d’exposer les credentials du cluster à l’extérieur.
| Aspect | Push (CI/CD) | Pull (GitOps) |
|---|---|---|
| Qui déploie | Pipeline externe | Agent dans le cluster |
| Credentials cluster | Nécessaires dans la CI | Restent dans le cluster |
| Drift detection | ❌ Pas natif | ✅ Réconciliation continue |
| Rollback | Re-run du pipeline | git revert |
| Audit trail | Logs CI | Historique Git |
| Sécurité | Credentials exposés | Principe du moindre privilège |
Pourquoi GitOps en 2026 ?
- Sécurité : plus besoin de
kubeconfigdans les pipelines CI/CD - Auditabilité : chaque changement = un commit Git avec auteur et timestamp
- Récupération : cluster crashé ? Recrée-le et pointe vers le même repo. Tout revient.
- Developer experience : les devs font des PR, pas du
kubectl - Compliance : les régulateurs adorent l’audit trail Git
ArgoCD
ArgoCD est l’outil GitOps le plus populaire. Développé par Intuit (les mêmes que TurboTax), maintenant projet CNCF graduated.
Installation
# Créer le namespace
kubectl create namespace argocd
# Installer ArgoCD
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
# Attendre que tout soit prêt
kubectl wait --for=condition=available deployment/argocd-server -n argocd --timeout=300s
# Récupérer le mot de passe admin initial
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d
# Exposer l'UI (port-forward pour tester)
kubectl port-forward svc/argocd-server -n argocd 8443:443
# Ou avec un Ingress (production)
cat <<EOF | kubectl apply -f -
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: argocd-server
namespace: argocd
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- argocd.devopslab.ch
secretName: argocd-tls
rules:
- host: argocd.devopslab.ch
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: argocd-server
port:
number: 443
EOF
Installer la CLI
# macOS
brew install argocd
# Linux
curl -sSL -o argocd https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64
chmod +x argocd && sudo mv argocd /usr/local/bin/
# Se connecter
argocd login argocd.devopslab.ch --username admin --password <password>
Concepts clés
Application — La ressource centrale. Elle lie un repo Git à un namespace Kubernetes :
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: my-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/devopslab/k8s-manifests.git
targetRevision: main
path: apps/my-app # Répertoire dans le repo
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated: # Sync automatique
prune: true # Supprimer les ressources orphelines
selfHeal: true # Re-sync si drift détecté
syncOptions:
- CreateNamespace=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
AppProject — Isole les applications par équipe/environnement :
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: team-backend
namespace: argocd
spec:
description: Projet pour l'équipe backend
sourceRepos:
- 'https://github.com/devopslab/*'
destinations:
- namespace: 'backend-*'
server: https://kubernetes.default.svc
clusterResourceWhitelist:
- group: ''
kind: Namespace
namespaceResourceBlacklist:
- group: ''
kind: ResourceQuota
roles:
- name: developer
policies:
- p, proj:team-backend:developer, applications, get, team-backend/*, allow
- p, proj:team-backend:developer, applications, sync, team-backend/*, allow
groups:
- team-backend-devs
ApplicationSet — Générer des Applications dynamiquement :
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: microservices
namespace: argocd
spec:
generators:
# Générer une Application par répertoire dans le repo
- git:
repoURL: https://github.com/devopslab/k8s-manifests.git
revision: main
directories:
- path: apps/*
template:
metadata:
name: '{{path.basename}}'
spec:
project: default
source:
repoURL: https://github.com/devopslab/k8s-manifests.git
targetRevision: main
path: '{{path}}'
destination:
server: https://kubernetes.default.svc
namespace: '{{path.basename}}'
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
Démo : déployer une app avec ArgoCD
Structure du repo Git :
k8s-manifests/
├── apps/
│ └── demo-app/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── ingress.yaml
│ └── kustomization.yaml
└── argocd/
└── demo-app.yaml
apps/demo-app/deployment.yaml :
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
labels:
app: demo-app
spec:
replicas: 3
selector:
matchLabels:
app: demo-app
template:
metadata:
labels:
app: demo-app
spec:
containers:
- name: demo-app
image: ghcr.io/devopslab/demo-app:v1.2.0
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 256Mi
apps/demo-app/service.yaml :
apiVersion: v1
kind: Service
metadata:
name: demo-app
spec:
selector:
app: demo-app
ports:
- port: 80
targetPort: 8080
type: ClusterIP
argocd/demo-app.yaml :
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: demo-app
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/devopslab/k8s-manifests.git
targetRevision: main
path: apps/demo-app
destination:
server: https://kubernetes.default.svc
namespace: demo
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
# Appliquer l'Application
kubectl apply -f argocd/demo-app.yaml
# Vérifier via CLI
argocd app get demo-app
argocd app sync demo-app
# Voir l'historique
argocd app history demo-app
# Rollback
argocd app rollback demo-app 1
Workflow quotidien avec ArgoCD
# 1. Modifier le manifest (ex: nouvelle image)
sed -i 's/v1.2.0/v1.3.0/' apps/demo-app/deployment.yaml
# 2. Commit + push
git add . && git commit -m "Bump demo-app to v1.3.0" && git push
# 3. ArgoCD détecte le changement et sync automatiquement
# (si syncPolicy.automated est activé)
# 4. Vérifier
argocd app get demo-app
# Status: Synced, Health: Healthy
# 5. Problème ? Revert Git
git revert HEAD && git push
# ArgoCD re-sync vers la version précédente
Flux
Flux est l’autre gros joueur GitOps. Développé par Weaveworks (RIP), maintenant projet CNCF graduated. Philosophie : léger, composable, Kubernetes-native.
Installation
# Installer la CLI
brew install fluxcd/tap/flux
# Ou
curl -s https://fluxcd.io/install.sh | sudo bash
# Vérifier les prérequis
flux check --pre
# Bootstrapper Flux avec GitHub
flux bootstrap github \
--owner=devopslab \
--repository=fleet-infra \
--branch=main \
--path=clusters/production \
--personal
# Ou GitLab
flux bootstrap gitlab \
--owner=devopslab \
--repository=fleet-infra \
--branch=main \
--path=clusters/production
Le bootstrap :
- Crée le repo
fleet-infras’il n’existe pas - Installe les composants Flux dans le cluster
- Configure Flux pour se gérer lui-même via Git (inception!)
Concepts clés
Flux est composable. Chaque fonctionnalité est un controller séparé :
| Controller | Rôle |
|---|---|
| source-controller | Récupère les sources (Git, Helm, OCI, S3) |
| kustomize-controller | Applique les manifests Kustomize |
| helm-controller | Gère les HelmReleases |
| notification-controller | Alertes et webhooks |
| image-reflector-controller | Détecte les nouvelles images |
| image-automation-controller | Met à jour les manifests avec les nouvelles images |
GitRepository — Source Git :
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m
url: https://github.com/devopslab/k8s-manifests.git
ref:
branch: main
secretRef:
name: github-token # Si repo privé
Kustomization — Ce qui doit être appliqué depuis la source :
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./apps/my-app
prune: true # Supprime les orphelins
sourceRef:
kind: GitRepository
name: my-app
targetNamespace: production
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: my-app
namespace: production
timeout: 3m
HelmRelease — Déployer un chart Helm :
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: nginx-ingress
namespace: flux-system
spec:
interval: 10m
chart:
spec:
chart: ingress-nginx
version: "4.x"
sourceRef:
kind: HelmRepository
name: ingress-nginx
values:
controller:
replicaCount: 2
service:
type: LoadBalancer
Démo : déployer avec Flux
Structure du repo :
fleet-infra/
├── clusters/
│ └── production/
│ ├── flux-system/ # Généré par bootstrap
│ │ ├── gotk-components.yaml
│ │ ├── gotk-sync.yaml
│ │ └── kustomization.yaml
│ ├── sources/
│ │ └── my-app.yaml
│ └── apps/
│ └── my-app.yaml
└── apps/
└── my-app/
├── deployment.yaml
├── service.yaml
└── kustomization.yaml
clusters/production/sources/my-app.yaml :
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
name: my-app
namespace: flux-system
spec:
interval: 1m
url: https://github.com/devopslab/k8s-manifests.git
ref:
branch: main
clusters/production/apps/my-app.yaml :
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
path: ./apps/my-app
prune: true
sourceRef:
kind: GitRepository
name: my-app
targetNamespace: demo
healthChecks:
- apiVersion: apps/v1
kind: Deployment
name: demo-app
namespace: demo
# Appliquer
git add . && git commit -m "Add my-app" && git push
# Flux détecte et applique automatiquement
# Vérifier
flux get kustomizations
flux get sources git
# Forcer une réconciliation
flux reconcile kustomization my-app --with-source
# Voir les événements
flux events
# Suspendre (maintenance)
flux suspend kustomization my-app
# Reprendre
flux resume kustomization my-app
Image Automation
Flux peut détecter les nouvelles images Docker et mettre à jour les manifests automatiquement :
# Scanner le registry
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageRepository
metadata:
name: my-app
namespace: flux-system
spec:
image: ghcr.io/devopslab/my-app
interval: 5m
---
# Politique de tag
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImagePolicy
metadata:
name: my-app
namespace: flux-system
spec:
imageRepositoryRef:
name: my-app
policy:
semver:
range: ">=1.0.0"
---
# Automation : update le manifest
apiVersion: image.toolkit.fluxcd.io/v1beta2
kind: ImageUpdateAutomation
metadata:
name: my-app
namespace: flux-system
spec:
interval: 5m
sourceRef:
kind: GitRepository
name: fleet-infra
git:
checkout:
ref:
branch: main
commit:
author:
name: fluxcdbot
email: flux@devopslab.ch
messageTemplate: 'chore: update {{.AutomationObject.Name}} to {{range .Changed.Changes}}{{.NewValue}}{{end}}'
push:
branch: main
update:
path: ./apps
strategy: Setters
Dans le manifest, marque l’image avec un commentaire :
spec:
containers:
- name: my-app
image: ghcr.io/devopslab/my-app:v1.2.0 # {"$imagepolicy": "flux-system:my-app"}
Flux va automatiquement committer le changement de tag quand une nouvelle version est publiée.
Comparatif ArgoCD vs Flux
Tableau comparatif détaillé
| Critère | ArgoCD | Flux |
|---|---|---|
| Architecture | Monolithique (serveur + UI) | Composable (controllers séparés) |
| UI | ✅ Interface web riche | ❌ Pas d’UI native (Weave GitOps UI en option) |
| CLI | ✅ Puissante | ✅ Puissante |
| Multi-cluster | ✅ Natif (hub-spoke) | ✅ Via Kustomization |
| Multi-tenancy | ✅ AppProjects + RBAC | ✅ Namespace-scoped |
| Helm | ✅ Via Application | ✅ HelmRelease natif |
| Kustomize | ✅ Natif | ✅ Natif |
| RBAC | ✅ Intégré (OIDC, LDAP) | ⚠️ Via Kubernetes RBAC |
| SSO | ✅ OIDC, SAML, LDAP | ❌ (via UI tierce) |
| Image automation | ⚠️ Argo Image Updater (séparé) | ✅ Natif |
| Notifications | ✅ Argo Notifications | ✅ notification-controller |
| Webhooks | ✅ GitHub, GitLab | ✅ GitHub, GitLab, et plus |
| Diff/Preview | ✅ Dans l’UI | ⚠️ CLI uniquement |
| Rollback | ✅ Un clic dans l’UI | ⚠️ git revert |
| OCI support | ✅ | ✅ |
| Footprint | ~200-500 Mi RAM | ~100-200 Mi RAM |
| Courbe d’apprentissage | Moyenne | Plus raide |
| CNCF Status | Graduated | Graduated |
| Communauté | Très active (~16k ⭐) | Active (~6k ⭐) |
Benchmark de performance
Sur un cluster avec 200 applications :
| Métrique | ArgoCD | Flux |
|---|---|---|
| Temps de sync moyen | 15-30s | 10-20s |
| RAM utilisée | ~450 Mi | ~180 Mi |
| CPU utilisé | ~200m | ~100m |
| Détection de drift | 3 min (default) | 1 min (configurable) |
Points forts de chacun
ArgoCD brille quand :
- Tu veux une UI pour visualiser l’état des apps
- Tu as besoin de SSO/RBAC intégré
- Plusieurs équipes doivent voir l’état des déploiements
- Tu veux du rollback en un clic
- Tu viens du monde CI/CD et tu veux une transition douce
Flux brille quand :
- Tu préfères une approche Kubernetes-native (tout est CRD)
- Tu veux un footprint minimal
- Tu as besoin d’image automation native
- Tu gères de l’infrastructure (pas seulement des apps)
- Tu veux de la composabilité (n’installe que ce dont tu as besoin)
Quand utiliser quoi ?
Arbre de décision
Tu as besoin d'une UI ?
├── Oui → ArgoCD
└── Non
├── Tu gères beaucoup d'infra (cert-manager, ingress, monitoring...) ?
│ ├── Oui → Flux (plus léger, HelmRelease natif)
│ └── Non
│ ├── Plusieurs équipes non-techniques doivent voir les déploiements ?
│ │ ├── Oui → ArgoCD (UI = adoption facile)
│ │ └── Non → Flux ou ArgoCD, les deux marchent
│ └── Tu as besoin d'image automation ?
│ ├── Oui → Flux (natif et mature)
│ └── Non → ArgoCD ou Flux
Recommandations par contexte
| Contexte | Recommandation |
|---|---|
| Startup / petite équipe | Flux (léger, rapide à setup) |
| Enterprise / plusieurs équipes | ArgoCD (UI, RBAC, SSO) |
| Platform engineering | Flux (composable, Kubernetes-native) |
| Migration depuis Jenkins/GitLab CI | ArgoCD (transition plus douce) |
| Multi-cluster massif | ArgoCD (ApplicationSet) ou Flux (Kustomization multi-cluster) |
| Edge / IoT / ressources limitées | Flux (footprint minimal) |
Le setup hybride
Rien n’empêche d’utiliser les deux :
- Flux pour l’infrastructure (cert-manager, ingress, monitoring, operators)
- ArgoCD pour les applications (ce que les devs voient et gèrent)
C’est un pattern de plus en plus courant en 2026.
Bonnes pratiques GitOps
Structure de repo
Mono-repo (recommandé pour commencer) :
fleet/
├── infrastructure/ # Composants infra
│ ├── cert-manager/
│ ├── ingress-nginx/
│ └── monitoring/
├── apps/ # Applications
│ ├── frontend/
│ ├── backend/
│ └── worker/
├── clusters/ # Config par cluster
│ ├── production/
│ └── staging/
└── README.md
Multi-repo (grandes organisations) :
# Repo 1: fleet-infra (platform team)
# Repo 2: app-frontend (frontend team)
# Repo 3: app-backend (backend team)
Sécurité
# Sealed Secrets (chiffrement côté client, déchiffrement dans le cluster)
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: my-secret
namespace: production
spec:
encryptedData:
password: AgBy3i... # Chiffré avec la clé publique du cluster
# Ou External Secrets Operator (secrets depuis Vault, AWS SM, etc.)
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: my-secret
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: ClusterSecretStore
target:
name: my-secret
data:
- secretKey: password
remoteRef:
key: secret/data/my-app
property: password
Le workflow PR
- Dev crée une branche et modifie les manifests
- PR review (le code ET les manifests)
- CI valide les manifests (
kubectl dry-run,kustomize build,helm template) - Merge → ArgoCD/Flux sync automatiquement
- Monitoring vérifie que tout est healthy
# GitHub Actions : valider les manifests avant merge
name: Validate K8s Manifests
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate manifests
run: |
# Installer les outils
curl -sL https://github.com/yannh/kubeconform/releases/latest/download/kubeconform-linux-amd64.tar.gz | tar xz
# Valider tous les YAML
find apps/ -name '*.yaml' -exec ./kubeconform -strict -summary {} +
- name: Kustomize build check
run: |
for dir in apps/*/; do
echo "Building $dir..."
kustomize build "$dir" > /dev/null
done
Conclusion
GitOps n’est plus une tendance — c’est le standard en 2026 pour le déploiement Kubernetes. ArgoCD et Flux sont tous deux matures, graduées CNCF, et production-ready.
TL;DR :
- Tu veux une UI et du RBAC → ArgoCD
- Tu veux du léger et du Kubernetes-native → Flux
- Tu débutes en GitOps → ArgoCD (l’UI aide beaucoup à comprendre)
- Tu es platform engineer → Flux (plus de contrôle)
Le plus important, c’est de commencer. Prends celui qui te parle, déploie-le, et itère. Le switch de l’un à l’autre est toujours possible — tes manifests Kubernetes restent les mêmes.
🖥️ Pratique sur ton propre serveur
Pour suivre GitOps en 2026 : ArgoCD vs Flux, le guide complet en conditions réelles, tu as besoin d'un VPS. DigitalOcean offre 200$ de crédit gratuit pour démarrer.
Sur cette page
Articles liés
GitHub Actions : construire un pipeline CI/CD complet de A à Z
Guide pratique pour construire un pipeline CI/CD complet avec GitHub Actions : lint, tests, build Docker, push registry et déploiement Kubernetes. Workflows YAML fonctionnels, secrets, matrix builds, caching et self-hosted runners.
Déployer Kubernetes en production en Suisse : guide complet 2026
Guide complet pour déployer Kubernetes en production en Suisse : choix du provider, architecture HA, sécurité LPD/RGPD, networking, monitoring et coûts. Retour d'expérience d'un DevOps senior.
Comparatif hébergement cloud 2026 : AWS vs GCP vs Azure vs alternatives
AWS vs GCP vs Azure vs alternatives : comparatif complet des hébergements cloud en 2026 avec pricing détaillé.