Aller au contenu

Talos Linux : Support CSI, CCM et fGPU Outscale

Mise à jour :

logo 3ds outscale

Ce guide avancé détaille l’intégration complète d’un cluster Talos Linux avec l’infrastructure Outscale. Nous aborderons le déploiement du Cloud Controller Manager (CCM) pour la gestion automatique des ressources cloud, du Container Storage Interface (CSI) pour le stockage persistant, et la configuration du support GPU NVIDIA pour les charges de travail d’IA et de calcul intensif.

Comprendre les composants cloud-native

Avant de déployer ces composants, comprenons leur rôle dans l’écosystème Kubernetes.

Cloud Controller Manager (CCM)

Le CCM est un composant Kubernetes qui intègre la logique de contrôle spécifique au cloud provider. Il remplace certaines fonctions historiquement intégrées dans kube-controller-manager :

  • Node Controller : Gère le cycle de vie des nœuds (détection d’arrêt, suppression automatique)
  • Route Controller : Configure les routes réseau dans le VPC pour la communication inter-pods
  • Service Controller : Provisionne automatiquement des Load Balancers pour les services Kubernetes de type LoadBalancer

Sans CCM, vous devez gérer manuellement ces opérations. Avec CCM, Kubernetes pilote directement l’infrastructure Outscale via l’API.

Container Storage Interface (CSI)

Le CSI est le standard d’interface entre Kubernetes et les systèmes de stockage. Le driver CSI Outscale permet :

  • Provisionnement dynamique : Création automatique de volumes BSU (Block Storage Unit) à la demande
  • Attachement/Détachement : Montage automatique des volumes sur les nœuds appropriés
  • Snapshots : Sauvegarde et restauration de volumes
  • Expansion : Redimensionnement de volumes en ligne

Le CSI remplace l’ancien système de provisionnement in-tree qui était intégré directement dans Kubernetes.

Support GPU NVIDIA

Le support GPU dans Kubernetes nécessite plusieurs composants :

  • NVIDIA Device Plugin : Expose les GPUs comme ressources schedulables
  • NVIDIA Container Toolkit : Permet aux containers d’accéder aux GPUs de l’hôte

Pour Talos, la configuration GPU nécessite une image personnalisée contenant les drivers NVIDIA.

Installation de CCM et CSI Outscale

Pour intégrer Talos Linux avec Outscale, nous allons déployer le CCM et le CSI via Helm. Mais d’abord, nous devons configurer les credentials pour accéder à l’API Outscale.

Création des Secret Kubernetes

Dans un premier temps, il faut créer deux secrets Kubernetes contenant les credentials d’accès à l’API Outscale. Utilisez vos clés d’accès :

Terminal window
# Créer les secrets avec les credentials
kubectl create secret generic osc-csi-bsu \
--namespace=kube-system \
--from-literal=access_key="<SECRET_KEY>" \
--from-literal=secret_key="<ACCESS_KEY>" \
--from-literal=aws_default_region="eu-west-2"
kubectl create secret generic osc-secret \
--namespace=kube-system \
--from-literal=access_key="<SECRET_KEY>" \
--from-literal=secret_key="<ACCESS_KEY>" \
--from-literal=aws_default_region="eu-west-2"
# Vérifier la création
kubectl get secret osc-csi-bsu osc-secret -n kube-system
NAME TYPE DATA AGE
osc-csi-bsu Opaque 3 3m12s
osc-secret Opaque 3 1s

Déploiement du Cloud Controller Manager (CCM)

Le CCM Outscale est disponible via un chart Helm officiel :

Terminal window
helm upgrade --install osc-ccm oci://registry-1.docker.io/outscalehelm/osc-cloud-controller-manager \
--set oscSecretName=osc-secret \
--set image.tag=v1.33.0 \
--namespace kube-system

Vérification du déploiement

Vérifiez que le CCM fonctionne correctement :

Terminal window
# Vérifier les pods du CCM
kubectl get pods -n kube-system -l app=osc-cloud-controller-manager -n kube-system
NAME READY STATUS RESTARTS AGE
osc-cloud-controller-manager-58k6b 1/1 Running 0 83s
osc-cloud-controller-manager-rs8cl 1/1 Running 0 83s
osc-cloud-controller-manager-s6v2d 1/1 Running 0 83s
# Consulter les logs
kubectl logs -n kube-system -l app=osc-cloud-controller-manager --tail=50
I1127 07:46:42.767595 1 leaderelection.go:293] successfully renewed lease kube-system/cloud-controller-manager
I1127 07:46:44.774099 1 leaderelection.go:293] successfully renewed lease kube-system/cloud-controller-manager
I1127 07:46:46.780280 1 leaderelection.go:293] successfully renewed lease kube-system/cloud-controller-manager
I1127 07:46:48.786674 1 leaderelection.go:293] successfully renewed lease kube-system/cloud-controller-manager

Déploiement du CSI Driver Outscale

Le CSI permet le provisionnement dynamique de volumes BSU (Block Storage Unit) Outscale.

Terminal window
helm upgrade --install osc-bsu-csi-driver oci://docker.io/outscalehelm/osc-bsu-csi-driver \
--wait --wait-for-jobs \
--set oscSecretName=osc-csi-bsu \
--namespace kube-system

Vérification du déploiement CSI

Terminal window
# Vérifier les pods CSI
kubectl get pod -n kube-system -l "app.kubernetes.io/name=osc-bsu-csi-driver,app.kubernetes.io/instance=osc-bsu-csi-driver"
NAME READY STATUS RESTARTS AGE
osc-csi-controller-679cf6c8b5-rz44q 5/5 Running 0 35s
osc-csi-controller-679cf6c8b5-sbkmv 5/5 Running 0 35s
osc-csi-node-2frqg 3/3 Running 0 35s
osc-csi-node-5zlph 3/3 Running 0 35s
osc-csi-node-7lhnn 3/3 Running 0 35s
osc-csi-node-cnl6h 3/3 Running 0 35s
osc-csi-node-crc85 3/3 Running 0 35s
osc-csi-node-hz8cp 3/3 Running 0 35s
osc-csi-node-r8tp5 3/3 Running 0 35s
# Vérifier le driver CSI
kubectl get csidrivers
NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE
bsu.csi.outscale.com true false false <unset> false Persistent 60s

Création des StorageClass

Créez les StorageClass pour provisionner automatiquement des volumes BSU :

Terminal window
cat <<EOF | kubectl apply -f -
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: outscale-gp2
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: bsu.csi.outscale.com
parameters:
type: gp2
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: outscale-io1
provisioner: bsu.csi.outscale.com
parameters:
type: io1
iops: "1000"
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: outscale-standard
provisioner: bsu.csi.outscale.com
parameters:
type: standard
volumeBindingMode: WaitForFirstConsumer
allowVolumeExpansion: true
EOF

Les types de volumes Outscale disponibles :

  • standard : Volumes magnétiques (HDD)
  • gp2 : SSD à usage général (General Purpose)
  • io1 : SSD haute performance avec IOPS provisionnées

Test de provisionnement dynamique

Testez le CSI en créant un PVC (PersistentVolumeClaim) :

Terminal window
cat <<EOF | kubectl apply -f -
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
storageClassName: outscale-gp2
resources:
requests:
storage: 10Gi
---
apiVersion: v1
kind: Pod
metadata:
name: test-csi-pod
namespace: default
spec:
containers:
- name: app
image: nginx:alpine
volumeMounts:
- name: data
mountPath: /data
command: ["/bin/sh"]
args:
- -c
- |
echo "Test CSI Outscale - $(date)" > /data/test.txt
echo "Volume monté avec succès !" >> /data/test.txt
cat /data/test.txt
tail -f /dev/null
volumes:
- name: data
persistentVolumeClaim:
claimName: test-pvc
EOF

Vérifiez le provisionnement :

Terminal window
# Vérifier le PVC
kubectl get pvc test-pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
test-pvc Bound pvc-e80722fb-a2ca-4872-b63e-c936997f0c7a 10Gi RWO outscale-gp2 <unset> 28s
# Vérifier le PV créé automatiquement
kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
pvc-e80722fb-a2ca-4872-b63e-c936997f0c7a 10Gi RWO Delete Bound default/test-pvc outscale-gp2 <unset> 39s
# Vérifier que le pod est Running
kubectl get pod test-csi-pod
NAME READY STATUS RESTARTS AGE
test-csi-pod 1/1 Running 0 70s
# Vérifier le volume dans Outscale
osc-cli api ReadVolumes --Filters '{"Tags": [{"Key": "Name", "Value": "test-pvc"}]}'

Le volume doit être créé automatiquement dans Outscale et attaché au nœud hébergeant le pod.

Testez l’écriture :

Terminal window
# Écrire des données dans le volume
kubectl exec test-csi-pod -- sh -c "echo 'Test CSI Outscale' > /data/test.txt"
# Vérifier la lecture
kubectl exec test-csi-pod -- cat /data/test.txt
Test CSI Outscale

Nettoyez les ressources :

Terminal window
kubectl delete pod test-csi-pod --force --grace-period=0s
kubectl delete pvc test-pvc

Configuration du support GPU NVIDIA

Pour utiliser des GPUs NVIDIA sur Talos, vous devez créer une image personnalisée avec les extensions GPU et déployer le NVIDIA GPU Operator.

Création d’une image Talos avec support GPU

Pour simplifier la création d’une image Talos Linux avec les drivers NVIDIA, vous utilisez mon dépot GitHub :

Terminal window
git clone https://github.com/stephrobert/talos-outscale.git
cd talos-outscale
# Copier le fichier d'exemple
cp .envrc.sample .envrc
# Éditer avec vos credentials
vim .envrc

Contenu du .envrc :

Terminal window
export OSC_ACCESS_KEY="VOTRE_ACCESS_KEY"
export OSC_SECRET_KEY="VOTRE_SECRET_KEY"
export OSC_REGION="eu-west-2"
export TF_VAR_access_key_id="$OSC_ACCESS_KEY"
export TF_VAR_secret_key_id="$OSC_SECRET_KEY"
export PACKER_LOG=1
export PACKER_LOG_PATH="./packer.log"

Chargez les variables d’environnement :

Terminal window
source .envrc
# Ou avec direnv
direnv allow

Construisez l’image GPU :

Terminal window
cd packer
# Copier et éditer les variables
cp variables.auto.pkrvars.hcl.example variables.auto.pkrvars.hcl
vim variables.auto.pkrvars.hcl
packer init talos-gpu-outscale.pkr.hcl
# Valider la configuration GPU
packer validate talos-gpu-outscale.pkr.hcl
# Build de l'OMI GPU (type universal recommandé)
packer build talos-gpu-outscale.pkr.hcl

Déploiement d’instances GPU

Lors du déploiement de nœuds GPU, utilisez l’OMI Talos Linux avec support GPU. Par exemple, avec Terraform, spécifiez l’OMI dans la ressourcce. Idem pour simplifier, vous pouvez utiliser mon dépôt GitHub avec les configurations Terraform adaptées. Il ne manque que l’attachement des GPU sur les instances. Opération que vous pouvez faire manuellement via l’interface Cockpit Outscale.

Une fois le node GPU provisionné, nous allons créer un patch Talos pour activer les extensions GPU. Pour cela créer le patch suivant talos-gpu-patch.yaml :

machine:
kernel:
modules:
- name: nvidia
- name: nvidia_uvm
- name: nvidia_drm
- name: nvidia_modeset
sysctls:
net.core.bpf_jit_harden: 1
nodeLabels:
node.kubernetes.io/worker-type: gpu
nvidia.com/gpu.present: "true"

Créons ensuite la configuration Talos avec le patch GPU :

Terminal window
talosctl --talosconfig ./talos-out/talosconfig apply-config --insecure --nodes 10.0.1.30 --file ./talos-out/worker-gpu.yaml

Ajoutons le node GPU au cluster Talos :

Terminal window
talosctl --talosconfig ./talos-out/talosconfig apply-config --insecure --nodes 10.0.1.30 --file ./talos-out/worker-gpu.yaml

Vérifions que le nœud GPU est bien ajouté au cluster Kubernetes :

Terminal window
kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-10-0-1-10 Ready control-plane 94m v1.34.1 10.0.1.10 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5
ip-10-0-1-20 Ready <none> 85m v1.34.1 10.0.1.20 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5
ip-10-0-2-11 Ready control-plane 92m v1.34.1 10.0.2.11 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5
ip-10-0-2-21 Ready <none> 85m v1.34.1 10.0.2.21 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5
ip-10-0-3-12 Ready control-plane 94m v1.34.1 10.0.3.12 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5
ip-10-0-3-22 Ready <none> 85m v1.34.1 10.0.3.22 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5
talos-5jn-u1l Ready <none> 25m v1.34.1 10.0.1.30 <none> Talos (v1.11.5) 6.12.57-talos containerd://2.1.5

Super, mais je dois fixer le nom du nœud GPU pour l’identifier facilement.

Vérification du support GPU

Vérifions les extensions de ce node :

Terminal window
NODE NAMESPACE TYPE ID VERSION NAME VERSION
10.0.1.30 runtime ExtensionStatus 0 1 nvidia-open-gpu-kernel-modules-production 570.172.08-v1.11.5
10.0.1.30 runtime ExtensionStatus 1 1 nvidia-container-toolkit-production 570.172.08-v1.17.8
10.0.1.30 runtime ExtensionStatus 2 1 nvidia-fabricmanager-production 570.172.08

On vérifie que les modules NVIDIA sont bien chargés :

Terminal window
export TALOSCONFIG=/home/outscale/talos-out/talosconfig
talosctl -e 10.0.1.30 -n 10.0.1.30 read /proc/modules |grep nvidia
nvidia_uvm 2260992 0 - Live 0xffffffffc14b0000 (O)
nvidia_drm 147456 0 - Live 0xffffffffc148a000 (O)
nvidia_modeset 2109440 1 nvidia_drm, Live 0xffffffffc11fd000 (O)
nvidia 12787712 7 nvidia_uvm,nvidia_modeset, Live 0xffffffffc05c9000 (O)

Déploiement du Nvidia Device Plugin

Pas besoin d’utiliser le Nvidia Gpu Operator, car les drivers sont déjà installés dans l’image Talos. Nous allons simplement déployer le Device Plugin via Helm :

Terminal window
helm repo add nvidia https://nvidia.github.io/k8s-device-plugin
helm repo update
## Création de la runtimeClass pour les pods GPU
cat <<EOF | kubectl apply -f -
---
apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
name: nvidia
handler: nvidia
EOF
## On ne veut scheduler les pods GPU que sur les nœuds avec GPU
cat > /tmp/device-plugin-values.yaml <<EOF
runtimeClassName: nvidia
nodeSelector:
nvidia.com/gpu.present: "true"
EOF
helm install nvidia-device-plugin nvdp/nvidia-device-plugin \
--version=0.13.0 \
--namespace kube-system \
--values /tmp/device-plugin-values.yaml

On vérifie le déploiement :

Terminal window
kubectl get pods -n kube-system -l app.kubernetes.io/name=nvidia-device-plugin
nvidia-device-plugin-4jckx 1/1 Running 0 4m13s

Test avec un workload GPU

Déployez un pod de test utilisant le GPU :

Terminal window
kubectl run \
nvidia-test \
--restart=Never \
-ti --rm \
--image nvcr.io/nvidia/cuda:12.5.0-base-ubuntu22.04 \
--overrides '{"spec": {"runtimeClassName": "nvidia"}}' \
nvidia-smi
Thu Nov 27 08:43:18 2025
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 570.172.08 Driver Version: 570.172.08 CUDA Version: 12.8 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA H100 PCIe On | 00000000:13:00.0 Off | 0 |
| N/A 37C P0 51W / 350W | 0MiB / 81559MiB | 0% Default |
| | | Disabled |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
pod "nvidia-test" deleted from kube-system namespace

Cool ca marche ! Vous pouvez maintenant déployer des workloads GPU sur votre cluster Talos Linux.

Conclusion

Vous disposez maintenant d’un cluster Talos Linux production-ready sur Outscale avec :

  • Cloud Controller Manager : Intégration automatique avec l’infrastructure Outscale (Load Balancers, routes, métadonnées)
  • CSI Driver : Provisionnement dynamique de volumes BSU avec snapshots et expansion
  • Support GPU NVIDIA : Accélération matérielle pour l’IA et le calcul haute performance

Cette configuration permet de déployer des applications cloud-native avec stockage persistant et accélération GPU, tout en bénéficiant de l’orchestration automatisée de Kubernetes et de la sécurité renforcée de Talos Linux.

Prochaines étapes

Pour aller plus loin :

  • Configurez un système de monitoring avec Prometheus et Grafana
  • Déployez un Ingress Controller (NGINX, Traefik) pour l’exposition HTTP/HTTPS
  • Mettez en place une solution de backup avec Velero
  • Implémentez des Network Policies avec Cilium pour la microsegmentation
  • Rendre le cluster air-gapped avec un registre d’images privé. Je vais commencer à travailler sur un guide dédié à ce sujet.