Un exemplo práctico de conexión de almacenamento baseado en Ceph a un clúster de Kubernetes

Container Storage Interface (CSI) é unha interface unificada entre Kubernetes e os sistemas de almacenamento. Xa o falamos brevemente contou, e hoxe analizaremos a combinación de CSI e Ceph: mostraremos como conectar o almacenamento Ceph ao clúster de Kubernetes.
O artigo ofrece exemplos reais, aínda que lixeiramente simplificados para facilitar a percepción. Non consideramos instalar e configurar clústeres Ceph e Kubernetes.

Estás a preguntar como funciona?

Un exemplo práctico de conexión de almacenamento baseado en Ceph a un clúster de Kubernetes

Polo tanto, tes un clúster de Kubernetes ao teu alcance, implantado, por exemplo, kubespray. Hai un clúster Ceph traballando preto; tamén podes instalalo, por exemplo, con isto un conxunto de libros de xogo. Espero que non faga falta mencionar que para a produción entre eles debe haber unha rede cun ancho de banda de polo menos 10 Gbit/s.

Se tes todo isto, imos!

Primeiro, imos a un dos nodos do clúster Ceph e comprobemos que todo está en orde:

ceph health
ceph -s

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

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

Pasemos ao clúster de Kubernetes. Alí, en primeiro lugar, instalaremos o controlador Ceph CSI para RBD. Instalaremos, como era de esperar, a través de Helm.
Engadimos un repositorio cun gráfico, obtemos un conxunto de variables para o 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

Agora cómpre encher o ficheiro cephrbd.yml. Para iso, descubra o ID do clúster e os enderezos IP dos monitores en Ceph:

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

Introducimos os valores obtidos no ficheiro cephrbd.yml. Ao mesmo tempo, habilitamos a creación de políticas de PSP (Pod Security Policies). Opcións en seccións nodeplugin и provedor xa no ficheiro, pódense corrixir como se mostra 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, só nos queda instalar o gráfico no clúster de Kubernetes.

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

Xenial, o controlador RBD funciona!
Imos crear unha nova StorageClass en Kubernetes. Isto require de novo un pouco de retoque con Ceph.

Creamos un novo usuario en Ceph e dámoslle dereitos para escribir no grupo cubo:

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

Agora vexamos que a clave de acceso aínda está aí:

ceph auth get-key client.rbdkube

O comando sairá algo así:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Agreguemos este valor a Secret no clúster de Kubernetes, onde o 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>

E creamos o noso segredo:

kubectl apply -f secret.yaml

A continuación, necesitamos un manifesto de StorageClass algo así:

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

É necesario cubrir clusterID, que xa aprendemos polo equipo ceph fsid, e aplique este manifesto ao clúster de Kubernetes:

kubectl apply -f storageclass.yaml

Para comprobar como funcionan os clústeres xuntos, creemos o seguinte PVC (reclamación de volume persistente):

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

Vexamos inmediatamente como Kubernetes creou o volume solicitado en Ceph:

kubectl get pvc
kubectl get pv

Todo parece ser xenial! Como se ve isto no lado de Ceph?
Temos unha lista de volumes na piscina e vemos información sobre o noso volume:

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

Agora vexamos como funciona o redimensionamento dun volume RBD.
Cambia o tamaño do volume no manifesto pvc.yaml a 2Gi e aplícao:

kubectl apply -f pvc.yaml

Agardemos a que os cambios teñan efecto e vexamos de novo o tamaño do volume.

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

kubectl get pv
kubectl get pvc

Vemos que o tamaño do PVC non cambiou. Para saber por que, podes consultar a Kubernetes unha descrición YAML do PVC:

kubectl get pvc rbd-pvc -o yaml

Aquí está o problema:

mensaxe: agardando a que o usuario (re)inicie un pod para rematar o redimensionamento do volume do sistema de ficheiros no nodo. tipo: FileSystemResizePending

É dicir, o disco creceu, pero o sistema de ficheiros non.
Para facer crecer o sistema de ficheiros, cómpre montar o volume. No noso país, o PVC/PV creado non se utiliza actualmente de ningún xeito.

Podemos crear un Pod de proba, por exemplo como este:

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

E agora vexamos o PVC:

kubectl get pvc

O tamaño cambiou, todo está ben.

Na primeira parte, traballamos co dispositivo de bloque RBD (son as siglas de Rados Block Device), pero isto non se pode facer se diferentes microservizos precisan traballar con este disco simultaneamente. CephFS é moito máis axeitado para traballar con ficheiros que con imaxes de disco.
Usando o exemplo dos clústeres Ceph e Kubernetes, configuraremos CSI e outras entidades necesarias para traballar con CephFS.

Imos obter os valores do novo gráfico Helm que necesitamos:

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

De novo cómpre encher o ficheiro cephfs.yml. Como antes, os comandos Ceph axudarán:

ceph fsid
ceph mon dump

Encha o ficheiro 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

Teña en conta que os enderezos dos monitores especifícanse no formulario sinxelo enderezo:porto. Para montar cephfs nun nodo, estes enderezos transfírense ao módulo do núcleo, que aínda non sabe como traballar co protocolo de monitor v2.
Cambiamos o porto para httpMetrics (Prometheus irá alí para supervisar as métricas) para que non entre en conflito con nginx-proxy, que está instalado por Kubespray. Quizais non necesites isto.

Instala o gráfico Helm no clúster de Kubernetes:

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

Imos ao almacén de datos Ceph para crear alí un usuario separado. A documentación indica que o provedor CephFS require dereitos de acceso de administrador do clúster. Pero imos crear un usuario separado fs con dereitos 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'

E vexamos inmediatamente a súa clave de acceso, necesitarémola máis tarde:

ceph auth get-key client.fs

Imos crear Secret e StorageClass separados.
Nada novo, xa o vimos no exemplo de RBD:

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

Aplicando o manifesto:

kubectl apply -f secret.yaml

E agora, unha 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

Imos enchelo aquí clusterID e aplicable en Kubernetes:

kubectl apply -f storageclass.yaml

Проверка

Para comprobar, como no exemplo anterior, creemos un PVC:

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

E comprobar a presenza de PVC/PV:

kubectl get pvc
kubectl get pv

Se queres ver ficheiros e directorios en CephFS, podes montar este sistema de ficheiros nalgún lugar. Por exemplo, como se mostra a continuación.

Imos a un dos nodos do clúster Ceph e realicemos as seguintes accións:

# Точка монтирования
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 suposto, montar FS nun nodo Ceph como este só é adecuado para fins de adestramento, que é o que facemos no noso Cursos de Slurm. Non creo que ninguén faga isto na produción; hai un alto risco de borrar accidentalmente ficheiros importantes.

E, finalmente, imos comprobar como funcionan as cousas co redimensionamento dos volumes no caso de CephFS. Volvamos a Kubernetes e editemos o noso manifesto para PVC: aumenta o tamaño alí, por exemplo, a 7Gi.

Apliquemos o ficheiro editado:

kubectl apply -f pvc.yaml

Vexamos o directorio montado para ver como cambiou a cota:

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

Para que este comando funcione, quizais necesite instalar o paquete no seu sistema atr.

Os ollos teñen medo, pero as mans

Todos estes feitizos e longos manifestos de YAML parecen complicados na superficie, pero na práctica, os estudantes de Slurm achéganse con bastante rapidez.
Neste artigo non entramos profundamente na selva - hai documentación oficial para iso. Se estás interesado nos detalles da configuración do almacenamento Ceph cun clúster de Kubernetes, estas ligazóns axudarán:

Principios xerais do traballo de Kubernetes con volumes
Documentación RBD
Integrando RBD e Kubernetes desde a perspectiva de Ceph
Integrando RBD e Kubernetes desde unha perspectiva CSI
Documentación xeral do CephFS
Integrando CephFS e Kubernetes desde unha perspectiva CSI

No curso de Slurm Base Kubernetes pode ir un pouco máis aló e implantar unha aplicación real en Kubernetes que utilizará CephFS como almacenamento de ficheiros. A través das solicitudes GET/POST poderás transferir ficheiros e recibilos de Ceph.

E se estás máis interesado no almacenamento de datos, rexístrate novo curso sobre Ceph. Mentres a proba beta está en curso, o curso pódese obter cun desconto e podes influír no seu contido.

Autor do artigo: Alexander Shvalov, enxeñeiro en exercicio Southbridge, Administrador certificado de Kubernetes, autor e desenvolvedor de cursos Slurm.

Fonte: www.habr.com