Un esempio pratico di connessione dello storage basato su Ceph a un cluster Kubernetes

Container Storage Interface (CSI) è un'interfaccia unificata tra Kubernetes e i sistemi di storage. Ne abbiamo già parlato brevemente detto, e oggi vedremo più da vicino la combinazione tra CSI e Ceph: mostreremo come connettere lo storage Ceph al cluster Kubernetes.
L'articolo fornisce esempi reali, anche se leggermente semplificati per facilitare la percezione. Non consideriamo l'installazione e la configurazione di cluster Ceph e Kubernetes.

Ti stai chiedendo come funziona?

Un esempio pratico di connessione dello storage basato su Ceph a un cluster Kubernetes

Quindi hai un cluster Kubernetes a portata di mano, distribuito, ad esempio, kubespray. C'è un cluster Ceph che funziona nelle vicinanze: puoi anche installarlo, ad esempio, con questo una serie di playbook. Spero non ci sia bisogno di dire che per la produzione tra loro deve esserci una rete con una larghezza di banda di almeno 10 Gbit/s.

Se hai tutto questo, andiamo!

Per prima cosa andiamo in uno dei nodi del cluster Ceph e controlliamo che sia tutto in ordine:

ceph health
ceph -s

Successivamente, creeremo immediatamente un pool per i dischi RBD:

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

Passiamo al cluster Kubernetes. Lì, prima di tutto, installeremo il driver Ceph CSI per RBD. Installeremo, come previsto, tramite Helm.
Aggiungi un repository con un grafico, ottieni un set di variabili del grafico ceph-csi-rbd:

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

Ora devi compilare il file cephrbd.yml. Per fare ciò, scopri l'ID del cluster e gli indirizzi IP dei monitor in Ceph:

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

Inseriamo i valori ottenuti nel file cephrbd.yml. Allo stesso tempo, abilitiamo la creazione di policy PSP (Pod Security Policies). Opzioni nelle sezioni nodoplugin и provveditore già nel file, possono essere corretti come mostrato di seguito:

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

Successivamente non ci resta che installare il grafico nel cluster Kubernetes.

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

Ottimo, il driver RBD funziona!
Creiamo una nuova StorageClass in Kubernetes. Anche questo richiede un po' di manipolazione con Ceph.

Creiamo un nuovo utente in Ceph e gli diamo i diritti per scrivere nel pool cubo:

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

Ora vediamo che la chiave di accesso è ancora lì:

ceph auth get-key client.rbdkube

Il comando restituirà qualcosa del genere:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Aggiungiamo questo valore a Secret nel cluster Kubernetes, dove ne abbiamo bisogno chiave utente:

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

E creiamo il nostro segreto:

kubectl apply -f secret.yaml

Successivamente, abbiamo bisogno di un manifest StorageClass simile a questo:

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

Deve essere compilato clusterID, che abbiamo già imparato dal team cefalo fside applica questo manifest al cluster Kubernetes:

kubectl apply -f storageclass.yaml

Per verificare come funzionano insieme i cluster, creiamo il seguente PVC (Persistent Volume Claim):

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

Vediamo subito come Kubernetes ha creato il volume richiesto in Ceph:

kubectl get pvc
kubectl get pv

Tutto sembra essere fantastico! E come appare dal lato Ceph?
Otteniamo un elenco di volumi nel pool e visualizziamo le informazioni sul nostro volume:

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

Ora vediamo come funziona il ridimensionamento di un volume RBD.
Modifica la dimensione del volume nel manifest pvc.yaml in 2Gi e applicalo:

kubectl apply -f pvc.yaml

Aspettiamo che le modifiche abbiano effetto e guardiamo di nuovo la dimensione del volume.

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

kubectl get pv
kubectl get pvc

Vediamo che la dimensione del PVC non è cambiata. Per scoprire il motivo, puoi interrogare Kubernetes per una descrizione YAML del PVC:

kubectl get pvc rbd-pvc -o yaml

Ecco il problema:

messaggio: In attesa che l'utente (ri)avvii un pod per completare il ridimensionamento del volume del file system sul nodo. tipo: FileSystemResizePending

Cioè, il disco è cresciuto, ma il file system su di esso no.
Per espandere il file system, è necessario montare il volume. Nel nostro Paese il PVC/PV creato non viene attualmente utilizzato in alcun modo.

Possiamo creare un pod di test, ad esempio in questo modo:

---
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 ora diamo un'occhiata al PVC:

kubectl get pvc

La dimensione è cambiata, va tutto bene.

Nella prima parte, abbiamo lavorato con il dispositivo a blocchi RBD (sta per Rados Block Device), ma ciò non può essere fatto se diversi microservizi devono funzionare contemporaneamente con questo disco. CephFS è molto più adatto per lavorare con file piuttosto che con immagini disco.
Utilizzando l'esempio dei cluster Ceph e Kubernetes, configureremo CSI e altre entità necessarie per funzionare con CephFS.

Otteniamo i valori dal nuovo grafico Helm di cui abbiamo bisogno:

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

Anche in questo caso è necessario compilare il file cephfs.yml. Come prima, i comandi Ceph aiuteranno:

ceph fsid
ceph mon dump

Compila il file con valori come questo:

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

Tieni presente che gli indirizzi dei monitor sono specificati nella forma semplice indirizzo:porta. Per montare cephfs su un nodo, questi indirizzi vengono passati al modulo del kernel, che non sa ancora come funzionare con il protocollo monitor v2.
Modifichiamo la porta per httpMetrics (Prometheus andrà lì per monitorare le metriche) in modo che non entri in conflitto con nginx-proxy, che è installato da Kubespray. Potrebbe non essere necessario.

Installa il grafico Helm nel cluster Kubernetes:

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

Andiamo all'archivio dati Ceph per creare lì un utente separato. La documentazione afferma che il provisioner CephFS richiede diritti di accesso di amministratore del cluster. Ma creeremo un utente separato fs con diritti limitati:

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 diamo subito un’occhiata alla sua chiave d’accesso, ci servirà dopo:

ceph auth get-key client.fs

Creiamo Secret e StorageClass separati.
Niente di nuovo, lo abbiamo già visto nell’esempio di RBD:

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

Applicazione del manifesto:

kubectl apply -f secret.yaml

E ora - una StorageClass separata:

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

Compiliamolo qui clusterID e applicabile in Kubernetes:

kubectl apply -f storageclass.yaml

Проверка

Per verificare, come nell'esempio precedente, creiamo una PVC:

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

E controlla la presenza di PVC/PV:

kubectl get pvc
kubectl get pv

Se vuoi esaminare file e directory in CephFS, puoi montare questo file system da qualche parte. Ad esempio come mostrato di seguito.

Andiamo su uno dei nodi del cluster Ceph ed eseguiamo le seguenti azioni:

# Точка монтирования
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

Naturalmente, montare FS su un nodo Ceph come questo è adatto solo a scopo di formazione, che è ciò che facciamo sul nostro Corsi slurm. Non credo che qualcuno lo farebbe in produzione; il rischio di cancellare accidentalmente file importanti è elevato.

E infine, controlliamo come funzionano le cose con il ridimensionamento dei volumi nel caso di CephFS. Torniamo a Kubernetes e modifichiamo il nostro manifest per PVC: aumentiamo le dimensioni lì, ad esempio, a 7Gi.

Applichiamo il file modificato:

kubectl apply -f pvc.yaml

Diamo un'occhiata alla directory montata per vedere come è cambiata la quota:

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

Affinché questo comando funzioni, potrebbe essere necessario installare il pacchetto attra.

Gli occhi hanno paura e le mani lo fanno

Tutti questi incantesimi e i lunghi manifest YAML sembrano complicati in superficie, ma in pratica gli studenti Slurm ne imparano abbastanza rapidamente.
In questo articolo non ci siamo addentrati nella giungla: esiste la documentazione ufficiale a riguardo. Se sei interessato ai dettagli sulla configurazione dello storage Ceph con un cluster Kubernetes, questi collegamenti ti saranno utili:

Principi generali di Kubernetes che lavora con i volumi
Documentazione RBD
Integrazione di RBD e Kubernetes dal punto di vista Ceph
Integrazione di RBD e Kubernetes dal punto di vista CSI
Documentazione generale di CephFS
Integrazione di CephFS e Kubernetes dal punto di vista CSI

Sul corso Slurm Base Kubernetes puoi andare un po' oltre e distribuire una vera applicazione in Kubernetes che utilizzerà CephFS come archivio di file. Attraverso le richieste GET/POST, sarai in grado di trasferire file e riceverli da Ceph.

E se sei più interessato all'archiviazione dei dati, iscriviti nuovo corso su Cef. Mentre il beta test è in corso, il corso può essere acquistato con uno sconto e puoi influenzarne i contenuti.

Autore dell'articolo: Alexander Shvalov, ingegnere praticante Southbridge, Amministratore Kubernetes certificato, autore e sviluppatore di corsi Slurm.

Fonte: habr.com