Esempio pratico di connessione di uno storage basato su Ceph in un cluster Kubernetes

L'interfaccia di archiviazione dei contenitori (CSI) è un'interfaccia unificata tra Kubernetes e i sistemi di archiviazione dei dati. In breve, ne abbiamo già parlato parlato, e oggi esamineremo più in dettaglio l'integrazione tra CSI e Ceph: mostreremo come collegare lo storage Ceph a un cluster Kubernetes.
Nell'articolo sono forniti esempi reali, anche se leggermente semplificati per una migliore comprensione. Non esamineremo l'installazione e la configurazione dei cluster Ceph e Kubernetes.

Sei curioso di sapere come funziona?

Esempio pratico di connessione di uno storage basato su Ceph in un cluster Kubernetes

Quindi, hai a disposizione un cluster Kubernetes, ad esempio kubespray. Accanto a esso c'è un cluster Ceph, che puoi anche installare, ad esempio, con questo insieme di playbook. Spero non sia necessario menzionare che per l'ambiente di produzione tra di loro deve esserci una rete con una capacità di almeno 10 Gbit/s.

Se hai tutto questo, andiamo!

Innanzitutto, accediamo a uno dei nodi del cluster Ceph e verifichiamo che tutto sia a posto:

ceph health
ceph -s

Poi creeremo immediatamente un pool per 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. Lo installeremo, come da prassi, tramite Helm.
Aggiungiamo il repository con il chart e otteniamo un insieme di variabili 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

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

ceph fsid  # così scopriamo il clusterID
ceph mon dump  # in questo modo vediamo gli indirizzi IP dei monitor

Inseriamo i valori ottenuti nel file cephrbd.yml. Nel frattempo, attiviamo la creazione delle politiche PSP (Pod Security Policies). Le opzioni nelle sezioni nodeplugin e provisioner sono già presenti nel file e possono essere corrette 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

Dopo, tutto ciò che ci resta è installare il chart 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 un nuovo StorageClass in Kubernetes. Per fare ciò, dovremo lavorare un po' di nuovo con Ceph.

Creiamo un nuovo utente in Ceph e concediamogli diritti di scrittura nel pool kube:

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

Ora controlliamo la chiave di accesso là dove di consueto:

ceph auth get-key client.rbdkube

Il comando restituirà qualcosa di simile:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Inseriremo questo valore in un Secret nel cluster Kubernetes, lì dove è necessario userKey:

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-rbd-secret
  namespace: ceph-csi-rbd
stringData:
  # I valori delle chiavi corrispondono al nome utente e alla sua chiave, come indicato nel
  # cluster Ceph. L'ID utente deve avere accesso al pool,
  # indicato nella storage class
  userID: rbdkube
  userKey:

E creiamo il nostro segreto:

kubectl apply -f secret.yaml

Ora abbiamo bisogno di un manifesto StorageClass simile a questo:

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

   imageFeatures: layering

   # Questi segreti devono contenere dati per l'autenticazione
   # nel tuo 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

Devi compilare clusterID, di cui abbiamo già parlato con il comando ceph fsid, e applicare questo manifesto nel cluster Kubernetes:

kubectl apply -f storageclass.yaml

Per verificare il funzionamento dei cluster collegati, creiamo un PVC (Persistent Volume Claim) come questo:

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

Diamo subito un'occhiata a come Kubernetes ha creato il volume richiesto in Ceph:

kubectl get pvc
kubectl get pv

Sembra tutto a posto! E come appare dal lato di Ceph?
Otteniamo un elenco di volumi nel pool e controlliamo le informazioni sul nostro volume:

rbd ls -p kube
rbd -p kube info csi-vol-eb3d257d-8c6c-11ea-bff5-6235e7640653  # qui, ovviamente, ci sarà un altro ID volume fornito dal comando precedente

Ora vediamo come funziona l'ampliamento del volume RBD.
Modifichiamo la dimensione del volume nel manifesto pvc.yaml a 2Gi e lo applichiamo:

kubectl apply -f pvc.yaml

Aspettiamo che le modifiche abbiano effetto e diamo un'altra occhiata alla 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, possiamo chiedere a Kubernetes di descrivere il PVC in formato YAML:

kubectl get pvc rbd-pvc -o yaml

Ecco il problema:

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

Quindi il disco è stato ampliato, ma il file system su di esso no.
Per aumentare il file system, occorre montare il volume. Al momento, il PVC/PV creato non è utilizzato.

Possiamo creare un Pod di prova, 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, tutto va bene.

Nella prima parte abbiamo lavorato con un dispositivo di blocco RBD (che si traduce come Rados Block Device), ma non è possibile farlo se è necessaria la collaborazione simultanea di diversi microservizi su questo disco. Per lavorare con i file, e non con un'immagine del disco, CephFS è molto più adatto.
Prendiamo degli esempi dei cluster Ceph e Kubernetes per configurare CSI e le altre entità necessarie per lavorare con CephFS.

Otteniamo i valori dal nuovo Helm chart che ci interessa:

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

È di nuovo necessario riempire il file cephfs.yml. Come prima, ci aiuteranno i comandi Ceph:

ceph fsid
ceph mon dump

Compiliamo il file con i valori in questo modo:

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

Si prega di notare che gli indirizzi dei monitor sono indicati nella forma semplice address:port. Per montare cephfs su un nodo, questi indirizzi vengono passati al modulo del kernel, che non è ancora in grado di lavorare con il protocollo dei monitor v2.
Modifichiamo la porta per httpMetrics (dove Prometheus andrà a cercare le metriche per il monitoraggio) in modo che non confligga con nginx-proxy, che è installato da Kubespray. Potrebbe non essere necessario per voi.

Installiamo l'Helm chart nel cluster Kubernetes:

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

Passiamo al sistema di archiviazione Ceph per creare un utente separato. La documentazione indica che il provisioner CephFS necessita di diritti di accesso come amministratore del cluster. Ma noi 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 subito dopo guardiamo la sua chiave di accesso, che ci servirà in seguito:

ceph auth get-key client.fs

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

---
apiVersion: v1
kind: Secret
metadata:
  name: csi-cephfs-secret
  namespace: ceph-csi-cephfs
stringData:
  # Necessario per i volumi creati dinamicamente
  adminID: fs
  adminKey:

Applichiamo il manifesto:

kubectl apply -f secret.yaml

E ora – un StorageClass separato:

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

  # Nome del file system CephFS in cui verrà creato il volume
  fsName: cephfs

  # (opzionale) Pool Ceph in cui saranno memorizzati i dati del volume
  # pool: cephfs_data

  # (opzionale) Opzioni di montaggio separate da virgola per Ceph-fuse
  # ad esempio:
  # fuseMountOptions: debug

  # (opzionale) Opzioni di montaggio CephFS per il kernel separate da virgola
  # Vedi il man mount.ceph per un elenco di queste opzioni. Ad esempio:
  # kernelMountOptions: readdir_max_bytes=1048576,norbytes

  # I segreti devono contenere accessi per l'amministratore e/o l'utente 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

  # (opzionale) Il driver può utilizzare o ceph-fuse (fuse), 
  # o ceph kernelclient (kernel).
  # Se non specificato, verrà utilizzato il montaggio dei volumi predefinito,
  # questo è determinato dalla ricerca di ceph-fuse e mount.ceph
  # mounter: kernel
reclaimPolicy: Delete
allowVolumeExpansion: true
mountOptions:
  - debug

Compiliamo qui clusterID e applichiamo in Kubernetes:

kubectl apply -f storageclass.yaml

Verifica

Per verificare, come nel caso precedente, creiamo un PVC:

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

E controlliamo la presenza di PVC/PV:

kubectl get pvc
kubectl get pv

Se vuoi vedere i file e le 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 e facciamo queste operazioni:

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

Certo, questo tipo di montaggio FS su un nodo Ceph è adatto esclusivamente per scopi didattici, come stiamo facendo nei nostri corsi Slurm. Non penso che qualcuno lo farebbe in produzione, c'è un alto rischio di sovrascrivere accidentalmente file importanti.

E infine, verifichiamo come si presenta la situazione con la modifica delle dimensioni del volume in CephFS. Torniamo in Kubernetes e modifichiamo il nostro manifesto per il PVC — aumentando la dimensione, ad esempio, a 7Gi.

Applichiamo il file modificato:

kubectl apply -f pvc.yaml

Controlliamo nella directory montata come è cambiato il limite:

getfattr -n ceph.quota.max_bytes

Per eseguire questo comando, potrebbe essere necessario installare il pacchetto attr.

Gli occhi hanno paura, ma le mani lavorano

A prima vista, tutti questi incantesimi e lunghi manifesti YAML possono sembrare complicati, ma nella pratica gli studenti di Slurm riescono a comprenderli abbastanza rapidamente.
In questo articolo non ci siamo addentrati nei dettagli — per questo c'è la documentazione ufficiale. Se sei interessato ai dettagli per configurare lo storage Ceph insieme al cluster Kubernetes, possono aiutarti questi link:

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

Nel corso di Slurm Base Kubernetes puoi andare ancora oltre e distribuire in Kubernetes un'applicazione reale che utilizzerà CephFS come storage per i file. Attraverso richieste GET/POST potrai inviare e ricevere file da Ceph.

E se ti interessa di più lo storage dei dati, iscriviti al nuovo corso su Ceph. Finché è in fase di beta testing, il corso è disponibile a un prezzo scontato e puoi influenzare il suo contenuto.

Autore dell'articolo: Aleksandr Shvalov, ingegnere praticante Southbridge, Certified Kubernetes Administrator, autore e sviluppatore dei corsi Slurm.

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster