Kubernetes: Proxmox VE Container Storage Interface (CSI) Driver
Hoy vamos manejar el almacenamiento de Proxmox VE de forma nativa con Kubernetes…para ello usaremos un driver.
La integración de Proxmox VE con Kubernetes a través del Container Storage Interface (CSI) Driver permite que Kubernetes gestione el almacenamiento proporcionado por Proxmox VE de manera nativa. Este driver proporciona una forma estandarizada de aprovisionar y gestionar volúmenes de almacenamiento para contenedores en un clúster de Kubernetes, utilizando el almacenamiento de Proxmox VE.
Container Storage Interface (CSI) es una especificación estándar que define una interfaz para la provisión de almacenamiento en contenedores. CSI permite a los proveedores de almacenamiento desarrollar drivers que pueden ser utilizados por cualquier sistema de orquestación de contenedores que soporte la especificación CSI, como Kubernetes.
Documentación Proxmox VE CSI Driver
Os dejo unos cuantos enlaces en los que me he basado:
- https://github.com/sergelogvinov/proxmox-csi-plugin
- https://arslan.io/2018/06/21/how-to-write-a-container-storage-interface-csi-plugin/
- https://kubernetes-csi.github.io/docs/
- https://pve.proxmox.com/wiki/Manual:_qm.conf
- https://pve.proxmox.com/wiki/Performance_Tweaks
- https://kb.blockbridge.com/guide/proxmox/
- https://github.com/sergelogvinov/ansible-role-proxmox
- https://github.com/sergelogvinov/terraform-talos/tree/main/proxmox
- https://storageclass.info/csidrivers/
Beneficios del Proxmox VE CSI Driver
- Compatibilidad: Permite que Kubernetes gestione el almacenamiento de Proxmox VE de manera nativa.
- Eficiencia: Automatiza la provisión y gestión de volúmenes de almacenamiento, reduciendo la intervención manual.
- Flexibilidad: Facilita la integración de las capacidades de almacenamiento de Proxmox VE en un clúster de Kubernetes.
- Escalabilidad: Soporta la creación y eliminación dinámica de volúmenes de almacenamiento según las necesidades del clúster.
Hay que decir que estamos limitados:
Requisitos previos para implementar Proxmox VE CSI Driver
Antes de comenzar la instalación del Proxmox VE CSI Driver, asegúrate de cumplir con los siguientes requisitos:
- Un clúster de Proxmox VE configurado y funcionando
- Un clúster de Kubernetes configurado y funcionando
- Acceso administrativo a los servidores
- Conocimientos básicos de Proxmox VE y Kubernetes
En mi caso ya tengo todo montado en mi LAB, usaré mi clúster Proxmox en versión 8.2.2 y tres nodos de Kubernetes que ya tenía montamos sobre Debian 12:
Os dejo la versión de Kubernetes:
1 2 3 4 5 |
root@KUBERNETES00:~# kubectl get nodes NAME STATUS ROLES AGE VERSION kubernetes01 Ready <none> 148d v1.28.6+k3s2 kubernetes02 Ready <none> 148d v1.28.6+k3s2 kubernetes00 Ready control-plane,master 149d v1.28.6+k3s2 |
Permisos en clúster Proxmox para trabajar con CSI Driver
Necesitamos preparar nuestro clúster Proxmox para que exista un role que pueda manejar el storage desde Kubernetes. Para ello creamos un role con el siguiente comando para el driver CSI:
1 |
root@minis:~# pveum role add CSI -privs "VM.Audit VM.Config.Disk Datastore.Allocate Datastore.AllocateSpace Datastore.Audit" |
Ahora creamos un usuario y le asignamos el role que hemos creado de la siguiente forma:
1 2 3 4 5 6 7 8 9 10 11 12 |
root@minis:~# pveum user add kubernetes-csi@pve root@minis:~# pveum aclmod / -user kubernetes-csi@pve -role CSI root@minis:~# pveum user token add kubernetes-csi@pve csi -privsep 0 ┌──────────────┬──────────────────────────────────────┐ │ key │ value │ ╞══════════════╪══════════════════════════════════════╡ │ full-tokenid │ kubernetes-csi@pve!csi │ ├──────────────┼──────────────────────────────────────┤ │ info │ {"privsep":"0"} │ ├──────────────┼──────────────────────────────────────┤ │ value │ 56cce90f-ebab-4127-9f9e-59f085567f6e │ └──────────────┴──────────────────────────────────────┘ |
Podéis validar conexión de la siguiente forma:
1 2 |
root@KUBERNETES00:~# curl -k -H 'Content-Type: application/json' -H 'Authorization: PVEAPIToken=kubernetes -csi@pve!csi=56cce90f-ebab-4127-9f9e-59f085567f6e' https://minis.negu.local:8006/api2/json |
Os muestro como están definidos mis almacenamientos en mi clúster Proxmox, usaré para este fin el SSD480GB que pasaré a formato XFS. Lo formateo:
Y lo vuelvo a agregar desde Discos -> Directorio, en este caso de mi nodo:
Queda así, en formato XFS y montado:
Y el tipo de almacenamiento que tiene cada nodo de Kubernetes, con controlador SCSI “VirtlO SCSI Single”, “iothread” activado y un disco al share NFS de mi NAS Unraid de 32GB:
Con nuestro clúster Proxmox preparado ahora tenemos que prepara el clúster Kubernetes.
Configurar clúster Kubernetes para driver CSI
Generamos un fichero “proxmox-csi.yaml” que nos permitirá realizar la configuración, con los datos del token que hemos generado antes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
root@KUBERNETES00:~/csi# nano proxmox-csi.yaml # proxmox-csi.yaml config: clusters: - url: https://minis.negu.local:8006/api2/json insecure: false token_id: "kubernetes-csi@pve!csi" token_secret: "56cce90f-ebab-4127-9f9e-59f085567f6e" region: NEGULAB - url: https://minis2.negu.local:8006/api2/json insecure: false token_id: "kubernetes-csi@pve!csi" token_secret: "56cce90f-ebab-4127-9f9e-59f085567f6e" region: NEGULAB storageClass: - name: proxmox-data-xfs storage: SSD480GB reclaimPolicy: Delete fstype: xfs |
Creamos un namespace con nombre “csi-proxmox”:
1 2 |
root@KUBERNETES00:~/csi# kubectl create namespace csi-proxmox namespace/csi-proxmox created |
Tenemos que etiquetar el espacio de nombres para permitir que el complemento se ejecute como privilegiado:
1 2 |
root@KUBERNETES00:~/csi# kubectl label ns/csi-proxmox pod-security.kubernetes.io/enforce=privileged namespace/csi-proxmox labeled |
Ejecutamos con helm:
1 2 3 4 5 6 7 8 9 10 |
root@KUBERNETES00:~/csi# helm upgrade -i -n csi-proxmox -f proxmox-csi.yaml proxmox-csi-plugin oci://ghcr.io/sergelogvinov/charts/proxmox-csi-plugin Release "proxmox-csi-plugin" does not exist. Installing it now. Pulled: ghcr.io/sergelogvinov/charts/proxmox-csi-plugin:0.2.5 Digest: sha256:3048804830aa700dfbe6a9fee72b9d386def5b8d7208939fe07ac6ce07ab4c49 NAME: proxmox-csi-plugin LAST DEPLOYED: Fri Jul 26 12:27:58 2024 NAMESPACE: csi-proxmox STATUS: deployed REVISION: 1 TEST SUITE: None |
Ya tenemos todo preparado, os dejo unos datos extras:
Para especificar el almacenamiento dentro del clúster usaremos las siguientes etiquetas, que luego veremos en un ejemplo como utilizarlas:
- topology.kubernetes.io/region
- topology.kubernetes.io/zone
- Spec.ProviderID
Para la definición de los recursos de almacenamiento tendremos las siguientes variables que pasaremos en un fichero “storageclass.yaml”:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: proxmox-data-xfs parameters: csi.storage.k8s.io/fstype: xfs|ext4 storage: data cache: directsync|none|writeback|writethrough ssd: "true|false" provisioner: csi.proxmox.sinextra.dev allowVolumeExpansion: true reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer |
Modificamos el parámetro “storage” en mi caso por SSD480GB, “ssd” en mi caso a TRUE, “csi.storage.k8s.io/fstype” a XFS y “cache” a NONE. Os dejo más detalle:
https://github.com/sergelogvinov/proxmox-csi-plugin/blob/main/docs/options.md
1 2 |
root@KUBERNETES00:~/csi# kubectl apply -f storageclass.yaml storageclass.storage.k8s.io/proxmox-data-xfs created |
Os dejo un ejemplo de NFS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
--- apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: nfs-csi provisioner: nfs.csi.k8s.io parameters: server: unraid.negy.local share: / # csi.storage.k8s.io/provisioner-secret is only needed for providing mountOptions in DeleteVolume # csi.storage.k8s.io/provisioner-secret-name: "mount-options" # csi.storage.k8s.io/provisioner-secret-namespace: "default" reclaimPolicy: Delete volumeBindingMode: Immediate mountOptions: - nfsvers=4.1 |
Validar driver CSI
Revisamos que está todo implementado:
1 2 3 |
root@KUBERNETES00:~/csi# kubectl get CSIDriver NAME ATTACHREQUIRED PODINFOONMOUNT STORAGECAPACITY TOKENREQUESTS REQUIRESREPUBLISH MODES AGE csi.proxmox.sinextra.dev true true true <unset> false Persistent 5m6s |
Nos mostrará este comando el storage disponible:
1 |
kubectl get csistoragecapacities -ocustom-columns=CLASS:.storageClassName,AVAIL:.capacity,ZONE:.nodeTopology.matchLabels -A |
Deployment de ejemplo CSI Kubernetes + Proxmox
Podemos lanzar un deployment de prueba generando un Pod de la siguiente forma. Yo lo he bajado y adaptado a mi entorno para ejecutarlo:
1 2 |
root@KUBERNETES00:~/csi# kubectl apply -f https://raw.githubusercontent.com/sergelogvinov/proxmox-csi-plugin/main/docs/deploy/test-pod-ephemeral.yaml pod/test created |
El contenido original es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
apiVersion: v1 kind: Pod metadata: name: test namespace: default spec: tolerations: - effect: NoSchedule key: node-role.kubernetes.io/control-plane nodeSelector: kubernetes.io/hostname: kube-11 containers: - name: alpine image: alpine command: ["sleep","6000"] volumeMounts: - name: pvc mountPath: /mnt securityContext: allowPrivilegeEscalation: false capabilities: drop: - ALL seccompProfile: type: RuntimeDefault runAsNonRoot: true terminationGracePeriodSeconds: 1 securityContext: fsGroup: 65534 runAsGroup: 65534 runAsUser: 65534 volumes: - name: pvc ephemeral: volumeClaimTemplate: metadata: labels: type: pvc-volume spec: accessModes: [ "ReadWriteOnce" ] storageClassName: proxmox-rbd resources: requests: storage: 1Gi |
StatefulSet con almacenamiento persistente de ejemplo CSI Kubernetes + Proxmox
Os dejo el enlace y el contenido original. Yo lo he bajado y adaptado a mi entorno para ejecutarlo:
1 |
kubectl apply -f https://raw.githubusercontent.com/sergelogvinov/proxmox-csi-plugin/main/docs/deploy/test-statefulset.yaml |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
apiVersion: apps/v1 kind: StatefulSet metadata: name: test namespace: default labels: app: alpine spec: podManagementPolicy: Parallel # default is OrderedReady serviceName: test replicas: 1 template: metadata: labels: app: alpine spec: terminationGracePeriodSeconds: 3 tolerations: - effect: NoSchedule key: node-role.kubernetes.io/control-plane nodeSelector: # kubernetes.io/hostname: kube-21 # topology.kubernetes.io/zone: hvm-1 containers: - name: alpine image: alpine command: ["sleep","1d"] securityContext: seccompProfile: type: RuntimeDefault capabilities: drop: ["ALL"] volumeMounts: - name: storage mountPath: /mnt updateStrategy: type: RollingUpdate selector: matchLabels: app: alpine volumeClaimTemplates: - metadata: name: storage spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi storageClassName: proxmox-lvm |
Te ha gustado la entrada SGUENOS EN TWITTER O INVITANOS A UN CAFE?