Ett praktiskt exempel på att ansluta Ceph-baserad lagring till ett Kubernetes-kluster

Container Storage Interface (CSI) är ett enhetligt gränssnitt mellan Kubernetes och lagringssystem. Vi har redan pratat om det kort sa, och idag ska vi titta närmare på kombinationen av CSI och Ceph: vi ska visa hur anslut Ceph-lagring till Kubernetes-klustret.
Artikeln ger verkliga, om än något förenklade exempel för att underlätta uppfattningen. Vi överväger inte att installera och konfigurera Ceph- och Kubernetes-kluster.

Undrar du hur det fungerar?

Ett praktiskt exempel på att ansluta Ceph-baserad lagring till ett Kubernetes-kluster

Så du har ett Kubernetes-kluster till hands, utplacerat, till exempel, kubespray. Det finns ett Ceph-kluster som arbetar i närheten - du kan även installera det till exempel med detta en uppsättning spelböcker. Jag hoppas att det inte finns något behov av att nämna att för produktion mellan dem måste det finnas ett nätverk med en bandbredd på minst 10 Gbit/s.

Om du har allt detta, låt oss gå!

Låt oss först gå till en av Ceph-klusternoderna och kontrollera att allt är i sin ordning:

ceph health
ceph -s

Därefter skapar vi omedelbart en pool för RBD-diskar:

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

Låt oss gå vidare till Kubernetes-klustret. Där kommer vi först och främst att installera Ceph CSI-drivrutinen för RBD. Vi kommer att installera, som förväntat, genom Helm.
Vi lägger till ett arkiv med ett diagram, vi får en uppsättning variabler för ceph-csi-rbd-diagrammet:

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

Nu måste du fylla i filen cephrbd.yml. För att göra detta, ta reda på kluster-ID och IP-adresser för monitorer i Ceph:

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

Vi anger de erhållna värdena i filen cephrbd.yml. Samtidigt möjliggör vi skapandet av PSP-policyer (Pod Security Policies). Alternativ i avsnitt nodeplugin и proviantör redan i filen kan de korrigeras enligt nedan:

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

Sedan är allt som återstår för oss att installera diagrammet i Kubernetes-klustret.

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

Bra, RBD-drivrutinen fungerar!
Låt oss skapa en ny StorageClass i Kubernetes. Detta kräver återigen lite mixtrande med Ceph.

Vi skapar en ny användare i Ceph och ger honom rättigheter att skriva till poolen Kub:

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

Låt oss nu se att åtkomstnyckeln fortfarande finns där:

ceph auth get-key client.rbdkube

Kommandot kommer att mata ut något så här:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Låt oss lägga till detta värde till Secret i Kubernetes-klustret – där vi behöver det användarnyckel:

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

Och vi skapar vår hemlighet:

kubectl apply -f secret.yaml

Därefter behöver vi ett StorageClass-manifest ungefär så här:

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

Behöver fyllas i kluster-ID, som vi redan har lärt oss av laget ceph fsid, och tillämpa detta manifest på Kubernetes-klustret:

kubectl apply -f storageclass.yaml

För att kontrollera hur klustren fungerar tillsammans, låt oss skapa följande PVC (Persistent Volume Claim):

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

Låt oss omedelbart se hur Kubernetes skapade den begärda volymen i Ceph:

kubectl get pvc
kubectl get pv

Allt verkar vara jättebra! Hur ser det här ut på Ceph-sidan?
Vi får en lista över volymer i poolen och ser information om vår volym:

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

Låt oss nu se hur storleksändring av en RBD-volym fungerar.
Ändra volymstorleken i pvc.yaml-manifestet till 2Gi och tillämpa den:

kubectl apply -f pvc.yaml

Låt oss vänta tills ändringarna träder i kraft och titta på volymstorleken igen.

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

kubectl get pv
kubectl get pvc

Vi ser att storleken på PVC inte har förändrats. För att ta reda på varför kan du fråga Kubernetes om en YAML-beskrivning av PVC:

kubectl get pvc rbd-pvc -o yaml

Här är problemet:

meddelande: Väntar på att användaren ska (om)starta en pod för att avsluta filsystemets storlek på volymen på noden. typ: FileSystemResizePending

Det vill säga att skivan har vuxit, men filsystemet på den har inte växt.
För att utöka filsystemet måste du montera volymen. I vårt land används den skapade PVC/PV för närvarande inte på något sätt.

Vi kan skapa en testpod, till exempel så här:

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

Och låt oss nu titta på PVC:

kubectl get pvc

Storleken har ändrats, allt är bra.

I den första delen arbetade vi med RBD-blockenheten (den står för Rados Block Device), men detta kan inte göras om olika mikrotjänster behöver arbeta med denna disk samtidigt. CephFS är mycket bättre lämpad för att arbeta med filer snarare än diskbilder.
Med exemplet med Ceph och Kubernetes-kluster kommer vi att konfigurera CSI och andra nödvändiga enheter för att arbeta med CephFS.

Låt oss hämta värdena från det nya Helm-diagrammet vi behöver:

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

Återigen måste du fylla i filen cephfs.yml. Som tidigare kommer Ceph-kommandon att hjälpa:

ceph fsid
ceph mon dump

Fyll i filen med värden så här:

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

Observera att monitoradresser anges i det enkla formuläret adress:port. För att montera cephfs på en nod skickas dessa adresser till kärnmodulen, som ännu inte vet hur man arbetar med v2-monitorprotokollet.
Vi ändrar porten för httpMetrics (Prometheus kommer att gå dit för att övervaka mätvärden) så att den inte kommer i konflikt med nginx-proxy, som installeras av Kubespray. Du kanske inte behöver detta.

Installera Helm-diagrammet i Kubernetes-klustret:

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

Låt oss gå till Cephs datalager för att skapa en separat användare där. Dokumentationen anger att CephFS-provisioneraren kräver åtkomsträttigheter för klusteradministratörer. Men vi kommer att skapa en separat användare fs med begränsade rättigheter:

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'

Och låt oss omedelbart titta på hans åtkomstnyckel, vi kommer att behöva den senare:

ceph auth get-key client.fs

Låt oss skapa separata Secret och StorageClass.
Inget nytt, vi har redan sett detta i exemplet med RBD:

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

Tillämpa manifestet:

kubectl apply -f secret.yaml

Och nu - en separat StorageClass:

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

Låt oss fylla i det här kluster-ID och gäller i Kubernetes:

kubectl apply -f storageclass.yaml

Проверка

För att kontrollera, som i föregående exempel, låt oss skapa en PVC:

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

Och kontrollera närvaron av PVC/PV:

kubectl get pvc
kubectl get pv

Om du vill titta på filer och kataloger i CephFS kan du montera detta filsystem någonstans. Till exempel som visas nedan.

Låt oss gå till en av Ceph-klusternoderna och utföra följande åtgärder:

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

Att montera FS på en sådan här Ceph-nod är naturligtvis endast lämpligt för träningsändamål, vilket är vad vi gör på vår Slurmkurser. Jag tror inte att någon skulle göra detta i produktionen; det finns en stor risk att av misstag radera viktiga filer.

Och slutligen, låt oss kolla hur saker och ting fungerar med att ändra storlek på volymer i fallet med CephFS. Låt oss återvända till Kubernetes och redigera vårt manifest för PVC – öka storleken där, till exempel, till 7Gi.

Låt oss tillämpa den redigerade filen:

kubectl apply -f pvc.yaml

Låt oss titta på den monterade katalogen för att se hur kvoten har förändrats:

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

För att det här kommandot ska fungera kan du behöva installera paketet på ditt system attr.

Ögonen är rädda, men händerna gör det

Alla dessa trollformler och långa YAML-manifest verkar komplicerade på ytan, men i praktiken får Slurm-eleverna grepp om dem ganska snabbt.
I den här artikeln gick vi inte djupt in i djungeln - det finns officiell dokumentation för det. Om du är intresserad av detaljerna för att ställa in Ceph-lagring med ett Kubernetes-kluster, hjälper dessa länkar:

Allmänna principer för Kubernetes som arbetar med volymer
RBD-dokumentation
Integrering av RBD och Kubernetes ur ett Ceph-perspektiv
Integrering av RBD och Kubernetes ur ett CSI-perspektiv
Allmän CephFS-dokumentation
Integrering av CephFS och Kubernetes ur ett CSI-perspektiv

På Slurmbanan Kubernetes bas du kan gå lite längre och distribuera en riktig applikation i Kubernetes som kommer att använda CephFS som fillagring. Genom GET/POST-förfrågningar kommer du att kunna överföra filer till och ta emot dem från Ceph.

Och om du är mer intresserad av datalagring, registrera dig för ny kurs om Ceph. Medan betatestet pågår kan kursen erhållas med rabatt och du kan påverka dess innehåll.

Författare till artikeln: Alexander Shvalov, praktiserande ingenjör Southbridge, Certifierad Kubernetes-administratör, författare och utvecklare av Slurm-kurser.

Källa: will.com