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

Container Storage Interface (CSI) es una interfaz unificada entre Kubernetes y los sistemas de almacenamiento. Ya hemos hablado brevemente de ello. dicho, y hoy veremos más de cerca la combinación de CSI y Ceph: mostraremos cómo conectar el almacenamiento Ceph al clúster de Kubernetes.
El artículo proporciona ejemplos reales, aunque ligeramente simplificados para facilitar la percepción. No consideramos instalar ni configurar clústeres de Ceph y Kubernetes.

¿Te preguntas cómo funciona?

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

Entonces, tiene un clúster de Kubernetes a su alcance, implementado, por ejemplo, kubespray. Hay un clúster Ceph funcionando cerca; también puedes instalarlo, por ejemplo, con este un conjunto de libros de jugadas. Espero que no sea necesario mencionar que para la producción entre ellos debe existir una red con un ancho de banda de al menos 10 Gbit/s.

Si tienes todo esto, ¡vamos!

Primero, vayamos a uno de los nodos del clúster Ceph y comprobemos que todo está en orden:

ceph health
ceph -s

A continuación, crearemos inmediatamente un grupo para discos RBD:

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

Pasemos al clúster de Kubernetes. Allí, en primer lugar, instalaremos el controlador Ceph CSI para RBD. Lo instalaremos, como era de esperar, a través de Helm.
Agregamos un repositorio con un gráfico, obtenemos un conjunto de variables para el gráfico 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 necesita completar el archivo cephrbd.yml. Para hacer esto, averigüe el ID del clúster y las direcciones IP de los monitores en Ceph:

ceph fsid  # так мы узнаем clusterID
ceph mon dump  # а так увидим IP-адреса мониторов

Ingresamos los valores obtenidos en el archivo cephrbd.yml. Al mismo tiempo habilitamos la creación de políticas PSP (Pod Security Policies). Opciones en secciones complemento de nodo и 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, solo nos queda instalar el gráfico 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 funciona!
Creemos una nueva StorageClass en Kubernetes. Nuevamente, esto requiere algunos retoques con Ceph.

Creamos un nuevo usuario en Ceph y le damos derechos para escribir en el grupo. cubo:

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

Ahora veamos que la clave de acceso sigue ahí:

ceph auth get-key client.rbdkube

El comando generará algo como esto:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Agreguemos este valor a Secret en el clúster de Kubernetes, donde lo necesitemos. clave de usuario:

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-rbd-secret
  namespace: ceph-csi-rbd
stringData:
  # Значения ключей соответствуют имени пользователя и его ключу, как указано в
  # кластере Ceph. ID юзера должен иметь доступ к пулу,
  # указанному в storage class
  userID: rbdkube
  userKey: <user-key>

Y creamos nuestro secreto:

kubectl apply -f secret.yaml

A continuación, necesitamos un manifiesto StorageClass similar a este:

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

   imageFeatures: layering

   # Эти секреты должны содержать данные для авторизации
   # в ваш пул.
   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

Necesita ser completado ID de clúster, que ya hemos aprendido por el equipo ceph fsidy aplique este manifiesto al clúster de Kubernetes:

kubectl apply -f storageclass.yaml

Para comprobar cómo funcionan los clústeres juntos, creemos el siguiente PVC (reclamación de volumen persistente):

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

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

kubectl get pvc
kubectl get pv

¡Todo parece ir genial! ¿Cómo se ve esto en el lado de Ceph?
Obtenemos una lista de volúmenes en el grupo y vemos información sobre nuestro volumen:

rbd ls -p kube
rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653  # тут, конечно же, будет другой ID тома, который выдала предыдущая команда

Ahora veamos cómo funciona el cambio de tamaño de un volumen RBD.
Cambie el tamaño del volumen en el manifiesto pvc.yaml a 2Gi y aplíquelo:

kubectl apply -f pvc.yaml

Esperemos a que los cambios surtan efecto y volvamos a mirar 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 saber por qué, puede consultar a Kubernetes para obtener una descripción YAML del PVC:

kubectl get pvc rbd-pvc -o yaml

Aquí está el problema:

Mensaje: Esperando a que el usuario (re)inicie un pod para finalizar el cambio de tamaño del sistema de archivos del volumen en el nodo. tipo: FileSystemResizePending

Es decir, el disco ha crecido, pero el sistema de archivos que contiene, no.
Para hacer crecer el sistema de archivos, necesita montar el volumen. En nuestro país, el PVC/PV creado actualmente no se utiliza de ninguna manera.

Podemos crear un Pod de prueba, por ejemplo así:

---
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

La talla ha cambiado, todo está bien.

En la primera parte, trabajamos con el dispositivo de bloque RBD (que significa Rados Block Device), pero esto no se puede hacer si diferentes microservicios necesitan trabajar con este disco simultáneamente. CephFS es mucho más adecuado para trabajar con archivos que con imágenes de disco.
Usando el ejemplo de los clústeres de Ceph y Kubernetes, configuraremos CSI y otras entidades necesarias para trabajar con CephFS.

Obtengamos los valores del nuevo gráfico de Helm que necesitamos:

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

Nuevamente debe completar el archivo cephfs.yml. Como antes, los comandos Ceph ayudarán:

ceph fsid
ceph mon dump

Complete el archivo con valores como este:

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 especifican en el formato simple dirección:puerto. Para montar cephfs en un nodo, estas direcciones se pasan al módulo del kernel, que aún no sabe cómo trabajar con el protocolo de monitor v2.
Cambiamos el puerto para httpMetrics (Prometheus irá allí para monitorear las métricas) para que no entre en conflicto con nginx-proxy, que instala Kubespray. Puede que no necesites esto.

Instale el gráfico Helm 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

Vayamos al almacén de datos de Ceph para crear un usuario independiente allí. La documentación indica que el aprovisionador de CephFS requiere 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 miremos inmediatamente su clave de acceso, la necesitaremos más tarde:

ceph auth get-key client.fs

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

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-cephfs-secret
  namespace: ceph-csi-cephfs
stringData:
  # Необходимо для динамически создаваемых томов
  adminID: fs
  adminKey: <вывод предыдущей команды>

Aplicando el manifiesto:

kubectl apply -f secret.yaml

Y ahora, una StorageClass separada:

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

  # Имя файловой системы CephFS, в которой будет создан том
  fsName: cephfs

  # (необязательно) Пул Ceph, в котором будут храниться данные тома
  # pool: cephfs_data

  # (необязательно) Разделенные запятыми опции монтирования для Ceph-fuse
  # например:
  # fuseMountOptions: debug

  # (необязательно) Разделенные запятыми опции монтирования CephFS для ядра
  # См. man mount.ceph чтобы узнать список этих опций. Например:
  # kernelMountOptions: readdir_max_bytes=1048576,norbytes

  # Секреты должны содержать доступы для админа и/или юзера 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

  # (необязательно) Драйвер может использовать либо ceph-fuse (fuse), 
  # либо ceph kernelclient (kernel).
  # Если не указано, будет использоваться монтирование томов по умолчанию,
  # это определяется поиском ceph-fuse и mount.ceph
  # mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
  - debug

Completemoslo aquí ID de clúster y aplicable en Kubernetes:

kubectl apply -f storageclass.yaml

Проверка

Para comprobarlo, como en el ejemplo anterior, creemos un PVC:

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

Y comprobar la presencia de PVC/PV:

kubectl get pvc
kubectl get pv

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

Vayamos a uno de los nodos del clúster Ceph y realicemos 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, montar FS en un nodo Ceph como este sólo es adecuado para fines de capacitación, que es lo que hacemos en nuestro Cursos de barrios marginales. No creo que nadie haría esto en producción; existe un alto riesgo de borrar accidentalmente archivos importantes.

Y finalmente, veamos cómo funcionan las cosas al cambiar el tamaño de los volúmenes en el caso de CephFS. Volvamos a Kubernetes y editemos nuestro manifiesto para PVC; aumentemos el tamaño allí, por ejemplo, a 7Gi.

Apliquemos el archivo editado:

kubectl apply -f pvc.yaml

Miremos el directorio montado para ver cómo ha cambiado la cuota:

getfattr -n ceph.quota.max_bytes <каталог-с-данными>

Para que este comando funcione, es posible que necesite instalar el paquete en su sistema attr.

Los ojos tienen miedo y las manos están haciendo

Todos estos hechizos y manifiestos YAML largos parecen complicados en la superficie, pero en la práctica, los estudiantes de Slurm los dominan con bastante rapidez.
En este artículo no nos adentramos en la jungla; existe documentación oficial para ello. Si está interesado en los detalles sobre cómo configurar el almacenamiento Ceph con un clúster de Kubernetes, estos enlaces le ayudarán:

Principios generales de Kubernetes trabajando con volúmenes.
Documentación RBD
Integrando RBD y Kubernetes desde la perspectiva de Ceph
Integrando RBD y Kubernetes desde una perspectiva CSI
Documentación general de CephFS
Integrando CephFS y Kubernetes desde una perspectiva CSI

En el curso de Slurm Base de Kubernetes puedes ir un poco más allá e implementar una aplicación real en Kubernetes que utilizará CephFS como almacenamiento de archivos. A través de solicitudes GET/POST podrá transferir archivos y recibirlos de Ceph.

Y si está más interesado en el almacenamiento de datos, regístrese en nuevo curso sobre Ceph. Mientras la prueba beta esté en curso, el curso se puede obtener con descuento y usted puede influir en su contenido.

Autor del artículo: Alexander Shvalov, ingeniero en ejercicio Southbridge, Administrador certificado de Kubernetes, autor y desarrollador de cursos de Slurm.

Fuente: habr.com