Arc 6 Quête A5

Les Courants du Destin

GitOps, ArgoCD, Flux et infrastructure as code

Au sommet de la plus haute tour de la Citadelle, il existe une salle secrète que peu d'archivistes connaissent : la Chambre des Courants. C'est ici que les Maîtres des Courants observent les forces invisibles qui gouvernent l'infrastructure du royaume - chaque pont, chaque route, chaque forteresse est façonné par ces courants.

Le Maître des Courants t'invite à observer la grande carte animée qui occupe tout un mur. Des lignes de lumière parcourent le royaume, connectant les serveurs de la Citadelle aux avant-postes les plus reculés. « Chaque modification que tu vois est un courant - un changement décrit dans un parchemin, qui façonne automatiquement la réalité. C'est ce qu'on appelle GitOps. Et c'est la manière la plus puissante de gouverner une infrastructure. »

La philosophie GitOps

GitOps est une philosophie où Git est la source de vérité unique pour toute l'infrastructure et les déploiements applicatifs. L'idée est simple mais révolutionnaire :

  • Toute l'infrastructure est décrite dans des fichiers versionnés dans Git
  • Modifier l'infrastructure = faire un commit
  • Déployer = merger une branche
  • Annuler un déploiement = git revert

Le terme a été inventé par Weaveworks en 2017. Depuis, il est devenu un standard de facto dans le monde Kubernetes et au-delà.

Les quatre principes fondamentaux

  1. Déclaratif : l'état désiré du système est décrit dans des fichiers (YAML, JSON, HCL), pas dans des scripts impératifs
  2. Versionné : tout est dans Git - l'historique complet de chaque changement d'infrastructure
  3. Automatique : un agent applique automatiquement les changements quand Git est modifié
  4. Auto-réconciliant : si quelqu'un modifie l'infrastructure manuellement, l'agent la remet dans l'état décrit par Git

GitOps transforme Git en panneau de contrôle de toute ton infrastructure. Pas besoin d'accès SSH aux serveurs, pas besoin de scripts de déploiement manuels. Git est le seul point d'entrée.

Pull vs Push deployment

Il existe deux modèles pour appliquer les changements d'infrastructure. Comprendre la différence est fondamental.

Le modèle Push (traditionnel)

Dans le modèle push, un système externe (CI/CD) pousse les changements vers le cluster :

# Modèle PUSH - le pipeline CI/CD déploie directement
# .github/workflows/deploy.yml

# 1. Le développeur push du code
# 2. Le CI/CD build l'image Docker
# 3. Le CI/CD applique les manifestes Kubernetes
#    kubectl apply -f k8s/deployment.yaml
# 4. Le CI/CD a besoin d'accès direct au cluster (credentials)

Problèmes du modèle push :

  • Le pipeline CI/CD a besoin de credentials d'accès au cluster - surface d'attaque importante
  • Si quelqu'un modifie le cluster manuellement, le CI/CD ne le sait pas (drift)
  • Pas de réconciliation automatique

Le modèle Pull (GitOps)

Dans le modèle pull, un agent installé dans le cluster surveille Git et applique les changements :

# Modèle PULL - un agent dans le cluster surveille Git

# 1. Le développeur push du code et des manifestes dans Git
# 2. L'agent GitOps (ArgoCD, Flux) détecte le changement
# 3. L'agent PULL les manifestes depuis Git
# 4. L'agent applique les changements dans le cluster
# 5. Si quelqu'un modifie manuellement, l'agent corrige (auto-healing)

Avantages du modèle pull :

  • Pas de credentials externes : l'agent est déjà dans le cluster
  • Auto-healing : toute modification manuelle est automatiquement corrigée
  • Audit complet : chaque changement est un commit Git
  • Rollback simple : git revert annule un déploiement
Aspect Push (CI/CD classique) Pull (GitOps)
Qui déploie Le pipeline CI/CD Un agent dans le cluster
Credentials Le CI/CD a accès au cluster L'agent a accès à Git (lecture seule)
Drift Non détecté Automatiquement corrigé
Rollback Re-déployer une ancienne version git revert
Audit Logs du CI/CD git log (complet, permanent)

ArgoCD - le gardien du cluster

ArgoCD est l'outil GitOps le plus populaire pour Kubernetes. Il s'installe dans ton cluster et surveille un ou plusieurs dépôts Git. Dès qu'un changement est détecté, il l'applique.

Concepts clés

  • Application : une ressource ArgoCD qui lie un dépôt Git à un namespace Kubernetes
  • Sync : le processus d'alignement entre l'état Git et l'état du cluster
  • Health : l'état de santé des ressources déployées
  • Diff : la différence entre l'état désiré (Git) et l'état actuel (cluster)

L'Application CRD

On déclare une Application ArgoCD en YAML. C'est la ressource centrale qui dit : "surveille ce dépôt Git et déploie dans ce namespace" :

# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: mon-app
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/mon-org/mon-app-gitops.git
    targetRevision: main
    path: overlays/production    # Dossier contenant les manifestes
  destination:
    server: https://kubernetes.default.svc
    namespace: mon-app
  syncPolicy:
    automated:                   # Sync automatique activé
      prune: true                # Supprime les ressources absentes de Git
      selfHeal: true             # Corrige les modifications manuelles
    syncOptions:
      - CreateNamespace=true     # Crée le namespace si nécessaire

Sync policies

  • Manual sync : tu déclenches le déploiement manuellement depuis l'UI ou le CLI
  • Automated sync : ArgoCD déploie automatiquement dès qu'il détecte un changement dans Git
  • Self-heal : si quelqu'un fait un kubectl edit manuel, ArgoCD restaure l'état Git
  • Prune : si tu supprimes un fichier de Git, ArgoCD supprime la ressource correspondante du cluster
# CLI ArgoCD - commandes courantes
# Se connecter
argocd login argocd.mon-domaine.com

# Lister les applications
argocd app list

# Voir l'état d'une application
argocd app get mon-app

# Synchroniser manuellement
argocd app sync mon-app

# Voir l'historique des déploiements
argocd app history mon-app

# Rollback vers une version précédente
argocd app rollback mon-app 3

Astuce : ArgoCD offre une interface web superbe qui affiche l'état de chaque ressource Kubernetes sous forme d'arbre visuel. C'est souvent par l'UI que les équipes surveillent leurs déploiements au quotidien.

Flux - l'alternative CNCF

Flux (anciennement Flux v2) est l'autre grand outil GitOps, maintenu par la CNCF (Cloud Native Computing Foundation). Contrairement à ArgoCD, Flux n'a pas d'interface web par défaut - il est entièrement piloté par des ressources Kubernetes.

Concepts clés de Flux

  • GitRepository : pointe vers un dépôt Git à surveiller
  • Kustomization : décrit quoi déployer depuis le dépôt et comment
  • HelmRelease : déploie des charts Helm depuis Git ou un registry
  • ImageUpdateAutomation : met à jour automatiquement les tags d'images dans Git
# Installation de Flux dans un cluster
flux bootstrap github \
  --owner=mon-org \
  --repository=flux-config \
  --path=clusters/production \
  --personal

# Cela crée un dépôt Git et installe Flux dans le cluster
# Flux se gère lui-même via GitOps !

Exemple de configuration Flux

# source.yaml - Définir la source Git
apiVersion: source.toolkit.fluxcd.io/v1
kind: GitRepository
metadata:
  name: mon-app
  namespace: flux-system
spec:
  interval: 1m                    # Vérifier Git toutes les minutes
  url: https://github.com/mon-org/mon-app-gitops
  ref:
    branch: main

---
# kustomization.yaml - Définir quoi déployer
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
  name: mon-app
  namespace: flux-system
spec:
  interval: 5m
  path: ./overlays/production     # Chemin dans le dépôt
  prune: true                     # Supprimer les ressources absentes de Git
  sourceRef:
    kind: GitRepository
    name: mon-app
  healthChecks:                   # Vérifier la santé après déploiement
    - apiVersion: apps/v1
      kind: Deployment
      name: mon-app
      namespace: mon-app

ArgoCD vs Flux - comment choisir ?

Aspect ArgoCD Flux
Interface web Oui, riche et intuitive Non (CLI + extensions tierces)
Configuration Application CRD + UI 100% ressources Kubernetes
Multi-cluster Natif (un ArgoCD gère N clusters) Un Flux par cluster
Helm Support intégré HelmRelease CRD
Philosophie Outil centralisé avec UI Composants distribués, natif K8s
Courbe d'apprentissage Plus facile (UI aide) Plus raide (tout en YAML)

Structure d'un repo GitOps

L'organisation du dépôt GitOps est cruciale. La structure la plus répandue utilise Kustomize avec des overlays par environnement :

mon-app-gitops/
├── base/                        # Configuration commune à tous les envs
│   ├── kustomization.yaml       # Liste des ressources de base
│   ├── deployment.yaml          # Déploiement de l'application
│   ├── service.yaml             # Service Kubernetes
│   ├── configmap.yaml           # Configuration non-sensible
│   └── hpa.yaml                 # Auto-scaling
├── overlays/                    # Personnalisations par environnement
│   ├── dev/
│   │   ├── kustomization.yaml   # Hérite de base/ + patches dev
│   │   ├── replicas-patch.yaml  # 1 réplica en dev
│   │   └── resources-patch.yaml # Moins de CPU/RAM
│   ├── staging/
│   │   ├── kustomization.yaml
│   │   ├── replicas-patch.yaml  # 2 réplicas en staging
│   │   └── ingress-patch.yaml   # Domaine staging
│   └── production/
│       ├── kustomization.yaml
│       ├── replicas-patch.yaml  # 5 réplicas en prod
│       ├── resources-patch.yaml # Plus de CPU/RAM
│       └── ingress-patch.yaml   # Domaine production
└── apps/                        # Autres applications déployées
    ├── monitoring/
    │   ├── kustomization.yaml
    │   └── prometheus.yaml
    └── ingress/
        ├── kustomization.yaml
        └── nginx-ingress.yaml

Kustomize en deux mots

Kustomize est un outil intégré à kubectl qui permet de personnaliser des manifestes YAML sans les dupliquer. Le principe : une base commune et des overlays qui la modifient.

# base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
  - configmap.yaml

---
# overlays/production/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base                  # Hérite de la base
patches:
  - path: replicas-patch.yaml   # Applique les patches prod
  - path: resources-patch.yaml
namespace: mon-app-prod         # Namespace spécifique

---
# overlays/production/replicas-patch.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mon-app
spec:
  replicas: 5                   # 5 réplicas en production
# Prévisualiser ce que Kustomize génère pour la prod
kubectl kustomize overlays/production/

# Appliquer directement (hors GitOps, pour tester)
kubectl apply -k overlays/production/

Gestion des secrets dans GitOps

Le plus grand défi de GitOps : comment versionner des secrets (mots de passe, clés API, certificats) dans Git sans les exposer en clair ?

Sealed Secrets (Bitnami)

Sealed Secrets chiffre tes secrets avec une clé publique. Seul le contrôleur installé dans le cluster peut les déchiffrer :

# Créer un Secret Kubernetes classique (NE PAS commiter !)
kubectl create secret generic mon-secret \
  --from-literal=db-password=SuperSecretMotDePasse \
  --dry-run=client -o yaml > secret.yaml

# Chiffrer avec kubeseal (clé publique du cluster)
kubeseal --format yaml < secret.yaml > sealed-secret.yaml

# Le SealedSecret est safe pour Git - il ne peut être déchiffré
# que par le contrôleur du cluster
cat sealed-secret.yaml
# apiVersion: bitnami.com/v1alpha1
# kind: SealedSecret
# spec:
#   encryptedData:
#     db-password: AgBy3i4OJSWK+... (chiffré, illisible)

# Commiter le SealedSecret (chiffré) dans Git
git add sealed-secret.yaml
git commit -m "Ajout du secret de base de données (chiffré)"

SOPS + age

SOPS (de Mozilla) chiffre les valeurs dans les fichiers YAML/JSON tout en gardant les clés lisibles. Combiné avec age (chiffrement moderne), c'est une solution élégante :

# Installer SOPS et age
# (varie selon l'OS)

# Générer une clé age
age-keygen -o key.txt
# Public key: age1ql3z7hjy...

# Configurer SOPS pour le projet
cat > .sops.yaml << 'EOF'
creation_rules:
  - path_regex: .*secrets.*\.yaml$
    age: age1ql3z7hjy...        # Clé publique
EOF

# Chiffrer un fichier
sops --encrypt secrets.yaml > secrets.enc.yaml

# Le fichier chiffré garde les clés lisibles :
# db:
#     password: ENC[AES256_GCM,data:abc123...,type:str]
#     host: ENC[AES256_GCM,data:def456...,type:str]

# Déchiffrer (nécessite la clé privée)
sops --decrypt secrets.enc.yaml

External Secrets Operator

External Secrets Operator (ESO) ne stocke pas les secrets dans Git du tout. Il les récupère depuis un gestionnaire de secrets externe (AWS Secrets Manager, HashiCorp Vault, Azure Key Vault) :

# external-secret.yaml - Référence vers un secret externe
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: mon-secret
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: ClusterSecretStore
  target:
    name: mon-secret             # Nom du Secret K8s créé
  data:
    - secretKey: db-password
      remoteRef:
        key: production/database  # Chemin dans Vault
        property: password
Solution Principe Idéal pour
Sealed Secrets Chiffrement asymétrique, déchiffrement dans le cluster Petites équipes, setup simple
SOPS + age Chiffrement des valeurs dans les fichiers YAML Flexibilité, multi-cloud
External Secrets Référence vers un gestionnaire de secrets externe Entreprises avec Vault/AWS SM existant

La puissance du modèle - rollback et audit

Voici où GitOps brille vraiment : les opérations qui sont complexes dans un déploiement traditionnel deviennent triviales.

Rollback = git revert

# Un déploiement a causé un problème en production ?
# Pas de panique. C'est un simple git revert.

# Voir l'historique des déploiements
git log --oneline
# a1b2c3d Mise à jour image v2.3.0
# d4e5f6g Ajout variable d'environnement LOG_LEVEL
# h7i8j9k Mise à jour image v2.2.0

# Annuler le dernier déploiement
git revert HEAD
# [main k1l2m3n] Revert "Mise à jour image v2.3.0"

# Push - l'agent GitOps détecte le changement et rollback automatiquement
git push

# En quelques secondes, la prod est revenue à v2.2.0
# Pas besoin de trouver la bonne commande kubectl
# Pas besoin de chercher la bonne image Docker
# Git a TOUT l'historique

Audit trail = git log

# Qui a modifié quoi, quand, et pourquoi ?
git log --format="%h %an %ad %s" --date=short
# a1b2c3d Alice 2026-03-09 Mise à jour image v2.3.0
# d4e5f6g Bob   2026-03-08 Ajout variable LOG_LEVEL=debug
# h7i8j9k Alice 2026-03-07 Mise à jour image v2.2.0
# l4m5n6o Carol 2026-03-05 Augmentation replicas 3 -> 5

# Qui a touché à la config de production ?
git log --oneline -- overlays/production/

# Qu'est-ce qui a changé exactement dans ce déploiement ?
git diff d4e5f6g..a1b2c3d

Avec GitOps, git log devient ton journal d'audit complet. Chaque changement d'infrastructure est tracé, attribué à un auteur, et peut être annulé. C'est exactement ce que les auditeurs de sécurité adorent.

Multi-environnement - branches vs dossiers

Comment gérer dev, staging et production dans un repo GitOps ? Deux approches existent :

Approche par branches (non recommandée)

# Branche dev    -> déploie en dev
# Branche staging -> déploie en staging
# Branche main   -> déploie en production

# Problème : les promotions se font par merge/cherry-pick
# entre branches. C'est fragile et source d'erreurs.
# Les branches divergent facilement.

Approche par dossiers (recommandée)

# Une seule branche (main), des dossiers par environnement
# overlays/dev/       -> déploie en dev
# overlays/staging/   -> déploie en staging
# overlays/production/ -> déploie en production

# Promotion : modifier le tag d'image dans le dossier suivant
# 1. Tester en dev  : modifier overlays/dev/kustomization.yaml
# 2. Promouvoir     : copier le même tag dans overlays/staging/
# 3. Mettre en prod : copier le tag dans overlays/production/

# Avantage : un seul git log montre tout l'historique
# de tous les environnements. Pas de divergence de branches.

Astuce : La communauté GitOps recommande fortement l'approche par dossiers. Les branches par environnement semblent intuitives au début, mais deviennent rapidement un cauchemar de maintenance quand les environnements divergent.

Exercice pratique - Structurer un repo GitOps

Crée un dépôt GitOps pour une application web fictive appelée "taverne-api" (l'API de la Taverne du royaume) avec Kustomize et trois environnements :

  1. Crée la structure base/ + overlays/ (dev, staging, production)
  2. Écris les manifestes de base (deployment, service)
  3. Personnalise chaque environnement (réplicas, ressources)
  4. Simule une promotion de dev vers production
  5. Simule un rollback avec git revert

Étape 1 - Créer la structure

# Créer le dépôt
mkdir taverne-gitops
cd taverne-gitops
git init -b main

# Créer l'arborescence
mkdir -p base
mkdir -p overlays/dev
mkdir -p overlays/staging
mkdir -p overlays/production

Étape 2 - Les manifestes de base

# base/deployment.yaml
cat > base/deployment.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: taverne-api
spec:
  replicas: 1
  selector:
    matchLabels:
      app: taverne-api
  template:
    metadata:
      labels:
        app: taverne-api
    spec:
      containers:
        - name: taverne-api
          image: taverne-api:v1.0.0
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
            limits:
              cpu: 200m
              memory: 256Mi
EOF

# base/service.yaml
cat > base/service.yaml << 'EOF'
apiVersion: v1
kind: Service
metadata:
  name: taverne-api
spec:
  selector:
    app: taverne-api
  ports:
    - port: 80
      targetPort: 8080
EOF

# base/kustomization.yaml
cat > base/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - deployment.yaml
  - service.yaml
EOF

git add base/
git commit -m "Ajout des manifestes de base taverne-api"

Étape 3 - Les overlays par environnement

# overlays/dev/kustomization.yaml
cat > overlays/dev/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: taverne-dev
images:
  - name: taverne-api
    newTag: v1.0.0
EOF

# overlays/staging/kustomization.yaml
cat > overlays/staging/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: taverne-staging
images:
  - name: taverne-api
    newTag: v1.0.0
patches:
  - path: replicas-patch.yaml
EOF

cat > overlays/staging/replicas-patch.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: taverne-api
spec:
  replicas: 2
EOF

# overlays/production/kustomization.yaml
cat > overlays/production/kustomization.yaml << 'EOF'
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
  - ../../base
namespace: taverne-prod
images:
  - name: taverne-api
    newTag: v1.0.0
patches:
  - path: replicas-patch.yaml
  - path: resources-patch.yaml
EOF

cat > overlays/production/replicas-patch.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: taverne-api
spec:
  replicas: 5
EOF

cat > overlays/production/resources-patch.yaml << 'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
  name: taverne-api
spec:
  template:
    spec:
      containers:
        - name: taverne-api
          resources:
            requests:
              cpu: 500m
              memory: 512Mi
            limits:
              cpu: "1"
              memory: 1Gi
EOF

git add overlays/
git commit -m "Ajout des overlays dev, staging et production"

Étape 4 - Simuler une promotion

# Nouvelle version testée en dev
sed -i 's/newTag: v1.0.0/newTag: v1.1.0/' overlays/dev/kustomization.yaml
git add overlays/dev/
git commit -m "Deploy taverne-api v1.1.0 en dev"

# Promotion en staging
sed -i 's/newTag: v1.0.0/newTag: v1.1.0/' overlays/staging/kustomization.yaml
git add overlays/staging/
git commit -m "Promotion taverne-api v1.1.0 en staging"

# Promotion en production
sed -i 's/newTag: v1.0.0/newTag: v1.1.0/' overlays/production/kustomization.yaml
git add overlays/production/
git commit -m "Promotion taverne-api v1.1.0 en production"

Étape 5 - Simuler un rollback

# Bug en prod ! On annule le dernier déploiement
git revert HEAD --no-edit
# [main abc1234] Revert "Promotion taverne-api v1.1.0 en production"

# Vérifier que la prod est revenue à v1.0.0
grep newTag overlays/production/kustomization.yaml
#     newTag: v1.0.0

# L'historique complet montre tout
git log --oneline
# abc1234 Revert "Promotion taverne-api v1.1.0 en production"
# def5678 Promotion taverne-api v1.1.0 en production
# ghi9012 Promotion taverne-api v1.1.0 en staging
# jkl3456 Deploy taverne-api v1.1.0 en dev
# mno7890 Ajout des overlays dev, staging et production
# pqr1234 Ajout des manifestes de base taverne-api

Récapitulatif des concepts

Concept Description
GitOps Philosophie où Git est la source de vérité pour l'infrastructure
Modèle Pull Un agent dans le cluster surveille Git et applique les changements
Modèle Push Le CI/CD pousse les changements vers le cluster (traditionnel)
ArgoCD Outil GitOps populaire avec interface web riche
Flux Outil GitOps CNCF, 100% natif Kubernetes
Kustomize Outil de personnalisation de manifestes YAML (base + overlays)
Sealed Secrets Chiffrement asymétrique de secrets pour Git
SOPS + age Chiffrement des valeurs dans les fichiers YAML
External Secrets Récupération de secrets depuis un gestionnaire externe
Self-healing Correction automatique des modifications manuelles
Dossiers vs branches Les dossiers par environnement sont préférés aux branches

Le Maître des Courants éteint la grande carte animée d'un geste de la main. La salle retrouve son calme. « Tu comprends maintenant pourquoi on les appelle les Courants du Destin. Chaque commit dans ton dépôt GitOps est un courant qui façonne l'infrastructure du royaume. Pas de magie obscure, pas de commandes tapées en urgence sur un serveur en feu. Juste des parchemins versionnés qui deviennent réalité. »

« Le plus beau, c'est que tout est dans l'historique. Qui a changé quoi, quand, pourquoi. Si quelque chose se brise, tu remontes le courant. Un simple git revert, et le royaume retrouve sa stabilité. C'est la paix de l'esprit que seul un Maître des Courants peut offrir. »

Il te tend un médaillon gravé d'un arbre dont les branches se transforment en flux lumineux. « Tu as appris à gouverner l'infrastructure par les Courants. Utilise ce pouvoir avec sagesse. »