Aller au contenu

À la découverte de Cluster API : le cluster de Workload

Romain Boulanger
Auteur
Romain Boulanger
Architecte Infra/Cloud avec une touche de DevSecOps
Sommaire
À la découverte de Cluster API - Cet article fait partie d'une série.
Partie 3: Cet article

Ultime étape de cette série sur Cluster API, j’ai nommé le cluster de Workload.

Dans la partie 2 de cette série, on a posé la première brique : un cluster de Management, créé par Cluster API et l’ensemble des Providers définis, avec une configuration migrée grâce au mécanisme de pivot. Pour rappel, ce cluster de Management se veut être le chef d’orchestre pour déployer des clusters Kubernetes en fonction des usages.

Petit problème : un chef d’orchestre sans musiciens ne vous donnera pas le concert du siècle ! C’est là qu’interviennent les clusters de Workload ou Workload clusters, ceux qui vont réellement faire tourner vos applications.

Un point de situation s’impose…
#

Comme dit, le cluster de Management est pleinement opérationnel et prêt à créer ces fameux clusters de Workload.

La différence entre les deux types de clusters a déjà été évoquée dans les précédentes parties, mais elle mérite d’être rappelée très succinctement une nouvelle fois tellement celle-ci est centrale dans la philosophie de Cluster API.

Le cluster de Management ne fait tourner aucune charge de travail métier, son unique fonction est de piloter le cycle de vie des autres clusters. Le cluster de Workload, lui, c’est l’inverse : il ne doit pas gérer l’infrastructure, il est là pour exécuter vos Deployments, vos Services, bref, vos applications favorites.

Concrètement, quand on crée les ressources d’un cluster de Workload, le Management cluster reprend exactement la même mécanique que celle vue lors de sa propre création. Le Core Provider détecte l’objet Cluster et les ressources sous-jacentes, sollicite CAPMOX pour dialoguer avec l’API de Proxmox et déployer les machines virtuelles, pendant que CABPT et CACPPT génèrent la configuration Talos et pilotent le Control Plane. La seule différence, c’est qu’on ne parle plus de pivot cette fois puisque le cluster de Workload n’a pas vocation à héberger lui-même les controllers Cluster API, il reste sous la coupe du cluster de Management durant tout son cycle de vie.

Provisioning avec Cluster API

On s’occupe maintenant du déploiement de la partie de droite, le cluster de Workload entièrement géré par le cluster de Management

GitOps ? Vous avez dit GitOps ?
#

Créer un cluster Kubernetes manuellement avec un kubectl create -f, ça a déjà été fait dans la partie 2, et ça reste correct dans une phase de bootstrap ou pour un premier cluster, mais dès que l’on veut gérer une flotte de clusters, plusieurs équipes, plusieurs environnements, cette approche montre vite ses limites.

On revient alors à un des principes fondateurs de tout ce qu’on a vu jusqu’ici : décrire l’état désiré, laisser une couche de réconciliation faire converger l’état courant vers celui-ci.

Vous l’aurez compris, l’approche déclarative des ressources de Cluster API se marie naturellement avec le GitOps, où l’ensemble de l’infrastructure des futurs clusters peut être défini dans un dépôt Git et administré depuis un outil tel qu’Argo CD !

L’heure est d’abord à l’enrichissement du cluster de Management pour en faire une véritable tour de contrôle…

Enrichir le cluster de Management
#

Argo CD est un choix clairement personnel, ses nombreuses ressources personnalisées (CRD) permettent d’automatiser la génération et le déploiement de clusters avec une interface qui ne cesse d’évoluer. Si vous préférez Flux CD ou autre outil de ce genre, c’est clairement à vous de voir.

Comme d’habitude, j’ai enrichi le dépôt de code GitHub avec les YAML pour cette partie :

Ensuite, pour Argo CD sur le cluster de Management, je vous propose d’utiliser le chart Helm officiel :

helm install \
  argocd \
  oci://ghcr.io/argoproj/argo-helm/argo-cd \
  --version 10.3.3 \
  --namespace argocd \
  --create-namespace \
  --values ./clusters/kmgt/charts/argo-cd.yaml \
  --wait

Le fichier values en question ./clusters/kmgt/charts/argo-cd.yaml dispose de quelques paramètres pour limiter le déploiement aux seuls composants indispensables et aussi pour paramétrer le mot de passe à admin pour les besoins de la démo.

Une fois Argo CD correctement installé, ce que l’on peut confirmer avec ce retour :

kubectl -n argocd get po
NAME                                                READY   STATUS    RESTARTS   AGE
argocd-application-controller-0                     1/1     Running   0          13s
argocd-applicationset-controller-6c9d8ff878-248fv   1/1     Running   0          15s
argocd-redis-6b5b88f8c6-dkw8n                       1/1     Running   0          15s
argocd-repo-server-8644c4759f-q7lhk                 1/1     Running   0          15s
argocd-server-54cb6dcdd8-jdjts                      1/1     Running   0          15s

Quelques variables supplémentaires sont nécessaires. Avant tout, je vous conseille de cloner ou forker mon dépôt de code pour ajuster les valeurs des configurations des clusters en fonction de vos besoins, car il va être utilisé par Argo CD pour récupérer les informations des Applications ou ApplicationSets afin de déployer ces derniers et configurer le Cluster API Operator directement.

Pour cela, si vous mettez votre nouveau repo en mode privé, n’hésitez pas à générer un token appelé aussi Personal Access Token (PAT) pour donner la permission à Argo CD d’y accéder, ce qui demande d’ajouter ces quelques lignes côté variables d’environnement :

export ARGO_CD_REPOSITORY_URL=    # Votre repo Git
export ARGO_CD_REPOSITORY_BRANCH= # Votre branche principale (généralement main)
export ARGO_CD_REPOSITORY_TOKEN=  # Votre token (PAT)

Une fois le code poussé et les quelques fichiers modifiés avec vos valeurs, on va déployer l’ensemble des ressources nécessaires qui seront templatisées avec les valeurs du dessus :

envsubst < ./clusters/kmgt/resources/argo-cd-repository.yaml | kubectl -n argocd create -f -
envsubst < ./clusters/kmgt/resources/argo-cd-appproject.yaml | kubectl -n argocd create -f -
envsubst '${ARGO_CD_REPOSITORY_URL} ${ARGO_CD_REPOSITORY_BRANCH}' < ./clusters/kmgt/resources/argo-cd-application-capi-operator.yaml | kubectl -n argocd create -f - # Évite d'écraser la valeur de $values
envsubst < ./clusters/kmgt/resources/argo-cd-applicationset-clusters.yaml | kubectl -n argocd create -f -

Je vous propose donc une structure classique :

  • Un Secret pour configurer l’accès au dépôt de code ;
  • Un AppProject pour centraliser l’ensemble de la configuration sous forme de dossier dans Argo CD et limiter les sourceRepos pour éviter les erreurs ;
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
  name: clusters
spec:
  description: "Clusters configuration"
  sourceRepos:
    - ${ARGO_CD_REPOSITORY_URL}
    - https://kubernetes-sigs.github.io/cluster-api-operator
[...]
  • L’Application pour le Cluster API Operator en venant récupérer le chart officiel en l’associant avec les values du fichier ./clusters/kmgt/charts/cluster-api-operator.yaml :
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: cluster-api-operator
spec:
  project: clusters
  sources:
    - repoURL: "https://kubernetes-sigs.github.io/cluster-api-operator"
      chart: cluster-api-operator
      targetRevision: 0.27.0
      helm:
        valueFiles:
          - $values/clusters/kmgt/charts/cluster-api-operator.yaml
    - repoURL: ${ARGO_CD_REPOSITORY_URL}
      targetRevision: ${ARGO_CD_REPOSITORY_BRANCH}
      ref: values
[...]
  • Et enfin la fameuse ApplicationSet pour créer autant d’Applications pour déployer les clusters que de sous-dossiers dans clusters :
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
  name: clusters
spec:
  generators:
    - git:
        repoURL: ${ARGO_CD_REPOSITORY_URL}
        revision: ${ARGO_CD_REPOSITORY_BRANCH}
        directories:
          - path: clusters/*
[...]

Avec la configuration présente, les clusters kmgt et kwkd seront visibles au sein d’Argo CD. Mais attention, on n’a pas encore évoqué la configuration du cluster de Workload, ça arrive !

L’ApplicationSet est une ressource intéressante dans ce cas de figure car l’ajout d’un dossier dans clusters ne nécessite pas de modifier quoi que ce soit côté configuration !

Pour accéder à Argo CD, vous pouvez utiliser le port-forward et ainsi naviguer dans l’interface pour déployer la dernière version du Cluster API Operator et s’assurer que le cluster kmgt est bien visible :

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

Le cluster de Management est paré pour mettre en pratique le déploiement de clusters en mode GitOps. On va pouvoir aller plus loin…

Une étape en plus vers l’automatisation à 100%
#

Dans la partie 2, lorsque le cluster de Management a été déployé, il restait une phase fortement manuelle : il était nécessaire d’installer deux composants essentiels comme Cilium et le Talos Cloud Controller Manager pour que le nœud soit dans l’état Ready.

De plus, avec l’envie de faire du GitOps, ce serait dommage de conserver cette partie à base de helm install qui casse le principe d’automatisation de bout en bout.

C’est pourquoi je vous propose d’ajouter un nouveau composant au Cluster API Operator pour installer automatiquement des charts Helm en fonction de labels : le Cluster API Add-on Provider for Helm ou CAAPH.

Cet addon fonctionne avec une ressource dédiée, le HelmChartProxy, qui cible les clusters possédant un certain label et y injecte un chart Helm avec les valeurs souhaitées.

On y reviendra plus en détail dans la section suivante, mais l’idée générale est là : dès qu’un Cluster avec des labels définis dans un HelmChartProxy apparaît, CAAPH s’occupera d’installer le chart en question sur ce dernier. Le nœud passera donc de NotReady à Ready de façon totalement autonome, sans que l’on ait à exécuter un seul helm install à la main.

Par exemple, si vous créez un HelmChartProxy pour installer Argo CD:

apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: argocd
spec:
  clusterSelector:
    matchLabels:
      gitops: argocd

Si votre Cluster dispose d’un label gitops: argocd, l’installation du chart s’exécutera dès que l’API du cluster en question sera opérationnelle.

Si vous avez correctement resynchronisé le Cluster API Operator dans Argo CD, vous devriez voir le namespace caaph-system ainsi que le Pod associé :

kubectl get pods -A | grep caaph-system

Maintenant, place à l’exécution de commandes et la mise à jour de fichiers !

Les mains dans le cambouis, le retour
#

Structure d’un cluster de Workload
#

Un cluster de Workload est un ensemble de nœuds dont certains sont dédiés aux tâches de Control Planes, mais il y a aussi des Workers ! Et cette seconde partie est complètement inédite.

Je vous propose, avant d’attaquer le vif du sujet, de voir ce dont l’on aura besoin en termes de configuration pour déployer le tout !

Structure d’un cluster de Workload complet

Structure complète d’un cluster Kubernetes avec ressources pour les Control Planes et Workers

Inutile de reparcourir l’ensemble des ressources, je vous invite à relire mon article sur le cluster de Management pour avoir un aperçu des ressources Cluster et celles pour les Control Planes.

Côté Workers, il y a :

  • Le MachineDeployment qui rassemble les deux composants du dessous pour faire le lien entre l’infrastructure (ProxmoxMachineTemplate) et le bootstrap (TalosConfigTemplate) qui permettra d’initialiser le ou les nœuds. Sans oublier le rattachement au cluster via le champ clusterName ainsi que certaines caractéristiques sur le nombre de nœuds (replicas) ou encore la version Kubernetes (version). Enfin, comme vous pouvez le constater, cette ressource est conçue pour désigner un ensemble de nœuds avec les mêmes caractéristiques, mais il est tout à fait possible de créer plusieurs ressources MachineDeployment différentes pour un seul et même Cluster :
apiVersion: cluster.x-k8s.io/v1beta2
kind: MachineDeployment
[...]
spec:
  clusterName: kwkd
  replicas: 1
  template:
    spec:
      clusterName: kwkd
      version: v1.36.2
      infrastructureRef:
        apiGroup: infrastructure.cluster.x-k8s.io
        [...]
      bootstrap:
        configRef:
          apiGroup: bootstrap.cluster.x-k8s.io
          [...]
  • Le TalosConfigTemplate, même chose que les Control Planes, donne la possibilité de surcharger la configuration de base de Talos Linux en ajoutant différents types de caractéristiques avec le champ strategicPatches tout en spécifiant que cette configuration doit être adaptée pour des Workers : generateType: worker. La configuration se veut moins verbeuse que ce que l’on a vu précédemment car les Workers ne contiennent pas de composants spécifiques comme l’API Server ou autres :
apiVersion: bootstrap.cluster.x-k8s.io/v1alpha3
kind: TalosConfigTemplate
[...]
spec:
  template:
    spec:
      generateType: worker
      talosVersion: v1.13.7
      strategicPatches:
        - |
          machine:
            install:
              disk: /dev/sda
              extraKernelArgs:
                - net.ifnames=0
            network:
              interfaces:
                - deviceSelector:
                    busPath: "0*"
                  dhcp: false
            kubelet:
              extraArgs:
                cloud-provider: external
                rotate-server-certificates: true
  • Le ProxmoxMachineTemplate, là aussi même chose que les Control Planes, ici le but est de définir les caractéristiques techniques des machines virtuelles : cpu, mémoire, réseau, espace disque, templateID, tags, etc.
apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: ProxmoxMachineTemplate
[...]
spec:
  template:
    spec:
      full: true
      sourceNode: proxmox
      templateID: 5001 # talos-v1.13.7-wk-tmpl
      format: qcow2
      numSockets: 1
      numCores: 2
      memoryMiB: 4096
[...]

Assez de théorie, c’est l’heure de réaliser le déploiement !

Déploiement étape par étape
#

Première étape, il est important de rejouer le script scripts/create-talos-template.sh au sein du shell de Proxmox pour créer un template pour les Workers, la différence se situe dans le fait de rajouter un disque de données si jamais les Pods ont besoin de stockage persistent.

Ensuite, vous pouvez vous connecter à Argo CD depuis le cluster de Management avec la commande port-forward en prenant le bon kubeconfig :

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

Comme évoqué plus haut, le cluster de Workload, ici appelé kwkd, dispose d’un dossier à son nom avec la configuration au sein de clusters/kwkd/config.yaml.

Il est important que vous preniez le temps de modifier les caractéristiques, notamment réseau, en fonction de votre adressage côté ProxmoxCluster :

apiVersion: infrastructure.cluster.x-k8s.io/v1alpha2
kind: ProxmoxCluster
[...]
spec:
  allowedNodes:
    - proxmox
  controlPlaneEndpoint:
    host: 192.168.1.151
    port: 6443
  dnsServers:
    - 192.168.1.1
  ipv4Config:
    addresses:
      - 192.168.1.130-192.168.1.140
    gateway: 192.168.1.1

Sans oublier la VIP du Control Plane, sinon le cluster restera bloqué dans son initialisation :

apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
kind: TalosControlPlane
[...]
spec:
[...]
      strategicPatches:
        - |
          [...]
            network:
              interfaces:
                - deviceSelector:
                    busPath: "0*"
                  dhcp: false
                  vip:
                    ip: 192.168.1.151 # Cela doit correspondre au controlPlaneEndpoint.host

Dernier point, les deux HelmChartProxy à la fin du fichier qui permettent d’installer Cilium et le Talos Cloud Controller Manager pour avoir un Cluster prêt à l’emploi :

apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: cilium
[...]
spec:
  clusterSelector:
    matchLabels:
      cni: cilium # Important
  repoURL: https://helm.cilium.io/
  chartName: cilium
  version: 1.19.6
  releaseName: cilium
  namespace: kube-system
  valuesTemplate: |
    operator:
      replicas: 1
[...]
apiVersion: addons.cluster.x-k8s.io/v1alpha1
kind: HelmChartProxy
metadata:
  name: talos-cloud-controller-manager
  namespace: kwkd
spec:
  clusterSelector:
    matchLabels:
      ccm: talos # Important
  repoURL: "oci://ghcr.io/siderolabs/charts"
  chartName: talos-cloud-controller-manager
  version: 0.5.5
  releaseName: talos-ccm
  namespace: kube-system
  valuesTemplate: |
    nameOverride: cloud-controller-manager
    fullnameOverride: cloud-controller-manager

    enabledControllers:
      - cloud-node
      - node-csr-approval

Ainsi, le champ clusterSelector est très important car il permet de désigner les labels qui seront pris en compte pour l’installation du chart en question.

Dans le cas du Cluster kwkd, sans surprise, on souhaite installer les deux :

apiVersion: cluster.x-k8s.io/v1beta2
kind: Cluster
metadata:
  name: kwkd
  namespace: kwkd
  labels:
    cni: cilium
    ccm: talos

Pour finir, côté Argo CD, il reste à synchroniser le cluster-kwkd et voir les ressources se créer une à une pour déployer le tout premier cluster de Workload !

Argo CD avec le déploiement du cluster kwkd

Après quelques minutes, tout devrait être opérationnel avec le statut Ready :

kubectl get nodes -o wide
NAME                 STATUS   ROLES           AGE     VERSION   INTERNAL-IP     EXTERNAL-IP   OS-IMAGE          KERNEL-VERSION          CONTAINER-RUNTIME
kwkdcp-sj4v9         Ready    control-plane   3m9s    v1.36.2   192.168.1.130   <none>        Talos (v1.13.7)   6.18.39-talos (amd64)   containerd://2.2.6
kwkdwk-s5wlq-pzj2l   Ready    <none>          3m12s   v1.36.2   192.168.1.131   <none>        Talos (v1.13.7)   6.18.39-talos (amd64)   containerd://2.2.6

Pour cela, on peut analyser l’exécution des charts Helm :

kubectl -n kwkd get helmchartproxies
NAME                             READY   REASON
cilium                           True    InfoReported
talos-cloud-controller-manager   True    InfoReported

Il est aussi possible de récupérer le kubeconfig et le talosconfig de kwkd depuis le cluster de Management comme ceci :

export KUBECONFIG=./clusters/kmgt/kubeconfig.yaml

kubectl -n kwkd get secrets kwkd-kubeconfig -o=jsonpath='{.data.value}' | base64 -d > ./clusters/kwkd/kubeconfig.yaml
kubectl -n kwkd get secrets kwkd-talosconfig -o=jsonpath='{.data.talosconfig}' | base64 -d > ./clusters/kwkd/talosconfig.yaml

La boucle est bouclée ! Le cluster de Workload est opérationnel, tout en étant piloté par le cluster de Management !

L’étape de la mise à jour
#

Je vous ai déjà parlé des montées de version dans la partie précédente, il y a effectivement deux cas : mettre à jour la version de Kubernetes et/ou mettre à jour la version de Talos Linux.

Comme vous le savez, Cluster API gère les mises à jour de manière transparente en mode rolling update en créant de nouvelles machines et en drainant les anciennes, assurant ainsi qu’il n’y ait pas de coupure de service.

Utiliser Argo CD et l’approche GitOps rend les choses plus visuelles et je vous propose de voir comment tout cela s’articule.

En soi, rien de compliqué, si l’on prend le cas d’une mise à jour Kubernetes, il y a deux champs à modifier : côté Control Planes et côté Workers.

Dans l’ordre des choses, il est clairement recommandé de mettre à jour les Control Planes avant de lancer les Workers pour assurer a minima la compatibilité des nœuds avec l’API Server.

Voici les deux lignes à modifier dans le fichier clusters/kwkd/config.yaml, on commence côté Control Planes :

apiVersion: controlplane.cluster.x-k8s.io/v1alpha3
kind: TalosControlPlane
metadata:
  name: kwkdcp
[...]
spec:
  version: v1.36.3 # Ancienne valeur : v1.36.2

Sans oublier les Workers :

# Workers
apiVersion: cluster.x-k8s.io/v1beta2
kind: MachineDeployment
metadata:
  name: kwkdwk
[...]
spec:
[...]
  template:
    spec:
      clusterName: kwkd
      version: v1.36.3 # Ancienne valeur : v1.36.2

Et un commit et un push plus tard, il ne reste plus qu’à lancer la synchronisation dans Argo CD et admirer la mise à jour se lancer…

Mise à jour de cluster dans Argo CD

Mise à jour des Control Planes dans Argo CD

Récapitulatif et mot de la fin
#

Cette série dédiée à Cluster API touche à sa fin…

Après une partie plutôt théorique sur les concepts, l’architecture, l’introduction de Talos Linux et le mode opératoire de Cluster API, les parties pratiques sur le déploiement du cluster de Management et du cluster de Workload viennent couronner le tout.

J’espère que cette première série sur ce sujet vous aura plu. Il est toujours important pour moi d’entremêler les concepts avec l’aspect exploratoire en mode lab, notamment pour comprendre plus en profondeur l’ensemble des tenants et des aboutissants.

Vous vous en doutez, mais ne faire qu’un seul article de cette série aurait été trop lourd ou alors, il aurait fallu supprimer des parties que je juge essentielles.

Cluster API est un très beau projet qui permet d’uniformiser la façon de déployer ses clusters Kubernetes en adoptant l’aspect totalement “as code” pour déployer son infrastructure, directement dans Kubernetes sans avoir recours à d’autres langages ou technologies du marché. Comme vous avez pu le voir, associer cet outil avec le monde du GitOps permet d’avoir une réelle tour de contrôle permettant de piloter et mettre à jour un parc entier où les opérations sont réduites à modifier quelques lignes de code dans Git. Un réel bonheur quand on s’occupe du Run de ce type de plateforme.

De plus, la force de Cluster API réside dans son aspect modulaire façon “puzzle” où il est possible de choisir chaque Provider en fonction de ses besoins afin d’augmenter sa flexibilité si l’on souhaite modifier son hyperviseur, changer de Cloud Provider, voire de distribution Kubernetes…

Je le recommande vivement, même si la migration initiale a un coût !

N’hésitez pas à me faire part de vos retours et réalisations sur Cluster API et ses composants, que ce soit sur LinkedIn ou le réseau de votre choix !

À la découverte de Cluster API - Cet article fait partie d'une série.
Partie 3: Cet article

Articles connexes