Skip to content

Installation

Dans cette documentation, nous allons détailler l’installation de Talos Linux et la création d’un cluster Kubernetes en mode « bare-metal » ou « vm ».

Autre point important, cette documentation traite de l’installation et de la création d’un cluster utilisant la CNI Cilium.
Talos Linux est déployé nativement avec la CNI Flannel, personnellement, je la trouve un peu limitée dans ses capacités, c’est pour celà que j’opte pour le choix de Cilium. Cilium sera déployé avec les features suivantes :

  • Remplacement de kube-proxy
  • Gestion des Gateway API Kubernetes
  • Déploiement de l’Ingress Controller embarqué (Envoy)

L’installation sur un Cloud Provider doit être faite d’une façon légèrement différente pour démarrer les machines.
Pour ce cas d’usage, je vous invite à vous rapprocher de la documentation de Talos.

  • Disposer sur votre machine ou sur une machine dédiée le binaire talosctl dans la dernière version stable disponible en téléchargement sur le dépot GitHub.
  • Déterminer la version du Kubernetes à installer à l’aide de la matrice de compatibilité si vous souhaitez déployer une version particulière de Kubernetes.
  • Disposer de l’iso de Talos Linux disponible également sur le dépot GitHub.
  • Disposer d’une adresse IP pour chacun des nœuds du cluster Talos qui va être constitué.
  • Disposer d’une adresse IP virtuelle (VIP) pour les Control Planes.
  • Disposer sur votre machine ou sur une machine dédiée de Helm

En tout premier lieu, préparez les machines qui vont être les nœuds de votre cluster.
Il suffit de démarrer les machines sur l’iso de Talos que vous avez récupéré en pré-requis. Si vous avez du DHCP sur votre réseau, les machines vont automatiquement prendre une adresse dans celui-ci, sinon, il faudra configurer manuellement les adresse IP depuis la console.

Dans le cadre de cette documentation, nous considèrerons que les adresse IP seront les suivantes :

hostname IP
talos-cp1 192.168.0.101
talos-cp2 192.168.0.102
talos-cp3 192.168.0.103
talos-worker1 192.168.0.201
talos-worker2 192.168.0.202
talos-worker3 192.168.0.203

Autre information réseau :

role IP
NTP 192.168.0.8
NTP 192.168.0.9
DNS 192.168.0.10
DNS 192.168.0.11

La toute première étape à effectuer est de générer et préparer les manifestes de configuration de Talos que vous allez injecter à vos machines.

Talos utilise pour sécuriser l’ensemble des communications de ses composants des jeux de certificats (serveurs et client).
Afin de s’assurer que ces certificats sont uniques, il est préférable de générer un fichier contenant ces secrets.

Le binaire talosctl permet de générer un fichier contenant l’ensemble des secrets :

Terminal window
talosctl gen secrets -o secrets.yaml

Vous obtiendrez donc le fichier suivant :

secrets.yaml
cluster:
id: <id du cluster>
secret: <secret interne du cluster>
secrets:
bootstraptoken: <token de jonction au cluster Kubernetes>
secretboxencryptionsecret: <clef de chiffrement des secrets Kubernetes>
trustdinfo:
token: <token de jonction au cluster Talos>
certs:
etcd:
crt: <certificat pour les communications ETCD>
key: <clef privée pour les communications ETCD>
k8s:
crt: <certificat pour les communications Kubernetes>
key: <clef privée pour les communications Kubernetes>
k8saggregator:
crt: <certificat pour les communications de Kubernetes aggregator>
key: <clef privée pour les communications de Kubernetes aggregator>
k8sserviceaccount:
key: <clef privée pour le compte de service Kubernetes administrateur>
os:
crt: <certificat pour la communication avec les API Talos>
key: <clef pivée pour la communication avec les API Talos>

Maintenant que vous avez le fichier contenant vos secrets, vous pouvez générer les fichiers de configuration de référence.
Ces fichiers serviront de socle général pour la configuration de vos nœuds :

  • controlplane.yaml : Le fichier de configuration de référence pour les Control Plane
  • worker.yaml : Le fichier de configuration de référence pour les workers.

Pour générer les fichiers :

Terminal window
talosctl gen config \
--with-secrets secrets.yaml \
<cluster_name> \
<cluster_endpoint>

Dans le cas de la commande ci-dessus, vous générez les configurations « standard » de Talos sans spécificitées.
Vous devrez spécifier deux paramètres :

  • <cluster_name> : Le nom de votre cluster Kubernetes
  • <cluster_endpoint> : L’URL d’accès aux API Kubernetes de votre cluster en utilisant la VIP. (Le format complet étant : https://<VIP>:6443)

Spécification de la version de Kubernetes

Section titled “Spécification de la version de Kubernetes”

Pour spécifier la version de Kubernetes à déployer, ajouter une option à la commande ci-dessus :

Terminal window
talosctl gen config \
--with-secrets secrets.yaml \
--kubernetes-version <kube_version> \
<cluster_name> \
<cluster_endpoint>

La version de Kubernetes doit être spécifié en intégralité. Par example : 1.29.3.

De mon côté, j’apprécie la feature Kubespan présente dans Talos.

Celà permet facilement d’hybrider un cluster Talos entre des nœuds sur site, et chez un cloud provider par exemple.
L’idée derrière cette feature est d’instancier un réseau Mesh Wireguard entre tous les nœuds du cluster pour permettre de chiffrer les communications entre les nœuds et de ne pas avoir à se soucier particulièrement de la sécurité réseau des communications vu que ces dernières sont encapsulée dans une solution de « VPN ».

Dans un réseau local dans l’absolu, elle n’est pas nécessaire, mais j’ai une préférence pour l’activer « by design ».

Pour ce faire, il faut ajouter une option à la commande permettant de générer les configurations :

Terminal window
talosctl gen config \
--with-secrets secrets.yaml \
--kubernetes-version <kube_version> \
--with-kubespan \
<cluster_name> \
<cluster_endpoint>

Lors de la génération des configurations, il est possible de passer d’autres options intéressantes :

  • --dns-domain : Domaine DNS utilisé au sein du cluster (par défaut cluster.local)
  • --install-disk : Le chemin absolu du disque sur lequel installer Talos (par défault /dev/sda)
  • --install-image : Le nom complet de l’image de Talos à installer. Si vous utilisez un registry local (cache ou avec des images en propre) par exemple plutôt que de tirer les images depuis le registry GitHub. (par défault : ghcr.io/siderolabs/installer:<talos_version>)
  • --talos-version : La version spécifique de Talos à installer, par exemple v1.6.8. Par défaut cette valeur correspond à la version du binaire talosctl que vous avez installé.

Afin de générer la bonne configuration à appliquer à vos machines, vous pouvez modifier les configurations initiales que vous venez de générer.

Par défaut, je vous invite à le faire pour tout ce qui sera commun entre vos Control Plane et vos Workers. Par exemple :

  • La configuration des serveurs DNS.
  • La configuration des CNI.
  • L’injection de fichiers de CA si vous disposez d’une PKI propre.
  • …

Dans notre cas, nous allons configurer dans les fichiers controlplane.yaml et worker.yaml les paramètres suivants :

  • Serveurs DNS
  • Serveurs NTP
  • Activation de la rotation automatique des certificats (rotate-server-certificates)
  • Désactivation de la CNI
  • Exposition des métriques
    • Proxy
    • ETCD
  • Déploiement de kubelet-serving-cert-approver pour la rotation automatique des certificats.
  • Déploiement de metric-server pour activer les capacités de HPA et de VPA de Kubernetes.
controlplane.yaml and worker.yaml
---
...
machine:
...
kubelet:
...
network:
...
nameservers:
- 192.168.0.10
- 192.168.0.11
...
rotate-server-certificates: true
...
...
time:
disabled: false
servers:
- 192.168.0.8
- 192.168.0.9
...
cluster:
...
network:
...
cni:
...
name: none
...

Dans le fichier controlplane.yaml uniquement, il faudra également désactiver la partie kube-proxy :

controlplane.yaml
---
...
cluster:
...
proxy:
...
disabled: true
etcd:
...
extraArgs:
listen-metrics-urls: http://0.0.0.0:2381
...
extraManifests:
...
- https://raw.githubusercontent.com/alex1989hu/kubelet-serving-cert-approver/main/deploy/standalone-install.yaml
- https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
...

Une fois vos configurations de références mise en place, vous pouvez créer vos fichiers de « patch » qui seront les configurations propres à chacun des nœuds de votre cluster Talos.

Il est donc nécessaire de disposer d’un fichier de patch par machine du cluster.

Pour la partie Control Plane, le fichier de patch « classique » sera le suivant :

patch-cpX.yaml
machine:
certSANs:
- <adresse_VIP>
- <adresse_node>
- <fqdn_VIP>
- <fqdn_node>
network:
hostname: <hostname>
interfaces:
- interface:
deviceSelector:
hardwareAddr : '<node_mac_address(xx:xx:xx:xx:xx:xx)>'
addresses:
- <adresse_node>
routes:
- network: 0.0.0.0/0
gateway: <adresse_de_gateway_du_réseau>
metric: 1024
mtu: 1500
vip:
ip: <adresse_VIP>

Dans la partie certSANs, il est recommandé d’expliciter l’ensemble des adresses ainsi que les noms du nœud.
Vous noterez dans ce cas la présence de l’adresse de VIP vu qu’elle peut être déclaré sur chaque Control-Plane.

Dans la partie réseau, on retrouve les champs à modifier :

  • <hostname> : Le nom d’hôte du nœud.
  • <node_mac_address> : L’adresse MAC du nœud. Cette configuration permet de définir sur quelle interface du nœud l’adresse IP que l’on est en train de configurer doit être appliquée. Il y a plusieurs façons de faire, celle-ci étant ma préférée.
  • <adresse_node> : L’adresse IP à attribuer au nœud.
  • <adresse_de_gateway_du_réseau> : L’adresse da la passerelle réseau pour ce nœud.
  • <adresse_VIP> : L’adresse VIP que vous avez définie en prérequis (dans notre cas 192.168.0.100).

Pour la partie Worker, c’est sensiblement similaire.
Au détail près qu’il ne faut pas intégrer les données propres à la VIP.

patch-workerX.yaml
machine:
certSANs:
- <adresse_node>
- <fqdn_node>
network:
hostname: <hostname>
interfaces:
- interface:
deviceSelector:
hardwareAddr : '<node_mac_address(xx:xx:xx:xx:xx:xx)>'
addresses:
- <adresse_node>
routes:
- network: 0.0.0.0/0
gateway: <adresse_de_gateway_du_réseau>
metric: 1024
mtu: 1500

Une fois vos configurations génériques et vos patchs finalisés, vous pouvez générer vos configurations finales qui seront appliqués à chacun de vos nœuds.

Pour ce faire, il faut exécuter la commande suivante (pour chacun des nœuds) :

Pour les Control Plane :

Terminal window
talosctl machineconfig patch controlplane.yaml --patch @<node_patch_file>.yaml --output <node>.yaml

Pour les Worker :

Terminal window
talosctl machineconfig patch worker.yaml --patch @<node_patch_file>.yaml --output <node>.yaml

Exemples :

Terminal window
talosctl machineconfig patch controlplane.yaml --patch @patch-talos-cp1.yaml --output talos-cp1.yaml # Configuration pour le nœud talos-cp1
talosctl machineconfig patch controlplane.yaml --patch @patch-talos-worker1.yaml --output talos-worker1.yaml # Configuration pour le nœud talos-worker1

Le déploiement d’un cluster Talos se déroule en plusieurs étapes :

  1. Configuration du premier Control Plane
  2. Bootstrap du cluster Kubernetes
  3. Récupération de la configuration du cluster Kubernetes (kubeconfig)
  4. Déploiement du CNI
  5. Déploiement des autres Control Planes
  6. Déploiement des workers

Avant toute action, définissez la variable d’environnement TALOSCONFIG comme suivant :

Terminal window
export TALOSCONFIG=talosconfig

Maintenant que vous avez préparé vos configurations, il faut déployer le premier Control Plane qui sera membre de votre cluster Talos.

Ce déploiement va avoir pour effet :

  • D’installer Tals sur le disque de la machine
  • De configurer le réseau
  • De configurér le nécessaire présent dans les configurations (DNS, NTP, certificats, secrets, …)

Pour déployer votre premier Control Plane, exécutez simplement la commande suivante :

Terminal window
talosctl apply-config --insecure -n <adresse_IP_du_CP> -f <configuration_cp>.yaml

Si on reprends la commande avec les informations données dans Préparation des hôtes ça donne ça :

Terminal window
talosctl apply-config --insecure -n 192.168.0.101 -f talos-cp1.yaml

Vous devrez patienter quelques minutes le temps que le nœud télécharge les images nécessaires.
Vous pouvez consulter la console du nœuds, vous devriez voir apparaitre le message suivant :

Control Plane logs
[talos] task startAllServices (1/1): service "etcd" to be "up"
[talos] controller failed {"component": "controller-runtime", "controller": "k8s.NodeApplyController", "error": "1 error(s) occurred:\n\ttimeout"}

Lorsque vous avez ce message, vous pouvez modifier la configuration talosconfig comme suivant et passer à l’étape suivante :

Terminal window
talosctl config endpoint <adresse_IP_du_premier_CP>

Dans notre cas :

Terminal window
talosctl config endpoint 192.168.0.100

Votre premier CP est actuellement prêt à accueillir le déploiement de Kubernetes.
Il est en attente de l’instruction qui va permettre de :

  • Déployer ETCD
  • Déployer les composants Kubernetes initiaux (kube-scheduler, kube-controller-manager, kube-apiserver )

Pour ce faire, exécutez la commande suivante :

Terminal window
talosctl bootstrap -n <adresse_IP_du_premier_CP>

Dans notre cas :

Terminal window
talosctl bootstrap -n 192.168.0.100

Vous devrez attendre d’avoir sur le dashboard plusieurs informations :

  • STAGE Running
  • READY False
  • KUBELET Healthy
  • APISERVER Healthy
  • CONTROLLER-MANAGER Healthy
  • SCHEDULER Healthy

Une fois que toutes ces informations sont validées, vous pouvez passer à la suite.

Vous pouvez maintenant récupérer la configuration Kubernetes vous permettant de dialoguer avec les API Kubernetes.

Pour ce faire utilisez la commande suivante :

Terminal window
talosctl kubeconfig -n <adresse_IP_du_premier_CP> kubeconfig

Cette commande va vous permettre d’extraire la configuration kubeconfig dans un fichier du même nom là où vous êtes dans le système.

Dans notre cas :

Terminal window
talosctl kubeconfig -n 192.168.0.100 kubeconfig

Une fois fait, vous pouvez exporter la variable d’environnement KUBECONFIG pour pointer votre fichier :

Terminal window
export KUBECONFIG=kubeconfig

Si tout va bien, vous pouvez maintenant afficher le status de votre nœud Kubernetes et dialoguer avec lui :

Terminal window
kubectl get nodes
NAME STATUS ROLES AGE VERSION
talos-cp1 NotReady control-plane 2m v1.28.6

Si vous afficher les pods, vous verrez que tous les pods Kubernetes sont en status Ready sauf ceux de coredns :

Terminal window
kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system coredns-c78fdf99-4kkwp 0/1 Pending 0 6m5s
kube-system coredns-c78fdf99-x5mcj 0/1 Pending 0 6m5s
kube-system kube-apiserver-talos-cp1 1/1 Running 0 4m16s
kube-system kube-controller-manager-talos-cp1 1/1 Running 2 (6m40s ago) 4m59s
kube-system kube-proxy-vbx6x 1/1 Running 0 5m55s
kube-system kube-scheduler-talos-cp1 1/1 Running 2 (6m38s ago) 4m53s
kube-system metrics-server-75bf97fcc9-ftkpp 0/1 Pending 0 4m53s
kubelet-serving-cert-approver kubelet-serving-cert-approver-58b48cf746-2z8p9 0/1 Pending 0 4m53s

Maintenant que la partie Kubernetes minimale est en place, il vous faut déployer la CNI.

Pour déployer Cilium, ma préférence va à Helm. Je trouve que c’est plus élégant et facile à utiliser pour la maintenance courante du CNI.

Pour l’utilisation des GatewayAPI Kubernetes, le chart Helm de Cilium n’intégrant pas l’ajout des CRDs nécessaires, il faut les déployer manuellement en pré-requis au déploiement de Cilium.

On utilise le manifeste fourni par Kubernetes pour faire ce déploiement (pensez à vérifier la version) :

Terminal window
kubectl apply -f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.1.0/standard-install.yaml

Pour ajouter le dépot Helm de Cilium :

Terminal window
helm repo add cilium https://helm.cilium.io/
helm repo update

Pour installer Cilium, Talos nous fourni dans sa documentation les configurations nécessaires minimales.
De mon côté et comme je l’ai précisé en début de documentation, je vais ajouter quelques configurations pour notre cas d’usage.

Terminal window
helm install \
cilium \
cilium/cilium \
--version 1.16.1 \
--namespace kube-system \
--set ipam.mode=kubernetes \
--set kubeProxyReplacement=true \
--set securityContext.capabilities.ciliumAgent="{CHOWN,KILL,NET_ADMIN,NET_RAW,IPC_LOCK,SYS_ADMIN,SYS_RESOURCE,DAC_OVERRIDE,FOWNER,SETGID,SETUID}" \
--set securityContext.capabilities.cleanCiliumState="{NET_ADMIN,SYS_ADMIN,SYS_RESOURCE}" \
--set cgroup.autoMount.enabled=false \
--set cgroup.hostRoot=/sys/fs/cgroup \
--set k8sServiceHost=localhost \
--set k8sServicePort=7445 \
--set gatewayAPI.enabled=true \
--set ingressController.enabled=true \
--set ingressController.loadbalancerMode=shared \
--set nodePort.enabled=true \
--set externalIPs.enabled=true \
--set hostPort.enabled=true \
--set l2announcements.enabled=true

Les parties que j’ai spécifiées dans cette configuration sont :

  • --set kubeProxyReplacement=true : Définit que Cilium remplace la partie Kube Proxy
  • --set gatewayAPI.enabled=true : On active la feature de Gateway API
  • --set ingressController.enabled=true : On active l’ingressController
  • --set ingressController.loadbalancerMode=shared : On définit l’ingressController comme étant partagé (on y revient)
  • --set nodePort.enabled=true : On autorise l’utilisation des ports
  • --set externalIPs.enabled=true : On autorise l’exposition d’adresse IP externes
  • --set hostPort.enabled=true : On autorise l’exposition des ports sur l’hôte
  • --set l2announcements.enabled=true : On active l’annonce layer 2 pour les adresses IP du Load Balancer (on y revient aussi)

Deux paramètres un peu spécifiques :

ingressController.loadbalancerMode=shared : Ce que l’on vient faire à ce niveau, c’est de dire à l’ingressController déployé par Cilium (Envoy) qu’il utilisera le LoadBalancer de Kubernetes comme étant partagé entre toutes les configurations d’Ingress que l’on définira.

Concrètement, celà revient à avoir une adresse IP qui sera prise par le LoadBalancer et exposée qui traitera l’ensemble des requêtes à destination de l’ingressController.

L’ingressController fourni par Cilium est par défaut configuré en mode dedicated. C’est-à-dire qu’il utilisera une adresse IP par Ingress déclaré.
Celà peut avoir un intérêt certain dans le cadre de gros clusters Kubernetes avec beaucoup de Workers, ou des Workers dans des réseaux distincts.
Dans le cadre de cette installation, il n’est pas nécessaire d’avoir d’ingressController dédié vu que l’on ne tourne que sur 3 workers étant sur le même réseau.

l2announcements.enabled=true : Cet autre paramètre permet d’activer les réponses ARP pour les adresse consommées par le LoadBalancer.
Par défaut, les réponses ARP ne sont pas actives, et de ce fait, les adresses attribuées au LoadBalancer ne seront pas accessibles par le réseau local.

Après avoir appliqué ce déploiement, vous devriez voir vos pods coredns passer en état Running, et les pods propre à Cilium se déployer dans le cluster :

Terminal window
kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system cilium-envoy-htlmp 1/1 Running 0 4m48s
kube-system cilium-operator-857d7f4c6d-44672 0/1 Pending 0 4m48s
kube-system cilium-operator-857d7f4c6d-tq4xq 1/1 Running 0 4m48s
kube-system cilium-pvk5z 1/1 Running 0 4m48s
kube-system coredns-c78fdf99-4kkwp 1/1 Running 0 28m
kube-system coredns-c78fdf99-x5mcj 1/1 Running 0 28m
kube-system kube-apiserver-talostestcp1 1/1 Running 0 26m
kube-system kube-controller-manager-talostestcp1 1/1 Running 2 (28m ago) 26m
kube-system kube-proxy-vbx6x 1/1 Running 0 27m
kube-system kube-scheduler-talostestcp1 1/1 Running 2 (28m ago) 26m
kube-system metrics-server-75bf97fcc9-ftkpp 0/1 Pending 0 26m
kubelet-serving-cert-approver kubelet-serving-cert-approver-58b48cf746-2z8p9 1/1 Running 0 26m

Maintenant que le premier Control Plane est terminé, et que vous avez un cluster Kubernetes établis et « fonctionnel », il est temps d’ajouter les autres Control Planes.

Pour ce faire, répétez la même opération que pour le premier Control Plane :

Terminal window
talosctl apply-config --insecure -n <adresse_IP_du_CP> -f <configuration_cp>.yaml

Si on reprends la commande avec les informations données dans Préparation des hôtes ça donne ça :

Terminal window
talosctl apply-config --insecure -n 192.168.0.102 -f talos-cp2.yaml

Répétez l’opération pour le troisième Control Plane.

Vous pouvez également passer directement à la suite pour ajouter les workers au cluster.
Toutes fois, je vous recommande d’attendre l’initialisation complète des Control Plane avant afin d’éviter une potentielle problématique de synchronisation de base ETCD.

Pour la partie Worker, vous pouvez lancer tous les workers à la suite, celà ne posera pas de problèmes.

Pour déployer les Worker, lancez la même commande que pour les Control Plane, mais en spécifiant les configurations des workers :

Terminal window
talosctl apply-config --insecure -n <adresse_IP_du_worker> -f <configuration_worker>.yaml

Dans notre cas ça va donner les trois commandes suivantes :

Terminal window
talosctl apply-config --insecure -n 192.168.0.201 -f talos-worker1.yaml
talosctl apply-config --insecure -n 192.168.0.202 -f talos-worker2.yaml
talosctl apply-config --insecure -n 192.168.0.203 -f talos-worker3.yaml

Après quelques minutes vous aurez vos 6 machines en status Ready lorsque vous lancez un kubectl get nodes et votre cluster Kubernetes sera prêt à accueillir de la charge de travail.

Une fois que votre cluster sera complètement déployé et opérationnel, il restera quand même quelques parties afin qu’il soit réellement prêt à accueillir de la production.

Je ne le ferais pas ici parce que cette documentation est déjà bien trop longue à mon goût, mais je me permets de vous lister quelques points.

À grand minima :

  • Le déploiement d’un CSI pour la partie stockage
  • La configuration du LoadBalancer

Pour considérer le cluster « Production Grade », je vous recommande comme pour tout déploiement de cluster Kubernetes :

  • Le déploiement d’une gestion de certificats (cert-manager + trust-manager + gatekeeper (au besoin))
  • Le déploiement d’une stack d’observabilité (Prometheus/Loki/Grafana)
  • Une solution de sauvegarde