De l'artisanat à l'industrialisation : GitOps multi-env avec Argo CD et Kustomize sur MicroK8s

🌍 Contexte : Pourquoi ce projet ?
Ce projet est le prolongement logique d'une démarche amorcée plusieurs mois auparavant. Initialement, mon infrastructure était gérée de façon artisanale : quelques fichiers Kubernetes posés dans un repository, un Ingress pour gérer le trafic entrant, un certificat Let’s Encrypt, un déploiement de mon app exposée en interne via un service ClusterIP, ainsi qu'un NodePort pour l'exposition externe.
Mais rapidement, cette approche a montré ses limites :
-
Pas de gestion multi-environnement
-
Pas de vision d'ensemble de l'état du cluster
-
Mises à jour via pipelines mais limitées (uniquement création ou mise à jour de ressources, le reste devant se faire manuellement), sans historique clair
Je voulais un setup plus robuste, plus proche de ce qui se fait en entreprise : versionnement complet de l'infrastructure, déploiement multi-env, GitOps, monitoring plus complet (traces, logs) et sécurité.
🚀 Objectifs techniques
Ce nouveau projet vise à construire une base solide et maintenable pour déployer n'importe quelle application dans un cluster Kubernetes auto-hébergé. Les piliers :
-
GitOps avec Argo CD pour des déploiements déclaratifs
-
Multi-environnement (dev, staging, prod...) via kustomize
-
Certificats TLS gérés automatiquement par cert-manager
-
Ingress NGINX pour l'exposition publique en HTTPS
-
Versionnement complet de l'infra : Ingress, Cert-Manager, Argo CD sont installés via Helm, mais pilotés via Kustomize
-
Namespace par environnement
📊 Stack technique
-
MicroK8s : Kubernetes local optimisé
-
Helm : gestionnaire de chart pour l'installation d'outils comme Argo CD, cert-manager, ingress-nginx
-
Kustomize : overlay d'environnements (dev, prod)
-
Argo CD : moteur GitOps pour le déploiement continue
-
cert-manager + ClusterIssuer Let's Encrypt : certificats TLS publics
📂 Organisation du repo
Le repository est structuré comme suit :
.
├── environments/
│ ├── dev/ # Déploiement dédié au développement
│ ├── staging/ # Environnement de préproduction
│ └── prod/ # Production simulée
├── base/ # Composants K8s communs à tous les environnements
Chaque outil est installé via Helm avec un values.yaml versionné, et les environnements dev/, staging/ et prod/ sont des overlays Kustomize avec des patchs ciblés.
Le repo est disponible ici : github.com/Wooulf/devops-bootcamp-ippon.
⚙️ Installation d'Argo CD avec HTTPS
Argo CD a été installé via Helm dans le namespace argocd
, avec cette configuration :
global:
domain: argocd.woulf.fr
configs:
params:
server.insecure: "true"
server:
certificate:
enabled: true
secretName: argocd-tls
domain: argocd.woulf.fr
issuer:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-prod
ingress:
enabled: true
ingressClassName: nginx
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
hosts:
- argocd.woulf.fr
tls:
- hosts:
- argocd.woulf.fr
secretName: argocd-tls
Pourquoi server.insecure: true
? Car la terminaison TLS est gérée au niveau de l'Ingress. Le trafic interne reste en HTTP, ce qui est acceptable dans un cluster local/VPS non mutualisé.
🌐 Accès public via Ingress
Le certificat TLS est généré automatiquement par cert-manager à partir du ClusterIssuer letsencrypt-prod
. Argo CD est maintenant accessible publiquement via https://argocd.woulf.fr.
📁 Premier déploiement avec Argo CD
Le déploiement du portfolio se fait via un Application
Argo CD pointant vers le namespace dev. L'Ingress est patché dynamiquement pour chaque environnement via un fichier JSON Kustomize :
environments/dev/kustomization.yaml
namespace: dev
resources:
- ../../base
patches:
- path: patch-ingress-host.json
target:
kind: Ingress
name: portfolio-ingress
environments/dev/patch-ingress-host.json
[
{
"op": "replace",
"path": "/spec/tls/0/hosts/0",
"value": "dev.woulf.fr"
},
{
"op": "replace",
"path": "/spec/rules/0/host",
"value": "dev.woulf.fr"
}
]
🧠 Définition de l'Application
Argo CD
Pour connecter Argo CD à mon dépôt Git et lui indiquer quoi synchroniser dans le cluster, j'ai créé une ressource Kubernetes de type Application
:
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: portfolio-dev
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/Wooulf/devops-bootcamp-ippon
targetRevision: HEAD
path: environments/dev
destination:
server: https://kubernetes.default.svc
namespace: dev
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
🔍 Comment ça fonctionne
-
source.repoURL + path + targetRevision
Argo CD surveille le répertoireenvironments/dev
du dépôt Githttps://github.com/Wooulf/devops-bootcamp-ippon
. Toute modification (commit, push) dans ce dossier déclenche une synchronisation automatique. -
destination
L’application est déployée dans le cluster local (MicroK8s) via l’URLhttps://kubernetes.default.svc
, dans le namespacedev
. -
syncPolicy.automated
automated
: synchronisation automatique sans action manuelle.prune
: suppression des ressources obsolètes qui ne sont plus déclarées dans Git.selfHeal
: restauration automatique si une ressource est modifiée manuellement dans le cluster.
-
syncOptions.CreateNamespace=true
Le namespacedev
est créé automatiquement s’il n’existe pas encore, rendant le déploiement autonome et idempotent.
🔁 Résultat final
- Déploiement GitOps complet et automatique dans l’environnement
dev
- Conformité assurée en permanence entre Git et le cluster
- Mise à jour ou suppression de ressources pilotée uniquement depuis le dépôt Git
- Namespace
dev
créé dynamiquement sans préconfiguration manuelle
Le portfolio dev
est maintenant déployé automatiquement avec la dernière image Docker taggée latest
, et accessible via https://dev.woulf.fr.
🧨 Problèmes rencontrés (et résolus)
-
Certificats auto-signés persistants : dus à un conflit entre plusieurs objets Certificate, causé par la présence d’annotations
cert-manager.io/cluster-issuer
sur l’Ingress et une sectionserver.certificate
dans lesvalues.yaml
. 👉 Solution : ne garder que la config server.certificate. -
Certificat temporaire utilisé même après provisionnement Let's Encrypt : comportement par défaut de cert-manager. Il faut juste patienter que le bon cert soit émis.
-
microk8s qui "perd" les addons (helm, dns, etc.) après reboot : nécessité de relancer les activations.
-
ClusterIssuer non appliqué après reboot : il faut le re-pusher si non persisté.
-
Erreurs d’accès HTTPS alors que tout semblait bon : souvent liées au certificat temporaire ou à une mauvaise terminaison TLS (que j'ai arrêté à l'ingress après coup).
Ces problématiques m'ont aussi amené à réfléchir à l'intérêt d'introduire un outil comme Ansible en complément d'Argo CD. Là où Argo veille à la conformité du state Kubernetes avec les manifests Git, Ansible pourrait m'aider à m'assurer que l'état global du système hôte (MicroK8s, add-ons actifs, prérequis réseau, etc.) est également conforme à mes attentes.
🧾 En résumé
Dans cet article, j’ai amorcé la transition vers une infrastructure GitOps multi-environnement, avec :
-
L’installation d’Argo CD via Helm dans un namespace dédié
-
La gestion du HTTPS avec cert-manager et un ClusterIssuer Let’s Encrypt
-
La résolution de problèmes classiques liés aux certificats (self-signed, temporaires, double création de certificat)
-
L’exposition d’Argo CD en HTTPS via Ingress NGINX
-
Le premier déploiement GitOps d’une application (
portfolio
) dans l’environnementdev
, patché dynamiquement viakustomize
🔜 À venir dans le prochain article
On poursuivra en intégrant Argo CD Image Updater pour assurer la mise à jour automatique des images déployées, en ajoutant une couche de sécurité avec SealedSecrets pour protéger le token d'API permettant d'interagir avec Argo CD. On verra aussi comment rendre ce système autonome, sans intervention manuelle, toujours dans une logique GitOps.