Praktyczny przykład połączenia pamięci masowej opartej na Ceph z klastrem Kubernetes

Container Storage Interface (CSI) to ujednolicony interfejs pomiędzy Kubernetesem a systemami pamięci masowej. Pokrótce już o tym rozmawialiśmy powiedział, a dzisiaj przyjrzymy się bliżej połączeniu CSI i Ceph: pokażemy, jak to zrobić podłącz pamięć Ceph do klastra Kubernetes.
W artykule przedstawiono rzeczywiste, choć nieco uproszczone przykłady dla ułatwienia percepcji. Nie rozważamy instalacji i konfiguracji klastrów Ceph i Kubernetes.

Zastanawiasz się jak to działa?

Praktyczny przykład połączenia pamięci masowej opartej na Ceph z klastrem Kubernetes

Masz więc klaster Kubernetes na wyciągnięcie ręki, wdrożony np. Kubespray. W pobliżu działa klaster Ceph - możesz go także zainstalować np. za pomocą tego zestaw książeczek zabaw. Mam nadzieję, że nie trzeba wspominać, że do produkcji pomiędzy nimi musi istnieć sieć o przepustowości co najmniej 10 Gbit/s.

Jeśli masz to wszystko, chodźmy!

Na początek przejdźmy do jednego z węzłów klastra Ceph i sprawdźmy, czy wszystko jest w porządku:

ceph health
ceph -s

Następnie od razu utworzymy pulę dla dysków RBD:

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

Przejdźmy do klastra Kubernetes. Tam w pierwszej kolejności zainstalujemy sterownik Ceph CSI dla RBD. Zainstalujemy, zgodnie z oczekiwaniami, za pośrednictwem Helma.
Dodajemy repozytorium z wykresem, otrzymujemy zestaw zmiennych do wykresu ceph-csi-rbd:

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

Teraz musisz wypełnić plik cephrbd.yml. Aby to zrobić, znajdź identyfikator klastra i adresy IP monitorów w Ceph:

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

Uzyskane wartości wpisujemy do pliku cephrbd.yml. Jednocześnie umożliwiamy tworzenie polityk PSP (Pod Security Policies). Opcje w sekcjach wtyczka węzła и zaopatrzeniowiec już w pliku, można je poprawić w sposób pokazany poniżej:

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

Następnie pozostaje nam już tylko zainstalować wykres w klastrze Kubernetes.

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

Świetnie, sterownik RBD działa!
Utwórzmy nową klasę StorageClass w Kubernetes. To znowu wymaga trochę majsterkowania przy Ceph.

Tworzymy nowego użytkownika w Ceph i nadajemy mu uprawnienia do zapisu do puli Kube:

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

Zobaczmy teraz, że klucz dostępu nadal tam jest:

ceph auth get-key client.rbdkube

Polecenie wyświetli coś takiego:

AQCO9NJbhYipKRAAMqZsnqqS/T8OYQX20xIa9A==

Dodajmy tę wartość do Secret w klastrze Kubernetes – tam, gdzie jej potrzebujemy klucz użytkownika:

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

I tworzymy nasz sekret:

kubectl apply -f secret.yaml

Następnie potrzebujemy manifestu StorageClass mniej więcej takiego:

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

Należy wypełnić identyfikator klastra, o czym przekonał się już zespół ceph fsidi zastosuj ten manifest do klastra Kubernetes:

kubectl apply -f storageclass.yaml

Aby sprawdzić, jak klastry współpracują ze sobą, utwórzmy następujące PVC (Persistent Volume Claim):

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

Zobaczmy od razu, jak Kubernetes utworzył żądany wolumin w Ceph:

kubectl get pvc
kubectl get pv

Wszystko wydaje się być świetne! Jak to wygląda po stronie Ceph?
Otrzymujemy listę woluminów w puli i przeglądamy informacje o naszym wolumenie:

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

Zobaczmy teraz, jak działa zmiana rozmiaru woluminu RBD.
Zmień rozmiar woluminu w manifeście pvc.yaml na 2Gi i zastosuj go:

kubectl apply -f pvc.yaml

Poczekajmy, aż zmiany zaczną obowiązywać i ponownie spójrzmy na rozmiar woluminu.

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

kubectl get pv
kubectl get pvc

Widzimy, że rozmiar PCV się nie zmienił. Aby dowiedzieć się dlaczego, możesz zapytać Kubernetesa o opis YAML PVC:

kubectl get pvc rbd-pvc -o yaml

Oto problem:

komunikat: Oczekiwanie, aż użytkownik (ponownie) uruchomi moduł w celu zakończenia zmiany rozmiaru woluminu w systemie plików w węźle. wpisz: FileSystemResizePending

Oznacza to, że dysk urósł, ale system plików na nim nie.
Aby powiększyć system plików, musisz zamontować wolumin. W naszym kraju powstałe PCV/PV nie jest obecnie w żaden sposób wykorzystywane.

Możemy stworzyć Poda testowego, na przykład tak:

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

A teraz spójrzmy na PCV:

kubectl get pvc

Rozmiar się zmienił, wszystko jest w porządku.

W pierwszej części pracowaliśmy z urządzeniem blokowym RBD (skrót od Rados Block Device), ale nie da się tego zrobić, jeśli różne mikrousługi muszą jednocześnie pracować z tym dyskiem. CephFS znacznie lepiej nadaje się do pracy z plikami niż z obrazami dysków.
Na przykładzie klastrów Ceph i Kubernetes skonfigurujemy CSI oraz inne niezbędne podmioty do współpracy z CephFS.

Uzyskajmy wartości z nowego wykresu Helma, których potrzebujemy:

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

Ponownie musisz wypełnić plik cephfs.yml. Tak jak poprzednio, polecenia Ceph pomogą:

ceph fsid
ceph mon dump

Wypełnij plik takimi wartościami:

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

Należy pamiętać, że adresy monitorów są podawane w prostej formie adres:port. Aby zamontować cephfs na węźle, adresy te są przesyłane do modułu jądra, który nie wie jeszcze, jak pracować z protokołem monitora v2.
Zmieniamy port dla httpMetrics (Prometheus pójdzie tam w celu monitorowania metryk), aby nie kolidował z nginx-proxy, który jest instalowany przez Kubespray. Możesz tego nie potrzebować.

Zainstaluj wykres Helm w klastrze Kubernetes:

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

Przejdźmy do magazynu danych Ceph, aby utworzyć tam osobnego użytkownika. Dokumentacja stwierdza, że ​​dostawca CephFS wymaga uprawnień administratora klastra. Ale utworzymy osobnego użytkownika fs z ograniczonymi prawami:

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'

I od razu spójrzmy na jego klucz dostępu, będziemy go potrzebować później:

ceph auth get-key client.fs

Utwórzmy osobne klasy Secret i StorageClass.
Nic nowego, widzieliśmy to już na przykładzie RBD:

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

Stosowanie manifestu:

kubectl apply -f secret.yaml

A teraz - osobna 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

Wypełnijmy to tutaj identyfikator klastra i ma zastosowanie w Kubernetes:

kubectl apply -f storageclass.yaml

Проверка

Aby to sprawdzić, tak jak w poprzednim przykładzie, utwórzmy PVC:

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

I sprawdź obecność PVC/PV:

kubectl get pvc
kubectl get pv

Jeśli chcesz przeglądać pliki i katalogi w CephFS, możesz gdzieś zamontować ten system plików. Na przykład jak pokazano poniżej.

Przejdźmy do jednego z węzłów klastra Ceph i wykonajmy następujące czynności:

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

Oczywiście montowanie FS na takim węźle Ceph nadaje się tylko do celów szkoleniowych, co właśnie robimy na naszym Kursy slumsowe. Nie sądzę, żeby ktokolwiek zrobił to w środowisku produkcyjnym; istnieje duże ryzyko przypadkowego usunięcia ważnych plików.

Na koniec sprawdźmy, jak wygląda sprawa ze zmianą rozmiaru woluminów w przypadku CephFS. Wróćmy do Kubernetesa i edytujmy nasz manifest dla PVC - zwiększmy tam rozmiar np. do 7Gi.

Zastosujmy edytowany plik:

kubectl apply -f pvc.yaml

Przyjrzyjmy się zamontowanemu katalogowi, aby zobaczyć, jak zmienił się limit:

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

Aby to polecenie zadziałało, może być konieczne zainstalowanie pakietu w systemie atr.

Oczy się boją, a ręce robią

Wszystkie te zaklęcia i długie manifesty YAML wydają się na pierwszy rzut oka skomplikowane, ale w praktyce uczniowie ze Sluru dość szybko opanowują je.
W tym artykule nie zagłębialiśmy się w dżunglę – jest na to oficjalna dokumentacja. Jeśli interesują Cię szczegóły konfiguracji magazynu Ceph z klastrem Kubernetes, poniższe linki będą pomocne:

Ogólne zasady Kubernetesa pracy z woluminami
Dokumentacja RBD
Integracja RBD i Kubernetes z perspektywy Ceph
Integracja RBD i Kubernetes z perspektywy CSI
Ogólna dokumentacja CephFS
Integracja CephFS i Kubernetes z perspektywy CSI

Na kursie Slum Baza Kubernetesa możesz pójść trochę dalej i wdrożyć w Kubernetesie prawdziwą aplikację, która będzie używać CephFS jako magazynu plików. Za pomocą żądań GET/POST będziesz mógł przesyłać pliki do i odbierać je od Ceph.

A jeśli bardziej interesuje Cię przechowywanie danych, zarejestruj się nowy kurs na Ceph. W trakcie beta-testów kurs można nabyć ze zniżką i mieć wpływ na jego treść.

Autor artykułu: Alexander Shvalov, praktykujący inżynier Southbridge, Certyfikowany Administrator Kubernetes, autor i twórca kursów Slurm.

Źródło: www.habr.com