Partie 6 : GitOps avec ArgoCD - L'installation

Partie 6 : GitOps avec ArgoCD - L'installation

Partie 6 : GitOps avec ArgoCD - L'installation

16 décembre 2025

Le grand Reset et la reconstruction

Après avoir cassé toute l'infrastructure en essayant de résoudre les problèmes de redirections vers mes services externes (Passbolt, NAS, stack Arr), j'ai pris une décision radicale : tout réinstaller from scratch.

Une semaine de recherche pour tenter de récupérer, une semaine de pause pour accepter la situation, et finalement : formatage des cartes SD et réinstallation complète de Raspberry Pi OS sur les 4 Raspberry Pi.

Mais cette fois-ci, j'avais un atout majeur : mes playbooks Ansible.

Le sauvetage par l'Infrastructure as Code

Grâce aux playbooks Ansible créés précédemment, la réinstallation du cluster K3s a été un jeu d'enfant :

ansible-playbook -i inventory.yml playbooks/site.yml

En moins d'une heure, j'avais :

  • Les 4 Raspberry Pi configurés
  • K3s installé et clusterisé
  • nginx-ingress-controller déployé
  • cert-manager configuré
  • Les certificats Let's Encrypt générés

C'est là que j'ai vraiment compris la puissance de l'Infrastructure as Code. Sans Ansible, j'aurais passé des jours à tout reconfigurer manuellement.

Le problème suivant : La dérive de configuration

Même avec Ansible pour l'infrastructure de base, je faisais encore beaucoup de kubectl apply manuels pour déployer mes applications. Et là, nouveau problème :

Comment savoir ce qui tourne réellement sur le cluster ?

  • J'avais des manifests YAML éparpillés
  • Des commandes Helm upgrade lancées à la main
  • Aucune trace de qui a modifié quoi et quand
  • Impossible de revenir en arrière facilement

Exemple typique :

# Moi, un lundi
helm upgrade home-fonta ./helm-charts/homefonta -n home-fonta

# Moi, le mercredi (j'ai oublié ce que j'ai changé)
kubectl get deployment home-fonta-web -n home-fonta -o yaml
# "Attendez, pourquoi il y a 2 replicas ? J'avais pas mis 3 ?"

La dérive de configuration (configuration drift) était inévitable.

GitOps : Git comme source de vérité unique

J'ai découvert le concept de GitOps :

Principe fondamental : L'état désiré de ton infrastructure est dans Git, et c'est la seule source de vérité.

Le flux GitOps :

  1. Je modifie un fichier YAML dans Git
  2. Je commit et push
  3. Un outil détecte le changement
  4. L'outil synchronise automatiquement Kubernetes avec Git
  5. Zéro commande kubectl manuelle

Avantages :

  • Historique complet dans Git (qui a changé quoi, quand, pourquoi)
  • Rollback facile (juste un git revert)
  • Code review via Pull Requests
  • Audit trail complet
  • Pas de dérive de configuration possible (auto-correction)

L'outil leader pour GitOps sur Kubernetes : ArgoCD

ArgoCD : Le contrôleur GitOps

ArgoCD est un contrôleur Kubernetes qui :

  • Surveille un repository Git
  • Compare l'état dans Git avec l'état dans Kubernetes
  • Synchronise automatiquement si différence détectée
  • Affiche une belle interface web pour visualiser tout ça

Installation d'ArgoCD sur K3s

Prérequis

Avant d'installer ArgoCD, j'avais déjà :

  • Cluster K3s opérationnel (4 nodes)
  • cert-manager installé
  • Certificat wildcard Let's Encrypt pour *.home-fonta.fr
  • Repository Git : git@github.com:Nikob2o/ansible-k3s.git

Étape 1 : Installation ArgoCD

La méthode officielle recommandée :

# Créer le namespace
kubectl create namespace argocd

# Installer ArgoCD (version stable)
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Cette commande installe :

  • Les Custom Resource Definitions (CRDs) : Application, ApplicationSet, AppProject
  • Les contrôleurs : application-controller, repo-server, server
  • Les services : argocd-server, argocd-repo-server, argocd-dex-server
  • Redis pour le cache

Vérification :

kubectl get pods -n argocd

Tous les pods doivent être en Running (prend 1-2 minutes).

Étape 2 : Exposition via Ingress

ArgoCD installé, mais pas encore accessible depuis l'extérieur. Je devais créer un Ingress.

Fichier : manifests/02-argocd/ingress.yaml

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: argocd-server-ingress
  namespace: argocd
  annotations:
    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
    nginx.ingress.kubernetes.io/ssl-passthrough: "false"
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - argo.home-fonta.fr
    secretName: wildcard-home-fonta-tls
  rules:
  - host: argo.home-fonta.fr
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: argocd-server
            port:
              name: https

Point important : backend-protocol: "HTTPS" car ArgoCD server écoute en HTTPS en interne, mais je fais du TLS termination sur l'Ingress.

Application de l'Ingress :

kubectl apply -f manifests/02-argocd/ingress.yaml

Étape 3 : Configuration DNS

Création de l'enregistrement DNS dans Cloudflare via API :

curl -s -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/dns_records" \
  -H "Authorization: Bearer API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"type":"A","name":"argo","content":"80.9.222.151","ttl":1,"proxied":false}'

Maintenant : https://argo.home-fonta.fr est accessible !

Problème 1 : Certificat SSL invalide

En accédant à https://argo.home-fonta.fr, Firefox me bloque : "Connexion bloquée : problème de sécurité potentiel".

Cause : Le certificat wildcard-home-fonta-tls existe dans le namespace home-fonta, mais pas dans le namespace argocd.

Les Secrets Kubernetes ne traversent PAS les namespaces (isolation de sécurité).

Solution temporaire : Port-forward pour accéder via localhost

kubectl port-forward svc/argocd-server -n argocd 8080:443

Puis accès via https://localhost:8080 (accepter le certificat auto-signé).

La vraie solution (réplication de certificat entre namespaces) viendra plus tard avec Reflector.

Étape 4 : Récupération du mot de passe admin

ArgoCD génère un mot de passe admin aléatoire au premier démarrage :

kubectl -n argocd get secret argocd-initial-admin-secret \
  -o jsonpath="{.data.password}" | base64 -d && echo

Credentials :

  • Username : admin
  • Password : (celui récupéré par la commande)

argocd_accueil.png

Je me connecte via https://localhost:8080 et... je suis dans ArgoCD !

Étape 5 : Installation du CLI ArgoCD

Pour gérer ArgoCD depuis le terminal, j'installe le CLI :

# Télécharger le binaire
mkdir -p ~/.local/bin
curl -sSL -o ~/.local/bin/argocd \
  https://github.com/argoproj/argo-cd/releases/latest/download/argocd-linux-amd64

# Rendre exécutable
chmod +x ~/.local/bin/argocd

# Vérifier la version
~/.local/bin/argocd version --client

Création d'un alias pour simplifier (dans ~/.zshrc) :

alias argocd="~/.local/bin/argocd --grpc-web"

Le flag --grpc-web évite les warnings gRPC.

Étape 6 : Connexion du CLI au serveur

argocd login argo.home-fonta.fr --username admin --password MOT_DE_PASSE --insecure

Note : --insecure car certificat auto-signé pour l'instant.

Vérification :

argocd cluster list

Résultat :

SERVER                          NAME        VERSION  STATUS   MESSAGE
https://kubernetes.default.svc  in-cluster           Unknown  Cluster has no applications...

Parfait ! ArgoCD est connecté au cluster K3s.

Configuration SSH pour Git (Sécurité)

ArgoCD a besoin d'accéder à mon repository GitHub pour lire les manifests. Deux options :

  1. HTTPS avec token
  2. SSH avec clé privée

J'ai choisi SSH pour plus de sécurité.

Principe : Clé SSH dédiée (Least Privilege)

Mauvaise pratique : Utiliser ma clé SSH personnelle

  • Si le cluster est compromis, l'attaquant a accès à TOUS mes repos GitHub

Bonne pratique : Créer une clé SSH dédiée pour ArgoCD

  • Accès en lecture seule
  • Limitée à UN seul repository
  • Révocation facile sans impacter mes autres accès

Création de la paire de clés

ssh-keygen -t ed25519 -C "argocd@home-fonta-k3s" -f ~/.ssh/argocd_k3s -N ""

Paramètres :

  • -t ed25519 : Type de clé moderne, sécurisé, compact
  • -C "argocd@home-fonta-k3s" : Commentaire pour identifier la clé
  • -f ~/.ssh/argocd_k3s : Nom du fichier
  • -N "" : Pas de passphrase (ArgoCD doit pouvoir l'utiliser automatiquement)

Résultat : 2 fichiers créés

  • ~/.ssh/argocd_k3s (privée)
  • ~/.ssh/argocd_k3s.pub (publique)

Ajout de la Deploy Key sur GitHub

Affichage de la clé publique :

cat ~/.ssh/argocd_k3s.pub

Exemple de sortie :

ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINJOPsG8SCftgMbQYyooLxbpV8VWBlYpC4NRV01DsUpW argocd@home-fonta-k3s

Sur GitHub :

  1. Aller sur https://github.com/Nikob2o/ansible-k3s/settings/keys
  2. Cliquer sur "Add deploy key"
  3. Titre : ArgoCD K3s Cluster - Read Only
  4. Clé : Coller la clé publique complète
  5. IMPORTANT : NE PAS cocher "Allow write access" (lecture seule)
  6. Cliquer sur "Add key"

Deploy Key vs SSH Key personnelle :

  • Deploy Key = Liée à UN repository spécifique
  • SSH Key = Liée à votre compte (accès à tous vos repos)

Création du Secret Kubernetes

ArgoCD a besoin de la clé privée pour se connecter à GitHub :

kubectl create secret generic argocd-repo-ssh-key \
  --from-file=sshPrivateKey=~/.ssh/argocd_k3s \
  -n argocd

Vérification :

kubectl get secret argocd-repo-ssh-key -n argocd

Résultat :

NAME                  TYPE     DATA   AGE
argocd-repo-ssh-key   Opaque   1      10s

Connexion du repository à ArgoCD

argocd repo add git@github.com:Nikob2o/ansible-k3s.git \
  --ssh-private-key-path ~/.ssh/argocd_k3s

Résultat :

Repository 'git@github.com:Nikob2o/ansible-k3s.git' added

Vérification :

argocd repo list
![argocd_repository.png](https://blog.home-fonta.fr/content/images/2025/12/argocd_repository.png)

Le repository est connecté ! ArgoCD peut maintenant lire mes manifests Kubernetes depuis Git.

Structure du repository

Pour ArgoCD, j'ai organisé mon repository ainsi :

ansible-k3s/
├── argocd-apps/              # Définitions des Applications ArgoCD
│   └── applications/         # Applications individuelles (utilisé par App of Apps)
│       ├── home-fonta.yaml
│       ├── ghost.yaml
│       ├── infrastructure.yaml
│       └── external-services.yaml
├── helm-charts/              # Helm charts
│   ├── homefonta/
│   ├── ghost/
│   ├── infrastructure/
│   └── external-services/
└── manifests/                # Manifests Kubernetes bruts
    ├── 01-external-services/
    └── 02-argocd/

État après l'installation

À ce stade, j'avais :

  • ArgoCD installé et accessible via https://argo.home-fonta.fr (via port-forward)
  • CLI ArgoCD configuré
  • Repository Git connecté en SSH (lecture seule)
  • Structure de fichiers prête pour GitOps

Problèmes en suspens :

  • Certificat SSL sur l'Ingress ArgoCD (secret pas dans le bon namespace)
  • Aucune application encore déployée via ArgoCD

Dans la prochaine partie, on va :

  1. Résoudre le problème de certificat avec Reflector
  2. Créer notre première Application ArgoCD
  3. Tester le workflow GitOps complet
  4. Migrer toutes les applications vers ArgoCD

Concepts clés appris

Sécurité SSH et principe de moindre privilège

Une clé par service : Chaque service (ArgoCD, CI/CD, etc.) doit avoir sa propre clé SSH, avec les permissions minimales nécessaires.

Si une clé est compromise, seul ce service est impacté, pas tous vos accès.

Secrets Kubernetes et isolation par namespace

Les Secrets Kubernetes ne sont accessibles que dans leur namespace. C'est une feature de sécurité (compartimentage), pas un bug.

Solutions pour partager un Secret entre namespaces :

  1. Copie manuelle (fastidieux, pas automatique au renouvellement)
  2. Outils de réplication : Reflector, Kubed (automatique)

TLS Termination vs SSL Passthrough

TLS Termination (ce que j'utilise) :

Client --[HTTPS]--> Ingress --[HTTP]--> Service
         ^
    Certificat Let's Encrypt

Avantages :

  • Certificat centralisé (Let's Encrypt)
  • Un seul point de gestion TLS
  • Inspection et logging possibles au niveau Ingress

SSL Passthrough :

Client --[HTTPS chiffré]--> Ingress --[HTTPS chiffré]--> Service
                                       ^
                                  Certificat du service

Avantages :

  • End-to-end encryption
  • Le service contrôle son propre certificat

GitOps : Le paradigme déclaratif

Impératif (avant) :

kubectl apply -f deployment.yaml
kubectl scale deployment my-app --replicas=3
helm upgrade my-app ./chart

Problèmes :

  • Pas d'historique
  • Pas de source de vérité
  • Dérive de configuration inévitable

Déclaratif (GitOps) :

# Je modifie values.yaml dans Git
git commit -m "Scale to 3 replicas"
git push

# ArgoCD détecte et applique automatiquement
# Aucune commande kubectl nécessaire

Avantages :

  • Git = source de vérité unique
  • Historique complet (qui, quoi, quand, pourquoi)
  • Rollback facile (git revert)
  • Code review (Pull Requests)
  • Pas de dérive (auto-correction)

Prochaine partie

Dans la Partie 7, on va :

  1. Installer Reflector pour répliquer le certificat wildcard
  2. Créer notre première Application ArgoCD (home-fonta)
  3. Tester la synchronisation automatique Git vers Kubernetes
  4. Migrer Ghost, Infrastructure et External Services
  5. Implémenter le pattern "App of Apps"
  6. Sécuriser les secrets avec SealedSecrets

Le voyage GitOps continue...


Suite : Partie 7 - ArgoCD en action : Déploiement et GitOps

Read more