💾 Stockage#
Le stockage est certainement quelque chose dont vous aurez besoin. Les applications/conteneurs sans état sont amusants et tout, mais au final, si vous voulez faire quelque chose d’utile, vous devez stocker des données. Même si ces données sont aussi simples qu’un fichier de configuration.
Sérieusement, comment Amazon ou Google gèrent-ils le stockage persistant sur leurs clusters Kubernetes ? Peut-être qu’ils utilisent simplement un SAN externe, comme 3Par, et présentent des LUN à chaque nœud… comment gèrent-ils alors plusieurs conteneurs essayant d’écrire dans le même fichier ? J’ai beaucoup de questions à ce sujet.
⚙️ Options#
Rook + Ceph – Celui-ci peut éventuellement fonctionner, mais avec des builds arm64 non officielles merci à https://github.com/raspbernetes/. Je pense que c’est stable sur des serveurs normaux, et même prêt pour la production, mais il n’a pas survécu à deux redémarrages de mon cluster K8s sur Raspberry Pi 4. En combinant cela avec la charge lourde et la courbe d’apprentissage pas raide mais verticale de Ceph, je ne le recommanderais pas pour un cluster Raspberry domestique.
Longhorn – Un autre stockage natif Kubernetes, désormais enfin avec prise en charge d’arm64 prête à l’emploi ! https://github.com/longhorn/longhorn/issues/6. J’ai fini par choisir celui-ci comme seule solution viable.
GlusterFS + Heketi– GlusterFS fonctionne bien sur Raspberry Pi, je l’ai testé… Heketi est mort cependant, donc pas vraiment de support natif. Cependant, nous pouvons utiliser GlusterFS pour monter un dossier sur chaque nœud et dire à Kubernetes d’utiliser le système de fichiers local comme stockage. Cela rendrait les données disponibles sur chaque nœud, et au cas où le pod basculerait vers un autre, les données persistantes seraient là, en attente. Un léger problème avec GlusterFS cependant : il n’est pas recommandé pour les fichiers « live », c’est-à-dire les bases de données, ce qui est nul… Mais, pour être honnête, j’ai vu MySQL fonctionner sur un cluster GlusterFS en production 😀.
NFS – Curieusement, celui-ci fonctionne très bien. Vous pouvez créer des revendications et les gérer à partir de Kubernetes (mon premier cluster utilisait NFS comme stockage persistant, et cela fonctionnait bien). Cependant, il n’est pas en cluster, et ce point de défaillance unique le rend contraire à l’exercice que nous essayons de faire ici.
🦬 Longhorn#
Système de fichiers natif Kubernetes assez nouveau pour arm64, au moment de la rédaction, mais bon sang, ça a marché ! Après l’épreuve avec Rook + Ceph, c’était un jeu d’enfant de le mettre en place ! Mon cluster est maintenant dans une phase de test de stabilité de 5 semaines, et rien n’a été cassé.
Comme vous le savez grâce à la configuration de notre nœud, je souhaite utiliser mon NAS en iscsi pour servir de volume de stockage. Longhorn nous simplifie la tâche. Il vous suffit de monter le disque sous /var/lib/longhorn
, qui est un chemin de données par défaut. J’ai oublié de le faire au préalable et j’ai dû le modifier plus tard, c’est super simple, donc pas de soucis. Je me suis retrouvé avec mon stockage sous /QTS01APP210
.
/var/lib/longhorn
si vous n’utilisez pas d’autre disque ou disque USB. Je l’ai simplement changé en /QTS01APP210
car c’est facile à trouver. Et lorsque j’ajouterai d’autres disques, je les ajouterai sous /storage02,03,04…Il y a un problème avec Raspberry Pi : les noms des disques sont attribués presque au hasard. Par conséquent, même si vous avez des disques USB dans les mêmes emplacements sur plusieurs nœuds, ils peuvent être nommés au hasard, /dev/sda ou /dev/sdb, et il n’existe aucun moyen simple d’imposer cette dénomination, sans trop modifier les règles udev.
📝 Configuration logicielle requise#
Installez le logiciel suivant, à partir du nœud maître, exécutez :
ansible cube -b -m apt -a "name=nfs-common state=present"
ansible cube -b -m apt -a "name=open-iscsi state=present"
ansible cube -b -m apt -a "name=util-linux state=present"
🖴 Identification des disques pour le stockage#
Nous allons à nouveau utiliser beaucoup Ansible et ajouterons de nouvelles variables avec des noms de disque qui seront utilisées pour le stockage dans /etc/ansible/hosts
.
Nous allons utiliser la commande lsblk -f
sur chaque nœud et rechercher les étiquettes de disque :
root@control00 ~ ❯ ansible cube -b -m shell -a "lsblk -f" 20:47:17
control00 | CHANGED | rc=0 >>
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
mmcblk0
├─mmcblk0p1 vfat FAT32 CONTROL00 4ED7-B7A8 95M 25% /boot
└─mmcblk0p2 ext4 1.0 7e09287c-8c4d-40f6-aa37-49fcb8404ee8 53.8G 4% /
cube01 | CHANGED | rc=0 >>
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
└─sda1 ext4 1.0 1d1efc46-5bc2-4b1a-8b98-59d56c2d33b6 232.5G 0% /QTS01APP210
mmcblk0
├─mmcblk0p1 vfat FAT32 CUBE01 4ED7-B7A8 95M 25% /boot
└─mmcblk0p2 ext4 1.0 7e09287c-8c4d-40f6-aa37-49fcb8404ee8 54.1G 3% /
cube00 | CHANGED | rc=0 >>
NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS
sda
└─sda1 ext4 1.0 0e4b419a-be9e-463c-b1ee-402d2267bfd4 232.5G 0% /QTS01APP210
mmcblk0
├─mmcblk0p1 vfat FAT32 CUBE00 4ED7-B7A8 95M 25% /boot
└─mmcblk0p2 ext4 1.0 7e09287c-8c4d-40f6-aa37-49fcb8404ee8 53.9G 4% /
Comme vous pouvez le voir, chaque nœud possède deux disques, sda
et mmcblk0
, mais attribués au démarrage. Chaque disque qui se divise en <name>1
et <name>2
, et a /boot
et /
comme points de montage, ce sont nos disques OS. L’autre est notre « stockage » 🙂. Cependant, tous mes disques ne sont pas effacés, alors prenons-en soin. Vous pouvez voir les disques avec : └─sda1
ext4
Modifiez /etc/ansible/hosts
et ajoutez une nouvelle variable (j’ai choisi le nom var_disk) avec le disque à correspond à mon NAS.
[control]
control00 ansible_connection=local var_hostname=control00
[workers]
cube00 ansible_connection=ssh var_hostname=cube00 var_disk=sdb
cube01 ansible_connection=ssh var_hostname=cube01 var_disk=sdb
[cube:children]
control
workers
📂 Système de fichiers et montage#
Nous devons obtenir un numéro d’identification unique pour nos disques de stockage afin de pouvoir les monter à chaque fois, même si /dev/… leur étiquette change. Pour cela, nous avons besoin de l’UUID des disques.
root@control01:~/longhorn# ansible workers -b -m shell -a "blkid -s UUID -o value /dev/{{ var_disk }}"
cube0 | CHANGED | rc=0 >>
c70ed2cd-c239-4cf5-a2eb-2233e478d8d6
cube01 | CHANGED | rc=0 >>
b114d056-c935-4410-b490-02a3302b38d2
Ajoutez-les à /etc/ansible/hosts
, avec une autre variable personnalisée, par exemple :
[control]
control00 ansible_connection=local var_hostname=control00
[workers]
cube00 ansible_connection=ssh var_hostname=cube00 var_disk=sdb var_uuid=c70ed2cd-c239-4cf5-a2eb-2233e478d8d6
cube01 ansible_connection=ssh var_hostname=cube01 var_disk=sdb var_uuid=b114d056-c935-4410-b490-02a3302b38d2
[cube:children]
control
workers
En utilisant Ansible et le module mount
, nous pouvons monter les disques sur /QTS01APP210
ansible workers -m ansible.posix.mount -a "path=/QTS01APP210 src=UUID={{ var_uuid }} fstype=ext4 state=mounted" -b
📥 Installer Longhorn#
La préparation fastidieuse de Longhorn est terminée, nous pouvons simplement utiliser helm
pour l’installer.
# Sur le noeud control00
cd
helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace --set defaultSettings.defaultDataPath="/QTS01APP210"
# Si vous ne voulez pas créer un fichier de service séparé pour l'accès à l'interface utilisateur comme je l'ai fait plus tôt avec `service.yaml`, vous pouvez l'utiliser comme ceci:
helm install longhorn longhorn/longhorn --namespace longhorn-system --create-namespace --set defaultSettings.defaultDataPath="/QTS01APP210" --set service.ui.loadBalancerIP="192.168.1.201" --set service.ui.type="LoadBalancer"
- –set defaultSettings.defaultDataPath est facultatif, vous pouvez supprimer/modifier les disques ultérieurement à partir de l’interface utilisateur. Laissez-lui un peu de temps. Il devrait se déployer, peut-être que certains pods redémarreront, mais à la fin, cela devrait ressembler à ceci.
Tout ce qui se trouve sous l’espace de noms longhorn-system
doit être 1/1 Running ou 2/2 Running.
root@control00 ~ 6s ❯ kubectl -n longhorn-system get pod 20:47:27
NAME READY STATUS RESTARTS AGE
csi-attacher-644c7b7568-jzmgd 1/1 Running 0 2m35s
csi-attacher-644c7b7568-l7425 1/1 Running 0 2m35s
csi-attacher-644c7b7568-lhwsm 1/1 Running 0 2m35s
csi-provisioner-58cc84b487-2z6fg 1/1 Running 0 2m35s
csi-provisioner-58cc84b487-9kpz2 1/1 Running 0 2m35s
csi-provisioner-58cc84b487-ccmtl 1/1 Running 0 2m35s
csi-resizer-6d5c898684-c847p 1/1 Running 0 2m35s
csi-resizer-6d5c898684-gzltz 1/1 Running 0 2m35s
csi-resizer-6d5c898684-hjtl9 1/1 Running 0 2m35s
csi-snapshotter-68b686dc4-2xvxh 1/1 Running 0 2m34s
csi-snapshotter-68b686dc4-s9q8z 1/1 Running 0 2m34s
csi-snapshotter-68b686dc4-zqs48 1/1 Running 0 2m34s
engine-image-ei-f4f7aa25-kpxvq 1/1 Running 0 3m59s
engine-image-ei-f4f7aa25-xlj5m 1/1 Running 0 3m59s
instance-manager-22b5e92bfa081faf764f52b9783db72b 1/1 Running 0 3m29s
instance-manager-37a4fd9921fffa04019ba40fbe002539 1/1 Running 0 3m13s
longhorn-csi-plugin-5c2vq 3/3 Running 1 (107s ago) 2m34s
longhorn-csi-plugin-9jqtw 3/3 Running 0 2m34s
longhorn-driver-deployer-6485bd4659-bs7nd 1/1 Running 0 5m33s
longhorn-manager-fdzht 2/2 Running 1 (3m59s ago) 5m34s
longhorn-manager-pdhn4 2/2 Running 0 5m33s
longhorn-ui-777d8d5674-kbvrh 1/1 Running 0 5m33s
longhorn-ui-777d8d5674-t5rrf 1/1 Running 0 5m33s
CrashLooBackOff
vous devez désinstaller Longhorn avec helm uninstall longhorn
, puis le réinstaller avec la même commande mais ajouter --version 1.2.4
à la fin de la commande.Regardez aussi les services. Longhorn-frontend
est une interface utilisateur de gestion pour le stockage, similaire à celle de Rook + Ceph. Très utile !
Plus tard, nous lui attribuerons sa propre IP LoadBalancer.
root@control00 ~ 5m 45s ❯ kubectl -n longhorn-system get svc 16:29:31
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
longhorn-admission-webhook ClusterIP 10.43.76.119 <none> 9502/TCP 6m9s
longhorn-backend ClusterIP 10.43.94.159 <none> 9500/TCP 6m9s
longhorn-conversion-webhook ClusterIP 10.43.238.61 <none> 9501/TCP 6m9s
longhorn-frontend LoadBalancer 10.43.236.223 192.168.1.201 80:30321/TCP 6m9s
longhorn-recovery-backend ClusterIP 10.43.128.197 <none> 9503/TCP 6m9s
🖥️ Interface utilisateur#
Nous pouvons configurer une IP externe pour l’interface utilisateur à partir de la plage que nous avons configurée dans metallb.
Créez un fichier service.yaml
avec le contenu suivant :
apiVersion: v1
kind: Service
metadata:
name: longhorn-ingress-lb
namespace: longhorn-system
spec:
selector:
app: longhorn-ui
type: LoadBalancer
loadBalancerIP: 192.168.1.201
ports:
- name: http
protocol: TCP
port: 80
targetPort: http
J’ai choisi l’adresse IP 192.168.1.201
pour l’interface utilisateur. Ensuite, appliquez-la et vérifiez-la.
root@control00 ~ ❯ kubectl get svc --all-namespaces | grep longhorn-ingress-lb 21:07:36
longhorn-system longhorn-ingress-lb LoadBalancer 10.43.106.158 192.168.1.201 80:31964/TCP 19d
Si tout s’est bien passé, vous devriez voir ce qui suit arriver à cette adresse IP avec le navigateur :

Ci-dessus, il s’agit de mon système déjà utilisé. Il y a donc quelques disques créés.
➕ Ajouter /QTS01APP210#
Nous devons ajouter notre stockage monté en tant que disque pour Longhorn. Accédez à Node
l’interface utilisateur Web. Vous devez effectuer cette opération pour chaque nœud. Cliquez sur Operation -> Edit node and disks
:

Vous aurez déjà un nœud rempli avec un stockage par défaut /var/lib/longhorn
et un nom aléatoire.
Tout d’abord, cliquez sur Add Disk
, puis indiquez un nouvel emplacement de disque, en vous assurant de passer Scheduling
à Enable
.