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

Woulf @woulf

Joined:
Mar 3, 2025

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

Publish Date: May 30
0 0

Mise en place d’un GitOps multi-environnement auto-hébergé avec Argo CD, Kustomize et cert-manager sur MicroK8s : architecture, défis, erreurs, et automatisation des déploiements Kubernetes.

🌍 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 : distribution légère de Kubernetes, mono-nœud

  • 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 continu

  • 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
Enter fullscreen mode Exit fullscreen mode

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.


📦 Gestion multi-environnement avec Kustomize

Kustomize est l’outil que j’utilise pour gérer proprement mes différents environnements (dev, staging, prod) à partir d’une base commune de ressources Kubernetes. Contrairement à Helm, il ne nécessite pas de moteur de templating externe. On parle ici de composition de fichiers déclaratifs plutôt que de génération dynamique.

Chaque environnement hérite des ressources communes de base/, et vient appliquer des patches spécifiques (ex : nom de domaine, image Docker, namespace...).

Exemple :

.
├── base/
│   └── portfolio/
│       ├── kustomization.yaml
│       ├── deployment.yaml
│       ├── service.yaml
│       └── ingress.yaml
├── environments/
│   ├── dev/
│   │   ├── kustomization.yaml
│   │   └── patch-ingress-host.json
│   ├── staging/
│   └── prod/
Enter fullscreen mode Exit fullscreen mode

Chaque répertoire (qu’il s’agisse de base ou d’un environnement comme dev, staging ou prod) contient un fichier kustomization.yaml obligatoire. Ce fichier décrit les ressources Kubernetes à assembler ainsi que les éventuelles modifications spécifiques à l’environnement (comme un patch JSON pour changer le host de l’Ingress).

Cette approche permet une composition claire et modulaire des ressources, tout en gardant un contrôle précis sur les différences entre environnements.

Exemple :
environments/dev/kustomization.yaml :

namespace: dev
resources:
  - ../../base/portfolio
patches:
  - path: patch-ingress-host.json
    target:
      kind: Ingress
      name: portfolio-ingress
Enter fullscreen mode Exit fullscreen mode

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" }
]
Enter fullscreen mode Exit fullscreen mode

👉 Avec cette structure, je peux déployer le même projet dans plusieurs environnements en changeant uniquement le contexte et quelques variables cibles.

🔍 Petit tip : pour valider la sortie Kustomize en local avant de confier le déploiement à Argo CD, on peut utiliser :
kubectl kustomize environments/dev
Cela génère le YAML final tel qu’il sera appliqué dans le cluster.

Et on peut l'appliquer comme ça :
kubectl apply -k environments/dev


🚀 Pourquoi j’utilise Argo CD ?

Argo CD est le cœur de ma stratégie GitOps : c’est lui qui veille à ce que l’état réel du cluster Kubernetes soit toujours synchronisé avec les manifests Git.

Ce que j’apprécie dans Argo CD :

  • Interface visuelle claire de l’état des déploiements
  • Déploiement automatique (pull-based) dès qu’un commit est détecté
  • Historique des modifications, gestion des rollback
  • Vérification automatique de la dérive de configuration
  • Facilité de ciblage d’environnements/namespaces spécifiques

⚙️ 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
Enter fullscreen mode Exit fullscreen mode

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.


📌 Définir un déploiement GitOps avec 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
Enter fullscreen mode Exit fullscreen mode

👉 Le fichier Application Argo CD est également versionné dans mon dépôt Git, visible ici : argocd/applications/portfolio-dev.yaml.

🔍 Comment ça fonctionne

  1. source.repoURL + path + targetRevision

    Argo CD surveille le répertoire environments/dev du dépôt Git https://github.com/Wooulf/devops-bootcamp-ippon. Toute modification (commit, push) dans ce dossier déclenche une synchronisation automatique.

  2. destination

    L’application est déployée dans le cluster local (MicroK8s) via l’URL https://kubernetes.default.svc, dans le namespace dev.

  3. 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.
  4. syncOptions.CreateNamespace=true

    Le namespace dev 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.

Vue Argo CD listant trois applications déployées : portfolio-dev, portfolio-staging et portfolio-prod. Chacune est en état Healthy et Synced, avec leurs chemins Git, namespaces et dernières synchronisations visibles.

🎯 Interface Argo CD : état de santé et synchronisation des environnements dev, staging et prod.

Vue détaillée de l'application Argo CD portfolio-dev : affichage arborescent des ressources Kubernetes créées (Deployment, Service, Ingress, Certificate, Pod), toutes en état Healthy et synchronisées avec Git.

🔍 Vue détaillée de l'application portfolio-dev déployée dans le namespace dev — chaque ressource est traquée, versionnée, et synchronisée à Git.


🧨 Problèmes rencontrés (et résolus)

  • Certificats auto-signés persistants J’ai eu des certificats non valides persistants (auto-signés) à cause de deux mécanismes de création simultanés : une annotation cert-manager.io/cluster-issuer sur l’Ingress et une configuration server.certificate dans les values.yaml de Helm. 👉 Solution : ne conserver qu’une seule source de vérité. Ici, la configuration Helm via server.certificate.

 

  • Certificat temporaire actif après provisionnement Let's Encrypt Cert-manager installe parfois un certificat temporaire avant que Let's Encrypt émette le définitif. 👉 Il suffit d’attendre la mise à jour, c’est un comportement normal.

 

  • MicroK8s qui "perd" des add-ons (Helm, DNS, etc.) après redémarrage J’ai constaté que certains add-ons de MicroK8s se désactivaient au reboot. 👉 Nécessité de relancer manuellement certains services.

 

  • ClusterIssuer manquant après reboot du cluster Après redémarrage, mon ClusterIssuer n’était plus reconnu. Cela venait d’un oubli de le versionner dans mon GitOps au début. 👉 Résolu en l’ajoutant explicitement dans les manifests surveillés par Argo CD.

 

  • Erreurs d’accès HTTPS malgré une config a priori correcte Liées dans mon cas à un certificat temporaire encore actif, ou à une mauvaise terminaison TLS côté Ingress. 👉 En fixant la gestion TLS uniquement au niveau Ingress, le problème a disparu.

🧾 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’environnement dev, patché dynamiquement via kustomize

Ce socle technique me permet désormais de tester, versionner et sécuriser mes déploiements comme en production, tout en gardant un maximum de contrôle sur l'infrastructure.


🔜 À 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.

Comments 0 total

    Add comment