Talos et les disques externes
Contexte
J’utilise beaucoup Talos en ce moment, et je suis confronté à un besoin spécifique : je souhaite utiliser des disques externes pour créer des PVC pour mes applications. C’est un cas d’utilisation assez spécifique, mais je pense que cela peut être utile pour d’autres personnes, voici le résultat de mes recherches.
Talos
Petit rappel sur ce qu’est Talos : c’est une distribution immuable dédiée à Kubernetes. Celle-ci est réputée pour être minimaliste (pas de shell, pas de systemd, pas de gestionnaire de paquet). Ainsi lorsqu’on souhaite modifier un paramètre dans le système, il faut passer par des patchs yaml
qui seront appliqués par talosctl
.
La problématique dans le fait de monter des disques dans Talos est que nous devons nous plier à ce que Talos demande et qu’il n’est pas possible d’utiliser des outils comme fdisk
ou mkfs
pour formater les disques.
L’objectif est alors le suivant : Créer un PV par disque. Pour cela, nous allons utiliser le provisionneur local-static-provisioner
.
Installation of local-static-provisioner
Local Static Provisioner est un provisionneur de stockage qui permet de créer des PV à partir de disques locaux. Dans les faits, nous pouvons lui donner un dossier qu’il va surveiller. Dès qu’un point de montage est créé dans ce dossier, il va créer un PV associé à ce point de montage.
Celui-ci s’installe via un Helm Chart :
helm repo add sig-storage-local-static-provisioner https://kubernetes-sigs.github.io/sig-storage-local-static-provisioner/
helm install local-static-provisioner sig-storage-local-static-provisioner/local-static-provisioner -n local-static-provisioner --create-namespace
Dans le fichier valeur, nous pouvons définir les classes de stockage (StorageClass) que nous souhaitons créer. Pour chaque classe, nous devons définir un dossier qui sera surveillé par le provisionneur.
classes:
- name: fast-storage
hostDir: /var/lib/disks/ssd/
volumeMode: Filesystem
storageClass: true
fsType: xfs
- name: slow-storage
hostDir: /var/lib/disks/hdd/
volumeMode: Filesystem
fsType: xfs
storageClass: true
- name: block-storage
hostDir: /var/lib/disks/block/
blockCleanerCommand:
- "/scripts/quick_reset.sh"
volumeMode: Block
storageClass: true
Remarque
Comme montré dans le dernier dossier (block-storage), il est aussi possible de créer des volumes en “Block” (qui seront formatés au scheduling). Dans ce cas, plutôt que de créer des points de montage, nous devons créer des liens symboliques vers les disques.
ln -s /dev/sdb /var/lib/disks/block/sdb
À savoir que Talos ne permet (pas encore?) la création de ce lien symbolique directement dans sa configuration. Il faudra passer par un pod avec 2 volumes HostPath pour créer ce lien.
Nous reparlerons des volumes en Block un plus bas.
Voici les 3 classes de stockage que nous avons créées :
fast-storage
pour les disques SSDslow-storage
pour les disques HDDblock-storage
pour tous les disques qui seront en mode bloc.
Cependant, ces SC ne peuvent actuellement pas provisionner de PVC. Nous devons encore ajouter les disques aux dossiers configurés dans le fichier valeur.
Configuration des disques
Considérons que nous avons 5 disques par machine, voici notre organisation :
- vda - Disque système (ne sera pas utilisé)
- vdb - SSD
- vdc - SSD
- vdd - HDD
- vde - HDD
- vdf - Block
- vdg - Block
Pour créer ces points de montage, nous devons les ajouter dans le fichier de configuration de Talos. Celui-ci va créer les dossiers demandés lors de l’ajout de cette configuration.
machine:
disks:
- device: /dev/vdb
partitions:
- mountpoint: /var/lib/disks/ssd/vdb
- device: /dev/vdc
partitions:
- mountpoint: /var/lib/disks/ssd/vdb
- device: /dev/vdd
partitions:
- mountpoint: /var/lib/disks/hdd/vdd
- device: /dev/vde
partitions:
- mountpoint: /var/lib/disks/hdd/vde
Après avoir appliqué ce patch à mes workers via talosctl patch mc --nodes w-1,w-2,w-3 --patch @patch.yaml
Local Static Provisioner devrait avoir créé des PV liés à ces disques.
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
local-pv-1f3185eb 60Gi RWO Delete Available fast-storage 4h54m
local-pv-50be5869 60Gi RWO Delete Available fast-storage 4h54m
local-pv-5ec0ef44 60Gi RWO Delete Available slow-storage 4h54m
local-pv-9119c1d6 60Gi RWO Delete Available slow-storage 4h54m
Nous pouvons maintenant créer un PVC et un pod pour tester si le stockage est bien monté.
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
spec:
containers:
- name: nginx
image: nginx:latest
volumeMounts:
- mountPath: "/usr/share/nginx/html"
name: nginx-pvc
volumes:
- name: nginx-pvc
persistentVolumeClaim:
claimName: nginx-pvc
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: slow-storage
Malheureusement, le pod échoue avec une erreur FailedMount
provenant de kubelet :
$ kubectl describe pod nginx-pod
# ...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 5s default-scheduler 0/6 nodes are available: persistentvolumeclaim "nginx-pvc" not found. preemption: 0/6 nodes are available: 6 Preemption is not helpful for scheduling..
Normal Scheduled 3s default-scheduler Successfully assigned default/nginx-pod to worker-4
Warning FailedMount 0s (x4 over 3s) kubelet MountVolume.NewMounter initialization failed for volume "local-pv-485eb69c" : path "/var/lib/disks/hdd/vde" does not exist
La raison à ça est que le kubelet n’a pas accès aux dossiers créés par Talos (c’est le cas dès lors que Kubelet est lui-même un conteneur), celui-ci doit pourtant pouvoir y accéder pour monter les volumes dans les pods sous forme de PV Local (cette limitation n’existe pas pour les volumes en mode HostPath
). Nous devons alors patcher la configuration de Talos pour que le kubelet puisse accéder à ces dossiers.
Voici notre nouveau patch :
machine:
kubelet:
extraMounts:
- destination: /var/lib/disks/
type: bind
source: /var/lib/disks/
options:
- rbind
- rshared
- rw
Plutôt que de créer un extraMounts pour chaque catégorie de disque, nous pouvons en utiliser un seul pour tous les disques.
Volume en block
Comme dit en début d’article, pour créer des volumes en mode bloc, nous devons créer des liens symboliques vers les disques. Talos ne peut pas créer ces liens directement, nous devons alors passer par un pod qui va créer ces liens.
Plutôt que d’en déployer un à la main, nous pouvons utiliser le daemonset de local-static-provisioner
pour créer ce lien.
En admettant que les disques vdf
et vdg
sont des disques en mode bloc sur toutes les machines, nous pouvons lancer ce script Bash :
pods=$(kubectl get pods -n local-pv -l app.kubernetes.io/name=local-static-provisioner -o jsonpath='{.items[*].metadata.name}')
disks=("vdf" "vdg")
for pod in $pods; do
for disk in "${disks[@]}"; do
echo "Linking /dev/$disk to /var/lib/disks/block/$disk in pod $pod"
kubectl exec $pod -- /bin/sh -c "mkdir /var/lib/disks/block"
kubectl exec $pod -- /bin/sh -c "ln -s /dev/$disk /var/lib/disks/block/$disk"
done
done
*Bien sûr, cette commande fonctionne uniquement parce que les pods possèdent un HostPath vers /var/lib/disks/block
.
Maintenant, nous devrions avoir nos nouveaux PV sur la classe de stockage block-storage
.
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
local-pv-1f3185eb 60Gi RWO Delete Available fast-storage 4h54m
local-pv-50be5869 60Gi RWO Delete Available fast-storage 4h54m
local-pv-5ec0ef44 60Gi RWO Delete Available slow-storage 4h54m
local-pv-9119c1d6 60Gi RWO Delete Available slow-storage 4h54m
local-pv-e13d6c91 60Gi RWO Delete Available block-storage 13m
local-pv-699a79e5 60Gi RWO Delete Available block-storage 13m
Nous pouvons à présent créer un pod et monter le PVC pour tester si le stockage block est bien disponible.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: block-pvc
spec:
storageClassName: block-storage
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
volumeMode: Block
---
apiVersion: v1
kind: Pod
metadata:
name: ubuntu-pod
spec:
containers:
- name: ubuntu-container
image: ubuntu:latest
command: ["/bin/bash", "-c", "while true; do sleep 3600; done"]
volumeDevices:
- name: my-block-storage
devicePath: /dev/sdo
volumes:
- name: my-block-storage
persistentVolumeClaim:
claimName: block-pvc
On peut maintenant vérifier si le sdo est bien mappé dans le container :
kubectl exec pods/ubuntu-pod -- ls -lah /dev/sdo
brw------- 1 root root 253, 48 Aug 20 19:35 /dev/sdo