Ejemplo práctico de conexión de almacenamiento basado en Ceph en un clúster de Kubernetes

La Interfaz de Almacenamiento de Contenedores (CSI) es una interfaz unificada que permite la interacción entre Kubernetes y los sistemas de almacenamiento de datos. Ya hemos hablado brevemente sobre ella, hemos contadoy hoy examinaremos más a fondo la conexión entre CSI y Ceph: mostraremos cómo conectar el almacenamiento Ceph al clúster de Kubernetes.
El artículo presenta ejemplos reales, aunque un poco simplificados para facilitar la comprensión. No abordamos la instalación y configuración de los clústeres Ceph y Kubernetes.

¿Te interesa saber cómo funciona?

Ejemplo práctico de conexión de almacenamiento basado en Ceph en un clúster de Kubernetes

Entonces, tienes a mano un clúster de Kubernetes desplegado, por ejemplo, kubespray.Cerca hay un clúster Ceph, que también se puede instalar, por ejemplo, con este conjunto de playbooks.Espero que no sea necesario mencionar que para la producción, entre ellos debe haber una red con un ancho de banda de al menos 10 Gbit/s.

Si tienes todo esto, ¡vamos!

Primero, accedamos a uno de los nodos del clúster Ceph y verifiquemos que todo esté en orden:

ceph health
ceph -s

A continuación, crearemos un pool para discos RBD:

ceph osd pool create kube 32
ceph osd pool application enable kube rbd

Pasamos al clúster de Kubernetes. Allí, lo primero que haremos será instalar el controlador Ceph CSI para RBD. Lo haremos, como corresponde, a través de Helm.
Agregamos el repositorio con el chart y obtenemos un conjunto de variables del chart ceph-csi-rbd:

helm repo add ceph-csi https://ceph.github.io/csi-charts
helm inspect values ceph-csi/ceph-csi-rbd > cephrbd.yml

Ahora necesitamos completar el archivo cephrbd.yml. Para hacer esto, averiguamos el ID del clúster y las direcciones IP de los monitores en Ceph:

ceph fsid  # así averiguamos el clusterID
ceph mon dump  # y así veremos las direcciones IP de los monitores

Los valores obtenidos se ingresan en el archivo cephrbd.yml. A la vez, activamos la creación de políticas PSP (Pod Security Policies). Las opciones en las secciones nodeplugin y proveedor ya están en el archivo, se pueden corregir como se muestra a continuación:

csiConfig:
  - clusterID: "bcd0d202-fba8-4352-b25d-75c89258d5ab"
    monitors:
      - "v2:172.18.8.5:3300/0,v1:172.18.8.5:6789/0"
      - "v2:172.18.8.6:3300/0,v1:172.18.8.6:6789/0"
      - "v2:172.18.8.7:3300/0,v1:172.18.8.7:6789/0"

nodeplugin:
  podSecurityPolicy:
    enabled: true

provisioner:
  podSecurityPolicy:
    enabled: true

A continuación, lo único que nos queda es instalar el chart en el clúster de Kubernetes.

helm upgrade -i ceph-csi-rbd ceph-csi/ceph-csi-rbd -f cephrbd.yml -n ceph-csi-rbd --create-namespace

¡Genial, el controlador RBD está funcionando!
Creemos una nueva StorageClass en Kubernetes. Para ello, será necesario trabajar un poco más con Ceph.

Crearemos un nuevo usuario en Ceph y le otorgaremos derechos de escritura en el pool kube.:

ceph auth get-or-create client.rbdkube mon 'profile rbd' osd 'profile rbd pool=kube'

Y ahora veamos la clave de acceso allí mismo:

ceph auth get-key client.rbdkube

El comando devolverá algo como esto:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Introduciremos este valor en un Secret en el clúster de Kubernetes, donde se necesita userKey:

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-rbd-secret
  namespace: ceph-csi-rbd
stringData:
  # Los valores de las claves correspondan al nombre de usuario y su clave, como se indica en
  # el clúster Ceph. El ID del usuario debe tener acceso al pool,
  # especificado en la clase de almacenamiento
  userID: rbdkube
  userKey:

Y creamos nuestro secreto:

kubectl apply -f secret.yaml

A continuación, necesitamos un manifiesto StorageClass similar al siguiente:

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
   name: csi-rbd-sc
provisioner: rbd.csi.ceph.com
parameters:
   clusterID: 
   pool: kube

   imageFeatures: layering

   # Estos secretos deben contener datos para la autorización
   # en su pool.
   csi.storage.k8s.io/provisioner-secret-name: csi-rbd-secret
   csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-rbd
   csi.storage.k8s.io/controller-expand-secret-name: csi-rbd-secret
   csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-rbd
   csi.storage.k8s.io/node-stage-secret-name: csi-rbd-secret
   csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-rbd

   csi.storage.k8s.io/fstype: ext4

reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
  - discard

Necesitamos llenar clusterID, que ya hemos obtenido con el comando ceph fsid, y aplicar este manifiesto en el clúster de Kubernetes:

kubectl apply -f storageclass.yaml

Para verificar el funcionamiento de los clústeres en conjunto, crearemos un PVC (Persistent Volume Claim) como el siguiente:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: rbd-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: csi-rbd-sc

Veamos de inmediato cómo Kubernetes creó el volumen solicitado en Ceph:

kubectl get pvc
kubectl get pv

¡Todo parece estar bien! ¿Y cómo se ve esto del lado de Ceph?
Obtenemos una lista de volúmenes en el pool y revisamos la información de nuestro volumen:

rbd ls -p kube
rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653  # aquí, por supuesto, habrá un ID diferente del volumen que proporcionó el comando anterior

Ahora veamos cómo funciona el cambio de tamaño del volumen RBD.
Cambiamos el tamaño del volumen en el manifiesto pvc.yaml a 2Gi y lo aplicamos:

kubectl apply -f pvc.yaml

Esperemos a que los cambios surtan efecto y miremos nuevamente el tamaño del volumen.

rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653

kubectl get pv
kubectl get pvc

Vemos que el tamaño del PVC no ha cambiado. Para averiguar la razón, podemos solicitar a Kubernetes la descripción del PVC en formato YAML:

kubectl get pvc rbd-pvc -o yaml

Y aquí está el problema:

message: Waiting for user to (re-)start a pod to finish file system resize of volume on node. type: FileSystemResizePending

Es decir, el disco ha aumentado, pero el sistema de archivos en él no.
Para aumentar el sistema de archivos, es necesario montar el volumen. El PVC/PV que hemos creado no se está utilizando en este momento.

Podemos crear un Pod de prueba, por ejemplo, de esta manera:

---
apiversion: v1
kind: Pod
metadata:
  name: csi-rbd-demo-pod
spec:
  containers:
    - name: web-server
      image: nginx:1.17.6
      volumeMounts:
        - name: mypvc
          mountPath: /data
  volumes:
    - name: mypvc
      persistentVolumeClaim:
        claimName: rbd-pvc
        readOnly: false

Y ahora veamos el PVC:

kubectl get pvc

El tamaño ha cambiado, todo está bien.

En la primera parte trabajamos con el dispositivo de bloque RBD (que se traduce como Rados Block Device), pero esto no se puede hacer si se requiere que diferentes microservicios trabajen con este disco al mismo tiempo. Para trabajar con archivos, en lugar de con la imagen del disco, CephFS es mucho más adecuado.
Usaremos los clústeres Ceph y Kubernetes para configurar CSI y las otras entidades necesarias para trabajar con CephFS.

Obtendremos los valores del nuevo Helm-chart que necesitamos:

helm inspect values ceph-csi/ceph-csi-cephfs > cephfs.yml

De nuevo, necesitamos completar el archivo cephfs.yml. Como antes, las órdenes de Ceph serán útiles:

ceph fsid
ceph mon dump

Completamos el archivo con los valores de la siguiente manera:

csiConfig:
  - clusterID: "bcd0d202-fba8-4352-b25d-75c89258d5ab"
    monitors:
      - "172.18.8.5:6789"
      - "172.18.8.6:6789"
      - "172.18.8.7:6789"

nodeplugin:
  httpMetrics:
    enabled: true
    containerPort: 8091
  podSecurityPolicy:
    enabled: true

provisioner:
  replicaCount: 1
  podSecurityPolicy:
    enabled: true

Tenga en cuenta que las direcciones de los monitores se indican en la forma simple address:port. Para montar cephfs en el nodo, estas direcciones se pasan al módulo del núcleo, que aún no puede trabajar con el protocolo de monitores v2.
Cambiamos el puerto para httpMetrics (donde Prometheus irá a recoger métricas para la supervisión) para que no entre en conflicto con nginx-proxy, que se instala con Kubespray. Puede que esto no sea necesario para usted.

Instalamos el Helm-chart en el clúster de Kubernetes:

helm upgrade -i ceph-csi-cephfs ceph-csi/ceph-csi-cephfs -f cephfs.yml -n ceph-csi-cephfs --create-namespace

Vamos al almacenamiento de datos Ceph para crear un usuario separado. La documentación indica que el provisionador de CephFS necesita derechos de acceso de administrador del clúster. Pero crearemos un usuario separado fs con derechos limitados:

ceph auth get-or-create client.fs mon 'allow r' mgr 'allow rw' mds 'allow rws' osd 'allow rw pool=cephfs_data, allow rw pool=cephfs_metadata'

Y de inmediato veremos su clave de acceso, que nos será útil más adelante:

ceph auth get-key client.fs

Crearemos un Secret y un StorageClass separados.
Nada nuevo, ya lo hemos visto en el ejemplo de RBD:

---
apiversion: v1
kind: Secret
metadata:
  name: csi-cephfs-secret
  namespace: ceph-csi-cephfs
stringData:
  # Necesario para volúmenes creados dinámicamente
  adminID: fs
  adminKey:

Aplicamos el manifiesto:

kubectl apply -f secret.yaml

Y ahora – un StorageClass separado:

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: csi-cephfs-sc
provisioner: cephfs.csi.ceph.com
parameters:
  clusterID: 

  # Nombre del sistema de archivos CephFS donde se creará el volumen
  fsName: cephfs

  # (opcional) Pool Ceph donde se almacenarán los datos del volumen
  # pool: cephfs_data

  # (opcional) Opciones de montaje separadas por comas para Ceph-fuse
  # por ejemplo:
  # fuseMountOptions: debug

  # (opcional) Opciones de montaje de CephFS para el núcleo, separadas por comas
  # Consulte man mount.ceph para obtener una lista de estas opciones. Por ejemplo:
  # kernelMountOptions: readdir_max_bytes=1048576,norbytes

  # Los secretos deben contener accesos para el administrador y/o el usuario de Ceph.
  csi.storage.k8s.io/provisioner-secret-name: csi-cephfs-secret
  csi.storage.k8s.io/provisioner-secret-namespace: ceph-csi-cephfs
  csi.storage.k8s.io/controller-expand-secret-name: csi-cephfs-secret
  csi.storage.k8s.io/controller-expand-secret-namespace: ceph-csi-cephfs
  csi.storage.k8s.io/node-stage-secret-name: csi-cephfs-secret
  csi.storage.k8s.io/node-stage-secret-namespace: ceph-csi-cephfs

  # (opcional) El controlador puede usar ceph-fuse (fuse) 
  # o ceph kernelclient (kernel).
  # Si no se especifica, se utilizará el montaje de volúmenes por defecto,
  # lo cual se determina buscando ceph-fuse y mount.ceph
  # mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
  - debug

Llenemos esto aquí clusterID y aplicamos en Kubernetes:

kubectl apply -f storageclass.yaml

Verificación

Para verificar, como en el ejemplo anterior, crearemos un PVC:

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: csi-cephfs-pvc
spec:
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
  storageClassName: csi-cephfs-sc

Y verificamos la existencia de PVC/PV:

kubectl get pvc
kubectl get pv

Si deseas ver los archivos y directorios en CephFS, puedes montar este sistema de archivos en algún lugar. Por ejemplo, como se muestra a continuación.

Viajamos a uno de los nodos del clúster Ceph y realizamos las siguientes acciones:

# Точка монтирования
mkdir -p /mnt/cephfs

# Создаём файл с ключом администратора
ceph auth get-key client.admin >/etc/ceph/secret.key

# Добавляем запись в /etc/fstab
# !! Изменяем ip адрес на адрес нашего узла
echo "172.18.8.6:6789:/ /mnt/cephfs ceph name=admin,secretfile=/etc/ceph/secret.key,noatime,_netdev    0       2" >> /etc/fstab

mount /mnt/cephfs

Por supuesto, este tipo de montaje de FS en un nodo Ceph es adecuado exclusivamente para fines de aprendizaje, que es lo que estamos haciendo en nuestros cursos de Slurm. No creo que alguien haga esto en producción, ya que existe un alto riesgo de sobrescribir archivos importantes.

Y para terminar, comprobemos cómo se maneja el cambio de tamaño del volumen en el caso de CephFS. Volvemos a Kubernetes y editamos nuestro manifiesto para el PVC, aumentamos su tamaño, por ejemplo, a 7Gi.

Aplicamos el archivo editado:

kubectl apply -f pvc.yaml

Veamos en el directorio montado cómo ha cambiado la cuota:

getfattr -n ceph.quota.max_bytes

Para ejecutar este comando, es posible que necesites instalar el paquete attr.

Los ojos tienen miedo, pero las manos lo hacen

A simple glance at all these spells and lengthy YAML manifests might seem daunting, but in practice, Slurm students manage to grasp them quite quickly.
In this article, we haven't delved deep — for that, there is the official documentation. If you're interested in the details of configuring Ceph storage in conjunction with a Kubernetes cluster, these links will help:

General principles of Kubernetes working with volumes
RBD documentation
Integrating RBD and Kubernetes from the perspective of Ceph
Integrating RBD and Kubernetes from the perspective of CSI
General documentation on CephFS
Integrating CephFS and Kubernetes from the perspective of CSI

In the Slurm course 8–10 de febrero de 2021. Y you can go a step further and deploy a real application in Kubernetes that will use CephFS as its storage for files. Through GET/POST requests, you will be able to transfer files to and retrieve them from Ceph.

And if you are more interested in data storage, then sign up for the new Ceph course. While the beta testing is ongoing, the course can be obtained at a discount and you can influence its content.

Author of the article: Alexander Shvalov, practicing engineer Southbridge, Certified Kubernetes Administrator, author and developer of Slurm courses.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster