DEV Community

Cover image for Gérer son cluster Kubernetes avec la méthode GitOps grâce à Flux2 et GitLab
Katia HIMEUR TALHI
Katia HIMEUR TALHI

Posted on

Gérer son cluster Kubernetes avec la méthode GitOps grâce à Flux2 et GitLab

1. Introduction

Lors de l’édition 2021 de l’open source experience, j’ai eu l’occasion, dans le cadre d’un workshop, de faire une démonstration pour montrer comment nous pouvons gérer un cluster Kubernetes avec la méthode GitOps, notamment grâce à Flux 2 et GitLab. L’objectif de cet article est de vous permettre de reproduire, étape par étape, les étapes de cette démonstration. Dans cet article, nous allons voir comment, grâce à Flux :

  • Déployer des ressources Kubernetes dans un cluster inaccessible depuis Internet (un cluster local pour cet article)
  • Mettre à jour automatiquement le nombre de réplicas déployés
  • Mettre à jour, automatiquement, le tag de l’image Docker déployée

Mais avant de commencer, je vais rappeler la définition du GitOps.

2. Qu’est-ce que le GitOps ?

Le GitOps est une manière d’implémenter le déploiement continu des applications dites cloud natives. L’état désiré des infrastructures est décrit de manière déclarative dans un répertoire Git. Et un processus automatisé vient vérifier que l’état décrit désiré correspond à l’état actuel. Si cela n’est pas le cas, il fait en sorte d’appliquer les modifications nécessaires.
Comme son nom l’indique, dans la méthode GitOps, le répertoire Git est l’élément central.

Parmi les avantages du GitOps, nous pouvons citer :

  • Réduction du nombre d’outils utilisés : Git devient l’élément central
  • Disposer d’un historique des changements
  • Facilité des retours arrières
  • Gérer ses déploiements depuis l’environnement et non plus depuis l'extérieur.
  • Possibilité d’avoir le descriptif complet des éléments déployés en consultant les manifests.

3. Avant de commencer

Avant de commencer, il nous faut répondre à plusieurs pré-requis :

  • Un cluster Kubernetes fonctionnel : pour la suite de cet article, je vais travailler avec un cluster Kubernetes local.
  • La CLI Flux installée
  • Un token GitLab : GitLab Personal access tokens

Je vais également utiliser Kustomize pour écrire et organiser mes ressources Kubernetes. Outil dont j’ai déjà parlé ici : Introduction to Kustomize: how to customize Kubernetes objects

4. Organisation des répertoires Git sur GitLab

J’ai créé deux projets GitLab pour ma démonstration :

  • my-infra : répertoire Git que je laisse volontairement vide au début et où mon code d’infrastructure sera versionné
  • my-app : contient les sources de mon application, les manifestes Kubernetes qui permettent de la déployer et le pipeline de CI/CD qui permet de créer une image Docker à chaque création de tag Git. Cette image est ensuite poussée dans le registre d’images de conteneurs GitLab. Les sources complètes sont ici : Sources

5. Vérifier que le cluster Kubernetes répond aux pré-requis de Flux

Avant d’initialiser Flux dans mon cluster, je vais vérifier que ce dernier répond à la liste des pré-requis attendus par Flux. Pour ce faire, je vais exécuter la commande suivante :

flux check --pre
Enter fullscreen mode Exit fullscreen mode

Résultats de la vérification des pré-requis Flux

6. Initialiser Flux (Bootstrap)

flux bootstrap gitlab \
  --owner=demo-flux \
  --repository="my-infra" \
  --branch=main \
  --path=clusters/local \
  --token-auth \
  --personal
Enter fullscreen mode Exit fullscreen mode

Cette commande permet d’installer les composants nécessaires au bon fonctionnement de Flux et de mettre à jour le répertoire GitLab my-infra avec la configuration générée automatiquement.
Comme je suis dans un environnement local, je demande à Flux, grâce au paramètre —path de mettre la configuration de mon environnement dans clusters/local.

7. Créer un namespace Kubernetes grâce à Flux

Avant de déployer mon application, je veux que Flux crée le namespace my-app. Je mets les manifestes dans le dossier infrastructure à la racine du répertoire my-infra. Maintenant, il faut que je prévienne Flux de prendre en compte ces manifestes. Pour cela je crée le fichier infrastructure.yaml dans clusters/local.

---
apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
kind: Kustomization
metadata:
  name: infrastructure
  namespace: flux-system
spec:
  interval: 30s
  sourceRef:
    kind: GitRepository
    name: flux-system
  path: ./infrastructure/local
  prune: true
  validation: client
Enter fullscreen mode Exit fullscreen mode

Je commit et je push ce fichier. J’attends quelques secondes pour que Flux voit mes modifications et hop, le namespace est créé.

8. Déployer mon application

Mon application est une simple page Index.html que j’utilise pour remplacer l’image par défaut de Nginx. Je versionne dans un autre répertoire Git mes sources.
Pour déployer dans mon cluster, je crée deux ressources Kubernetes : un déploiement et un service. Mes manifestes sont dans le dossier manifests/.

La première étape pour déployer est de dire à Flux quelle source Git utiliser (Ressource GitRepository). Mais avant, pour générer le bon manifeste, j’exécute la commande suivante :

flux create source git my-app \
  --url=https://gitlab.com/demo-flux/my-app.git \
  --branch=main \
  --interval=30s \
  --export > ./clusters/local/my-app-source.yaml
Enter fullscreen mode Exit fullscreen mode

Cette commande va générer le fichier my-app-source.yaml

---
apiVersion: source.toolkit.fluxcd.io/v1beta1
kind: GitRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 30s
  ref:
    branch: main
  url: https://gitlab.com/demo-flux/my-app.git
Enter fullscreen mode Exit fullscreen mode

Pour que Flux puisse voir cette ressource, je pousse ma modification sur le répertoire distant. Pour vérifier la prise en compte de ma modification, j’exécute la commande suivante :

flux get sources git --watch
Enter fullscreen mode Exit fullscreen mode

La seconde étape est d’indiquer à Flux où se situent les manifestes qui concernent mon environnement. Pour cela, je génère la ressource Kustomization grâce à la commande suivante :

flux create kustomization my-app \
  --target-namespace=my-app \
  --source=my-app \
  --path="./manifests/local" \
  --prune=true \
  --interval=30s \
  --export > ./clusters/local/my-app-kustomization.yaml
Enter fullscreen mode Exit fullscreen mode

Le fichier my-app-kustomization.yaml est le suivant :

--------
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
  name: my-app
  namespace: flux-system
spec:
  interval: 30s
  path: ./manifests/local
  prune: true
  sourceRef:
    kind: GitRepository
    name: my-app
  targetNamespace: my-app
Enter fullscreen mode Exit fullscreen mode

Une fois la modification poussée sur le répertoire Git distant, je vérifie la prise en compte de ma modification grâce à la commande

flux get kustomizations --watch
Enter fullscreen mode Exit fullscreen mode

J’attends quelques secondes et Flux va déployer mon application.

Maintenant, je souhaite modifier le nombre de réplicas de mon déploiement. Je crée une branche où j’apporte les modifications nécessaires aux manifestes

Changement du nombre de réplicas

Je merge et j’attends quelques secondes, le temps que Flux voit la modification. J’ai maintenant deux pods au lieu d’un seul.

9. Mettre à jour l’image Docker déployée automatiquement grâce à Flux

A ce stade de l’article, le tag de l’image Docker déployée est écrit en dur dans les manifestes. Si je souhaite modifier le tag déployé, je dois modifier le manifeste. Je souhaite déléguer cette mission à Flux pour ne pas avoir à le faire manuellement.

Premièrement, je réxécute la commande bootstrap pour installer les composants nécessaires :

flux bootstrap gitlab \
  --owner=demo-flux \
  --components-extra=image-reflector-controller,image-automation-controller \
  --repository="my-infra" \
  --branch=main \
  --path=clusters/local \
  --token-auth \
  --personal
Enter fullscreen mode Exit fullscreen mode

J’ai ajouté le paramètre —composants-extra qui va me déployer deux nouveaux pods. À chaque fois que je crée ou modifie un manifeste existant, je commit et pousse mes modifications systématiquement sur le répertoire Git distant pour que Flux prenne en compte ces changements.

Ensuite, je crée un token GitLab qui doit avoir les droits de lecture et d’écriture sur le répertoire Git de mon application. Je stocke ce token et l’identifiant dans un secret Kubernetes

kubectl create secret generic -n flux-system https-credentials \
  --from-literal=username="${GITLAB_USERNAME}" --from-literal=password="${GITLAB_TOKEN}"
Enter fullscreen mode Exit fullscreen mode

Je mets à jour la ressource GitRepository créée au début, afin de lui spécifier ce secret à utiliser

flux create source git my-app \
  --url=https://gitlab.com/demo-flux/my-app.git \
  --branch=main \
  --interval=30s \
  --secret-ref=https-credentials \
  --export > ./clusters/local/my-app-source.yaml
Enter fullscreen mode Exit fullscreen mode

J’ai ajouté le paramètre —secret.

Maintenant, je vais créer une ressource Image repository pour dire à Flux quel registre d'images de conteneurs scanné :

flux create image repository my-app \
--image=registry.gitlab.com/demo-flux/my-app \
--interval=30s \
--export > ./clusters/local/my-app-registry.yaml
Enter fullscreen mode Exit fullscreen mode

Le manifeste créé est le suivant :

--------
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImageRepository
metadata:
  name: my-app
  namespace: flux-system
spec:
  image: registry.gitlab.com/demo-flux/my-app
  interval: 30s
Enter fullscreen mode Exit fullscreen mode

Une fois la ressource créée, je crée une image policy. Je génère le manifeste qui décrit cette ressource avec la commande suivante :

flux create image policy my-app \
--image-ref=my-app \
--select-semver=1.0.x \
--export > ./clusters/local/my-app-policy.yaml
Enter fullscreen mode Exit fullscreen mode

Le fichier généré est le suivant :

--------
apiVersion: image.toolkit.fluxcd.io/v1beta1
kind: ImagePolicy
metadata:
  name: my-app
  namespace: flux-system
spec:
  imageRepositoryRef:
    name: my-app
  policy:
    semver:
      range: 1.0.x
Enter fullscreen mode Exit fullscreen mode

Je choisis le semantic versioning comme police. Je vais créer un tag Git 1.0.0 pour créer une image Docker avec le même tag.

Maintenant, la dernière étape est de créer une ressource de type Image Update Automation

flux create image update my-app \
--git-repo-ref=my-app \
--git-repo-path="./manifests/base" \
--checkout-branch=main \
--push-branch=main \
--author-name=fluxcdbot \
--author-email=fluxcdbot@users.noreply.github.com \
--commit-template="{{range .Updated.Images}}{{println .}}{{end}}" \
--export > ./clusters/local/my-app-automation.yaml
Enter fullscreen mode Exit fullscreen mode

Avec cette commande, je spécifie à Flux où se trouve l’image déployée avec le paramètre —git-repo-path. Et dans le manifeste Kubernetes de mon déploiement, je vais ajouter une annotation au niveau de la ligne de l’image

# {"$imagepolicy": "flux-system:my-app"}

Dès que je la pousse dans le répertoire distant et que Flux détecte le nouveau tag créé, il va se charger de mettre à jour le manifeste dans le répertoire my-app. Ensuite Flux va détecter que le manifeste a changé et il va donc appliquer la modification. Et c’est ainsi, que l’image déployée est mise à jour automatiquement, sans intervention humaine.

10.Conclusion :

Flux est un outil très puissant et simple à utiliser qui permet d’implémenter le déploiement continu avec la méthode GitOps et ainsi de bénéficier de ces nombreux avantages.

Discussion (0)