Étape 9 : Le réseau sous Kubernetes et le CNI Cilium

Introduction

Il est temps de traiter le dernier rôle présent au sein du playbook xkub_30_cluster.yml, soit le rôle xkub_cilium

Précédemment nous avons vu comment traiter l’initialisation du cluster via le rôle xkub_kubeadm_init puis comment ensuite y ajouter l’ensemble des nodes avec le rôle xkub_kubeadm_join. L’ensemble passait la manipulation de kubeadm que Ansible va pouvoir exécuter afin d’enchainer les commandes nécessaires sur chaque serveur.

Si le playbook se finissait ainsi, nous aurions un cluster opérationnel aux sens fondamentaux du terme avec la mise en ligne des control plane et des workers conformément à notre architecture cible.

Les composants de bases, tels que l’API serveur ou la base ETCD seraient en place.

Néanmoins, on ne saurait pas capable d’exécuter un asset sur le cluster ou du moins pas de le rendre accessible.

La raison est que la couche réseau ne serait tout simplement pas présente, et c’est bien l’objectif de ce rôle xkub_cilium que nous allons voir dans cet article.

Le réseau sous K8S

Avant de rentrer dans le détail du rôle, on va en profiter pour évoquer quelques principes autour du réseau au sein de Kubernetes.

Déjà, il est important de signaler que l’architecture réseau de Kubernetes abandonne le modèle traditionnel de ports mappés sur l’hôte, type bridge avec NAT systématiques (du moins par défaut)). Pas de docker bridge ici, et on va plutôt résonné sur le principe d’un réseau à plat où le Pod est l’unité atomique d’adressage.

Kubernetes n’implémente pas le réseau lui-même, il impose une manière de faire strict que toute infrastructure sous-jacente doit respecter.

  • Pod-to-Pod sans NAT : Chaque Pod reçoit sa propre adresse IP unique au sein du cluster (PodCIDR). Tous les Pods peuvent communiquer entre eux directement, qu'ils soient sur le même nœud ou sur des nœuds distincts, sans translation d'adresse (NAT).
  • Node-to-Pod sans NAT : Les démons système d'un nœud (comme le kubelet pour les sondes livenessProbe / readinessProbe) peuvent communiquer avec n'importe quel Pod sans NAT.
  • Cohérence de l'IP perçue : L'adresse IP qu'un Pod voit pour lui-même est exactement la même que celle vue par les autres Pods et les nœuds lorsqu'il leur envoie du trafic.
  • Partage du Network Namespace (NetNS) par Pod : Au sein d'un même Pod, tous les conteneurs partagent la même pile réseau Linux (interfaces, tables de routage, règles iptables) et communiquent entre eux via localhost (127.0.0.1)

En plus de ces règles, on retrouve trois plages d’IP réseau (CIDRs)

  • Node Network : c’est le réseau physique ou virtuel associé au serveur du cluster. C’est l’IP même des nodes, celle qu’on a paramétrée dans le déploiement des VMs avec Terraform. On va donc retrouver le réseau 192.168.10.0 pour les nœuds du lans et 192.168.5.0 pour les nœuds en DMZ.
  • Pod Network (--cluster-cidr) : ce sont les IPs attribuées dynamiquement aux Pods. Dans notre architecture, on a retenu 10.11.0.0/16. Chaque pods qui va être exécuté sur le cluster disposera d’une IP dans cette plage. Il est donc important de retenir une plage large, car le nombre de pod peut très vitre monté, et de retenir également une plage qui n’est pas routée sur son architecture classique.
  • Service Network (--service-cluster-ip-range) : ce sont les adresses IP virtuelles (VIP / ClusterIP) qui n'existent sur aucune interface réseau physique ou virtuelle, mais servent de cibles d'équilibrage de charge vers les Pods. Un pod n’a donc pas vocation à être joint directement par son IP, prise dans la plage précédente, mais à être exposé par un service qui reroutera vers l’un des pods couverts. Dans notre cas, nous avons choisi 10.12.0.0/16 pour les services. Ici aussi, la plage doit être large et non routée.

Il faut bien être conscient qu’en interne, et par défaut, peu importe les namespaces utilisés, tout le monde discute avec tout le monde, mais pas forcément avec l’extérieur.

La résolution DNS interne

D’ailleurs on a également tout un mécanisme de résolution DNS interne avec des serveurs DNS exécutés parmi les briques de bases. Dans une installation Vanilla c’est CoreDNS qui est présent et déployé en même temps qu’on initie le cluster.

On a donc un domaine interne au cluster fixé par défaut à cluster.local, un service en interne du cluster pourra se résoudre toujours sous la forme « whoami.default.svc.cluster.local ». En dehors du cluster les requêtes DNS sont renvoyées aux DNS configurés sur les nodes.

Voici d’ailleurs un schéma qui explique le principe de résolution interne d’un cluster K8S.

Résolution DNS interne d'un cluster Kubernetes : CoreDNS, namespaces et nom complet service.namespace.svc.cluster.local

Cliquez sur l'image pour l'agrandir.

Le CNI

Par contre, toute cette architecture réseau n’est pas fonctionnelle sans l’ajout au cluster d’un plugin CNI (Container Network Interface)

C’est ce plugin qui est en charge de l’interaction avec le container runtime (containerd) pour la gestion du réseau.

C’est lui qui s’occupe de créer des paires d’interfaces virtuelles associées aux pods, d’allouer des IPs parmis les plages configurées et de router le trafic entre les nœuds.

Ce routage est d’ailleurs possible selon deux options:

  • Mode Overlay (Encapsulation) : Le CNI encapsule le paquet Pod-to-Pod dans un paquet UDP sur le réseau des nœuds via VXLAN ou Geneve. Simple à déployer (aucune dépendance sur le réseau physique L2/L3 sous-jacent), mais ajoute un léger overhead CPU et réduit la MTU (typiquement de 1500 à 1450 octets).
  • Mode Routage Natif (Direct Routing / BGP) : Pas d'encapsulation. Les nœuds s'échangent les routes des PodCIDR (souvent via BGP ou des tables de routage cloud) et routent les paquets à vitesse filaire avec la MTU native.

Ce choix et d’autres sont propres au plugin retenu. Les CNI historique comme Flannel ou Calico (en mode standard) s’appuient sur la pile historique du noyau Linux (netfilter/iptables) et kube-proxy, le composant natif de K8S pour l’exposition des services.

Le souci, c’est qu’à grande échelle, iptables peut devenir un goulot d’étranglement, où chaque règle associée doit être évaluée séquentiellement.

Cilium

C’est pourquoi d’autres plugins, comme celui que l’on a retenu, Cilium, préfèrent s’appuyer sur eBPF (Extended Berkeley Packet Filter). Ce protocole permet d’interagir directement dans l’espace du kernel Linux, sans avoir à modifier le noyau ni à charger des modules. Cela permet d’observer, décider ou modifier tout ce qui est lié au réseau.

Dans notre architecture, Cilium va s’appuyer sur eBPF pour :

  • le routage des pods : faire circuler le trafic entre pods de nœuds différents, encapsulé en VXLAN (on est donc en mode overlay)
  • les Services : il remplace kube-proxy et iptables (les ClusterIP en 10.12.0.0/16 sont résolues par eBPF) (c’est pourquoi, dans l’init du cluster on a retiré le déploiement de kube-proxy);
  • les NetworkPolicies : il filtre le trafic par identité de pod plutôt que par IP. Cela nous permettra d’intégrer des équivalents de règles de firewall bien plus évoluées que la simple police de réseau permise par K8S par défaut.
  • l'observabilité : Hubble, le composant de supervision lié à Cilium, lit ce que voit eBPF pour fournir une visibilité sur les flux réseau. Ce point est très intéressant, car, dans des architectures, type microservice, comme on peut en retrouver sur des architectures K8S, l’observabilité des flux devient nécessaire pour identifier tout le goulot d’étranglement et apporter une bonne sécurité à l’ensemble.

eBPF rend le noyau Linux programmable de façon sûre et rapide. Cilium utilise une logique de réseau plus efficace et plus visible pour remplacer iptables et kube-proxy.

Le projet Cilium a démarré en 2015, sous l’impulsion de Thomas Graf, un développeur historique du noyau Linux chez RedHat.

Progressivement, il a gagné en popularité pour devenir en 2020 le moteur par défaut des solutions Kubernetes opérées par les grands noms du cloud (Google, AWS, Azure) et pour intégrer la CNCF (Cloud Native Computing Foundation) en 2021.

En décembre 2023, Cisco fait l’acquisition d’Isovalent, l’entreprise qui avait été créée suite au projet, afin de faire de Cilium le socle de sa stratégie sécurité et cloud-native, tout en maintenant la gouvernance ouverte du projet sous l'égide de la CNCF. (Il existe une version payante de Cilium qui permet notamment de souscrire à un support et d’obtenir des fonctionnalités supplémentaires, mais le cœur du projet et des composants reste opensource)

On peut dire aujourd’hui que Cilium est devenu le plugin CNI le plus déployé, ce qui ne veut pas dire pour autant qu’il est forcément nécessaire de le choisir. Calico par exemple, reste largement utilisé et réputé pour être plus performant.

Tout va dépendre de vos besoins et des spécificités réseau recherchés au sein de vos architectures.

Pour ce cookbook j’ai retenu Cilium, car c’est celui qui me paraissait le plus approprié, car le plus représentatif de ce qu’on pourrait trouver aujourd’hui sur une nouvelle architecture K8S.

Principe de Cilium : programmes eBPF dans le noyau Linux pour le routage des pods, les services, les NetworkPolicies et l'observabilité Hubble

Cliquez sur l'image pour l'agrandir.

Le rôle xkub_cilium

Maintenant, passons à l’exploration du rôle en charge du déploiement de cilium sur notre Cluster.

Celui-ci, intégré dans le playbook xkub_30_cluster.yml, ne sera activé que sur le premier nœud du cluster. C’est inutile de se connecter aux autres, puisque toute la configuration va passer par l’API K8S.

- name: Cilium — CNI avec kubeProxyReplacement (chart Helm depuis le control plane primaire)
  hosts: "{{ groups['k8s_controlplane_lan'] | sort | first }}"
  become: true
  roles:
    - xkub_cilium

playbooks/xkub_30_cluster.yml (extrait)

Comme d’habitude on va explorer l’arborescence du rôle pour traiter chaque fichier

Arborescence du rôle Ansible xkub_cilium : dossiers defaults, tasks et templates

Cliquez sur l'image pour l'agrandir.

Les variables du rôle

Dans le dossier Defaults et le fichier main.yml, on retrouve les variables propres aux rôles.

---
xkub_cilium_kube_proxy_replacement: true
xkub_cilium_hubble_enabled: true

xkub_cilium_helm_repo_url: https://helm.cilium.io/
xkub_cilium_release_name: cilium
xkub_cilium_release_namespace: kube-system
xkub_cilium_values_path: /etc/kubernetes/cilium-values.yaml
xkub_cilium_helm_wait_timeout: 10m

roles/xkub_cilium/defaults/main.yml

Ces variables serviront surtout à spécifier ou récupérer Cilium et à comment l’installer.

Helm

Pour ça on va passer par Helm, qui n’est autre que le gestionnaire de package disponible pour Kubernetes. Si classiquement les objets K8S se déploient sous forme de fichier yamls propres à chaque objet, Helm permet de masquer la complexité de ces derniers en donnant accès à des repos dans lesquelles on va retrouver ce qu’on appelle des Chart. Il s’agit d’archives ou de dossiers structurés qui contiennent tous les modèles de manifestes Kubernetes nécessaires pour faire tourner une application.

Si une configuration par défaut est proposée, il est possible de la surcharger afin de personnaliser l’installation, et ça va être le rôle du fichier /etc/kubernetes/cilium-values.yaml défini par la variable xkub_cilium_values_path

À noter qu’on va déployer Cilium dans le namespace par défaut kube-system, soit le namespace regroupant les composants de bases du cluster et théoriquement accessible uniquement qu’aux administrateurs du cluster.

Il est possible de dédier un namespace à Cilium, c’est une question de préférence et de logique personnelle.

Les tasks

On peut s’attaquer au dossier tasks.

main.yml

Le fichier main.yml ne fait que référencer l’ordre d’exécution des tâches.

---
- name: Installer Helm (binaire officiel, version épinglée)
  ansible.builtin.import_tasks: 01_helm.yml
  tags:
    - xkub
    - xkub.cilium
    - xkub.cilium.helm

- name: Installer cilium-cli (vérification post-déploiement uniquement)
  ansible.builtin.import_tasks: 02_cilium_cli.yml
  tags:
    - xkub
    - xkub.cilium
    - xkub.cilium.cli

- name: Déployer le chart Helm Cilium
  ansible.builtin.import_tasks: 03_deploy.yml
  tags:
    - xkub
    - xkub.cilium
    - xkub.cilium.deploy

roles/xkub_cilium/tasks/main.yml

01_helm.yml

Le déploiement de Cilium par Ansible démarre par les actions décrites dans 01_helm.yml

---
# Helm est installé depuis le binaire officiel (version épinglée dans
# versions.yml). Comme containerd/crictl, il échappe à dnf : la garde doit
# porter sur la VERSION et non sur la présence du fichier, sinon une montée de
# version (ou un correctif de CVE) ne s'applique jamais
- name: Relever la version de Helm installée
  ansible.builtin.command:
    cmd: "{{ k8s_helm_binary_path }} version --short"
  register: xkub_cilium_helm_installed
  changed_when: false
  failed_when: false

# `helm version --short` renvoie « v3.21.3+g<sha> ».
# Absent ou illisible => chaîne vide => la version cible est (ré)installée.
- name: Extraire le numéro de version de Helm
  ansible.builtin.set_fact:
    xkub_cilium_helm_current: >-
      {{ (xkub_cilium_helm_installed.stdout
          | regex_search('v(\d+\.\d+\.\d+)', '\1')
          | default([''], true) | first) | default('', true) }}

- name: Télécharger et extraire Helm {{ helm_version }} dans /tmp
  ansible.builtin.unarchive:
    src: "{{ helm_download_url }}"
    dest: /tmp
    remote_src: true
  when: xkub_cilium_helm_current != helm_version

- name: Installer le binaire Helm dans {{ k8s_helm_binary_path }}
  ansible.builtin.copy:
    src: /tmp/linux-amd64/helm
    dest: "{{ k8s_helm_binary_path }}"
    owner: root
    group: root
    mode: "0755"
    remote_src: true
  when: xkub_cilium_helm_current != helm_version

- name: Nettoyer l'archive Helm extraite
  ansible.builtin.file:
    path: /tmp/linux-amd64
    state: absent
  when: xkub_cilium_helm_current != helm_version

# Sans ce plugin, kubernetes.core.helm avertit « The default idempotency check
# can fail to report changes in certain cases » et rapporte volontiers
# `changed` à chaque exécution, même quand la release est identique 
- name: Installer le plugin helm-diff ({{ helm_diff_version }})
  kubernetes.core.helm_plugin:
    binary_path: "{{ k8s_helm_binary_path }}"
    plugin_path: https://github.com/databus23/helm-diff
    plugin_version: "{{ helm_diff_version }}"
    state: present

roles/xkub_cilium/tasks/01_helm.yml

Comme expliquer plus haut, c’est helm qui a été retenu pour installer Cilium. Il est possible d’utiliser d’autres méthodes, mais helm est la plus répandue.

Pour cela, on vérifie déjà si le binaire helm est présent. Si ce n’est pas le cas, on va le récupérer directement sur le site officiel via la variable helm_download_url. Celle-ci n’est pas définie au niveau du rôle, mais dans le fichier de variable versions.yml présent dans .\inventory\group_vars\clu_k8s_xkub, comme d’autres variables utilisées ici (n’hésitez pas à revoir le principe des variables Ansible)

# Helm ( binaire officiel).
helm_version: "3.21.3"
helm_download_url: "https://get.helm.sh/helm-v{{ helm_version }}-linux-amd64.tar.gz"

# Plugin helm-diff — requis par kubernetes.core.helm pour une détection de
# changement fiable. Sans lui, le module avertit « The default idempotency
# check can fail to report changes in certain cases » et rapporte volontiers
# `changed` à chaque exécution 
helm_diff_version: "3.15.11"


cilium_version: "1.20.0"


cilium_cli_version: "0.19.7"


kube_vip_version: "1.2.1"

# cilium-cli — binaire officiel GitHub, sert UNIQUEMENT à la vérification
# post-déploiement (cilium status, cilium connectivity test) : Cilium
cilium_cli_download_url: "https://github.com/cilium/cilium-cli/releases/download/v{{ cilium_cli_version }}/cilium-linux-amd64.tar.gz"

inventory/group_vars/clu_k8s_xkub/versions.yml (extrait)

Helm est ensuite placé dans le dossier correspondant à la variable k8s_helm_binary_path

# --- Outillage installé hors gestionnaire de paquets -------------------------
k8s_helm_binary_path: /usr/local/bin/helm

inventory/group_vars/clu_k8s_xkub/main.yml (extrait)

En plus de Helm, on déploie également helm-diff. Celui-ci, un peu à l’image d’un terraform plan, permet de montrer ce qui changerait dans le cluster avant d’appliquer une mise à jour via helm.

Cela permet à Ansible d’identifier les besoins de changement ou non, et garantit l’idempotence de notre playbook, sans quoi il redéploierait Cilium à chaque exécution.

02_cilium_cli.yml

On peut passer au fichier 02_cilium_cli.yml

---
# cilium-cli sert EXCLUSIVEMENT à la vérification (cilium status, cilium
- name: Relever la version de cilium-cli installée
  ansible.builtin.command:
    cmd: /usr/local/bin/cilium version --client
  register: xkub_cilium_cli_installed
  changed_when: false
  failed_when: false

- name: Extraire le numéro de version de cilium-cli
  ansible.builtin.set_fact:
    xkub_cilium_cli_current: >-
      {{ (xkub_cilium_cli_installed.stdout
          | regex_search('v(\d+\.\d+\.\d+)', '\1')
          | default([''], true) | first) | default('', true) }}

- name: Télécharger et installer cilium-cli {{ cilium_cli_version }} dans /usr/local/bin
  ansible.builtin.unarchive:
    src: "{{ cilium_cli_download_url }}"
    dest: /usr/local/bin
    remote_src: true
  when: xkub_cilium_cli_current != cilium_cli_version

roles/xkub_cilium/tasks/02_cilium_cli.yml

Comme j’ai pu le présenter plus haut, Cilium est un plugin CNI très avancé. Il permet beaucoup de choses, et, pour simplifier sa gestion et son administration, il est possible de télécharger un binaire qui va fournir une CLI pour interagir avec lui.

C’est le but de cette section du rôle, où l’on va tout simplement récupérer la CLI et l’installer dans /usr/local/bin, en prenant soin de prendre la CLI qui correspond à notre version cible de Cilium, dont on parlera juste après.

03_deploy.yml

Le dernier fichier de taches est 03_deploy.yml

---
- name: Déployer les values Helm Cilium
  ansible.builtin.template:
    src: cilium-values.yaml.j2
    dest: "{{ xkub_cilium_values_path }}"
    owner: root
    group: root
    mode: "0644"

- name: "Installer/mettre à jour le chart Helm Cilium ({{ cilium_version }})"
  kubernetes.core.helm:
    binary_path: "{{ k8s_helm_binary_path }}"
    name: "{{ xkub_cilium_release_name }}"
    chart_ref: cilium
    chart_repo_url: "{{ xkub_cilium_helm_repo_url }}"
    chart_version: "{{ cilium_version }}"
    release_namespace: "{{ xkub_cilium_release_namespace }}"
    kubeconfig: /etc/kubernetes/admin.conf
    values_files:
      - "{{ xkub_cilium_values_path }}"
    wait: true
    wait_timeout: "{{ xkub_cilium_helm_wait_timeout }}"

roles/xkub_cilium/tasks/03_deploy.yml

Il va concerner le déploiement à proprement parler.

Pour cela on commence déjà par copier le template de fichier de configuration qui va nous permettre de personnaliser l’installation de helm sur le cluster. On va le voir un peu plus tard.

Ensuite, Ansible avec lancer la commande helm qui reviendrait à celle-ci si nous devions la passer à la main

helm upgrade --install cilium cilium \
  --repo https://helm.cilium.io/ \
  --version 1.20.0 \
  --namespace kube-system \
  --kubeconfig /etc/kubernetes/admin.conf \
  -f /etc/kubernetes/cilium-values.yaml \
  --wait --timeout 10m

Cette action, va intégrer le repo cilium à la configuration helm, récupéré le Chart associé à la version qu’on souhaite, puis utiliser notre fichier de configuration, plus le fichier de configuration de l’admin de notre cluster pour mettre en place Cilium conformément à notre souhait.

Les templates

cilium-values.yaml.j2

Cela nous permet d’enchainer avec le répertoire templates et de s’attarder sur le fichier cilium-values.yaml.j2 qui est présent.

# {{ ansible_managed }}
# Values Helm Cilium — version épinglée dans group_vars/clu_k8s_xkub/versions.yml
kubeProxyReplacement: {{ xkub_cilium_kube_proxy_replacement | bool | lower }}
k8sServiceHost: {{ k8s_api_vip }}
k8sServicePort: {{ k8s_api_port }}
ipam:
  mode: cluster-pool
  operator:
    clusterPoolIPv4PodCIDRList:
      - "{{ k8s_pod_cidr }}"
hubble:
  relay:
    enabled: {{ xkub_cilium_hubble_enabled | bool | lower }}
  ui:
    enabled: {{ xkub_cilium_hubble_enabled | bool | lower }}
    frontend:
      server:
        ipv6:
          enabled: false
  tls:
    auto:
      enabled: true
      method: helm
      certValidityDuration: 1095

roles/xkub_cilium/templates/cilium-values.yaml.j2

Une fois copié sur le premier node du cluster, voici ce à quoi il va ressembler

# Ansible managed
kubeProxyReplacement: true
k8sServiceHost: 192.168.10.121
k8sServicePort: 6443
ipam:
  mode: cluster-pool
  operator:
    clusterPoolIPv4PodCIDRList:
      - "10.11.0.0/16"
hubble:
  relay:
    enabled: true
  ui:
    enabled: true
    frontend:
      server:
        ipv6:
          enabled: false
  tls:
    auto:
      enabled: true
      method: helm
      certValidityDuration: 1095

/etc/kubernetes/cilium-values.yaml

Il permet de préciser l’IP de la VIP rattachée à l’API de K8S pour que Cilium puisse discuter avec le cluster. (on n’utilise pas le nom DNS pour ne pas avoir de dépendance à la résolution de nom à ce niveau). On précise que Cilium doit remplacer kube-proxy, puisqu’on ne l’aura pas déployé (et on utilisera ainsi toutes les capacités de Cilium)

Dans la section IPAM, on indique être en cluster-pool, c’est donc Cilium qui se chargera de découper la plage 10.11.0.0/16 (notre plage de pod) en sous-plage propre à chaque node.

La section hubble nous permet d’activer l’observabilité des flux réseau, comme dit plus haut, c’est une capacité importante à mettre en œuvre. À noter qu’un certificat interne va être utilisé pour les composants liés à cette fonctionnalité, c’est Helm qui va le générer avec une validité de 3 ans. Il sera mis à jour à chaque update de cilium.

Conclusion

On arrive enfin à la fin du playbook xkub_30_cluster.yml avec la présentation de tous les rôles associés en terminant par le rôle xkub_cilium en charge du déploiement du CNI Cilium.

Cela nous aura permis de voir les grands principes réseau dans K8S qu’il est important de connaitre. C’est un paradigme complet dont il faut avoir conscience. On commence déjà ici à toucher l’une des particularités de K8S, à savoir d’embarquer toute la logique propre à une application et pas seulement l’application elle-même. Tout ce qui touche à l’accès réseau de cette dernière peut être intégré à son déploiement, et le choix d’un CNI comme Cilium est un élément clef dans une architecture Kubernetes.

Le prochain article va nous permettre enfin de lancer notre playbook et de vérifier si tout ce qui a été dit jusque-là est fonctionnel. Ça sera l’occasion de passer en revue la configuration du cluster avant d’aller plus loin dans son exploitation.

Annexe

Résumé des variables et commandes équivalentes hors Ansible

Cette annexe résume l’ensemble des variables utilisées par Ansible pour cet article et donne un équivalent des commandes et configurations mises en œuvre par Ansible pour cette partie.

Variables utilisées

Variable Valeur Déclarée dans
helm_version 3.21.3 inventory/group_vars/clu_k8s_xkub/versions.yml
helm_download_url https://get.helm.sh/helm-v3.21.3-linux-amd64.tar.gz inventory/group_vars/clu_k8s_xkub/versions.yml
helm_diff_version 3.15.11 inventory/group_vars/clu_k8s_xkub/versions.yml
cilium_version 1.20.0 (version du chart) inventory/group_vars/clu_k8s_xkub/versions.yml
cilium_cli_version 0.19.7 inventory/group_vars/clu_k8s_xkub/versions.yml
cilium_cli_download_url https://github.com/cilium/cilium-cli/releases/download/v0.19.7/cilium-linux-amd64.tar.gz inventory/group_vars/clu_k8s_xkub/versions.yml
k8s_helm_binary_path /usr/local/bin/helm inventory/group_vars/clu_k8s_xkub/main.yml
k8s_api_vip 192.168.10.121 (→ k8sServiceHost) inventory/group_vars/clu_k8s_xkub/main.yml
k8s_api_port 6443 (→ k8sServicePort) inventory/group_vars/clu_k8s_xkub/main.yml
k8s_pod_cidr 10.11.0.0/16 (→ clusterPoolIPv4PodCIDRList) inventory/group_vars/clu_k8s_xkub/main.yml
xkub_cilium_kube_proxy_replacement true roles/xkub_cilium/defaults/main.yml
xkub_cilium_hubble_enabled true roles/xkub_cilium/defaults/main.yml
xkub_cilium_helm_repo_url https://helm.cilium.io/ roles/xkub_cilium/defaults/main.yml
xkub_cilium_release_name cilium roles/xkub_cilium/defaults/main.yml
xkub_cilium_release_namespace kube-system roles/xkub_cilium/defaults/main.yml
xkub_cilium_values_path /etc/kubernetes/cilium-values.yaml roles/xkub_cilium/defaults/main.yml
xkub_cilium_helm_wait_timeout 10m roles/xkub_cilium/defaults/main.yml
xkub_cilium_helm_installed / xkub_cilium_helm_current sortie de helm version --short / numéro extrait register et set_fact dans roles/xkub_cilium/tasks/01_helm.yml
xkub_cilium_cli_installed / xkub_cilium_cli_current sortie de cilium version --client / numéro extrait register et set_fact dans roles/xkub_cilium/tasks/02_cilium_cli.yml
ansible_user ansible-windows inventory/hosts.yml (all.vars)

Équivalent sans Ansible

Connexion : ssh [email protected], puis sudo -i. Toutes les commandes tournent en root, sur prdk8sgru501.

# Action Serveur Compte Commande(s)
1 Relever la version de Helm installée (étapes 2 à 4 seulement si elle diffère de v3.21.3) prdk8sgru501 root /usr/local/bin/helm version --short
2 Télécharger et extraire Helm 3.21.3 prdk8sgru501 root curl -fsSL -o /tmp/helm-v3.21.3-linux-amd64.tar.gz https://get.helm.sh/helm-v3.21.3-linux-amd64.tar.gz
tar -C /tmp -xzf /tmp/helm-v3.21.3-linux-amd64.tar.gz
3 Installer le binaire prdk8sgru501 root install -m 755 -o root -g root /tmp/linux-amd64/helm /usr/local/bin/helm
4 Nettoyer prdk8sgru501 root rm -rf /tmp/linux-amd64 /tmp/helm-v3.21.3-linux-amd64.tar.gz
5 Plugin helm-diff 3.15.11 (s'il n'apparaît pas dans helm plugin list) prdk8sgru501 root helm plugin install https://github.com/databus23/helm-diff --version 3.15.11
6 Relever la version de cilium-cli (étape 7 seulement si elle diffère de v0.19.7) prdk8sgru501 root /usr/local/bin/cilium version --client
7 Installer cilium-cli 0.19.7 prdk8sgru501 root curl -fsSL -o /tmp/cilium-linux-amd64.tar.gz https://github.com/cilium/cilium-cli/releases/download/v0.19.7/cilium-linux-amd64.tar.gz
tar -C /usr/local/bin -xzf /tmp/cilium-linux-amd64.tar.gz
8 Écrire les values Helm prdk8sgru501 root Créer /etc/kubernetes/cilium-values.yaml (bloc A), chmod 644
9 (facultatif) Voir ce qu'un upgrade changerait prdk8sgru501 root helm diff upgrade cilium cilium --repo https://helm.cilium.io/ --version 1.20.0 -n kube-system --kubeconfig /etc/kubernetes/admin.conf -f /etc/kubernetes/cilium-values.yaml
10 Installer ou mettre à jour Cilium prdk8sgru501 root Bloc B
11 Vérifier prdk8sgru501 root export KUBECONFIG=/etc/kubernetes/admin.conf
cilium status --wait
kubectl get nodes (les nœuds passent Ready)

L'étape 9 correspond à ce que fait Ansible en interne. Avec helm-diff installé, le module kubernetes.core.helm compare la release au chart et ne lance l'upgrade que s'il trouve une différence. C'est ce qui rend le rôle idempotent.

Bloc A /etc/kubernetes/cilium-values.yaml

kubeProxyReplacement: true
k8sServiceHost: 192.168.10.121
k8sServicePort: 6443
ipam:
  mode: cluster-pool
  operator:
    clusterPoolIPv4PodCIDRList:
      - "10.11.0.0/16"
hubble:
  relay:
    enabled: true
  ui:
    enabled: true
    frontend:
      server:
        ipv6:
          enabled: false
  tls:
    auto:
      enabled: true
      method: helm
      certValidityDuration: 1095

Bloc B déploiement du chart

helm upgrade --install cilium cilium \
  --repo https://helm.cilium.io/ \
  --version 1.20.0 \
  --namespace kube-system \
  --kubeconfig /etc/kubernetes/admin.conf \
  -f /etc/kubernetes/cilium-values.yaml \
  --wait --timeout 10m