Kubernetes: Longhorn, настройка

Небольшое how-to по базовой настройке Longhorn.

  • У вас уже есть готовый кластер K8s.
  • У вас установлен и настроен Longhorn, например, по статье Kubernetes: Longhorn, установка
  • Файловые системы
  • Привязка Longhorn к конкретным нодам

По умолчанию Longhorn создаёт StorageClass (SC), который использует ext4. Убедиться в этом можно, изучив манифест деплоя. Это наводит нас на мысль, что Longhorn поддерживает и другие файловые системы:

Либо, что проще и быстрее:

k get sc longhorn -o yaml

и увидим соответствующие параметры

parameters:
  dataEngine: v1
  dataLocality: disabled
  disableRevisionCounter: "true"
  fromBackup: ""
  fsType: ext4
  numberOfReplicas: "3"
  staleReplicaTimeout: "30"
  unmapMarkSnapChainRemoved: ignored
provisioner: driver.longhorn.io
reclaimPolicy: Delete

Поддерживаемые файловые системы

Список поддерживаемых файловых систем доступен в документации Longhorn. Он невелик: ext4 и xfs.

Что ж, XFS — современная высокопроизводительная файловая система. Создадим StorageClass с её использованием.

Вот манифест для создания SC. После его применения у нас будет sc longhorn-xfs

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-xfs
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
parameters:
  numberOfReplicas: "2"
  staleReplicaTimeout: "30"
  fromBackup: ""
  fsType: "xfs"
  dataLocality: "disabled"
  unmapMarkSnapChainRemoved: "ignored"
  disableRevisionCounter: "true"
  dataEngine: "v1"

Что ж, теперь можно создать PVC и тестовый Deployment, который его использует

---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: longhorn-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
  storageClassName: longhorn-xfs
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: go-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: go-app-label
  template:
    metadata:
      labels:
        app: go-app-label
    spec:
      containers:
      - image: denisitpro/go-example:latest
        name: go-app
        env:
          - name: AI_NAME
            value: "Ivan"
        ports:
        - containerPort: 8082
        readinessProbe:
          failureThreshold: 5
          httpGet:
            path: /
            port: 8082
          periodSeconds: 10
          successThreshold: 2
          timeoutSeconds: 3
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /
            port: 8082
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 3
          initialDelaySeconds: 10
        resources:
          requests:
            cpu: 100m
            memory: 64Mi
          limits:
            cpu: 300m
            memory: 512Mi
        volumeMounts:
        - mountPath: /opt/example
          name: data-volume
      volumes:
      - name: data-volume
        persistentVolumeClaim:
          claimName: "longhorn-pvc"

Зайдём в наш Pod и проверим, какая файловая система в точке монтирования. В нашем случае это /opt/example

$ kubectl exec -it  go-app-fd8f8d4c-ptq9t -- /bin/bash
$ mount | grep /opt/example
 
/dev/longhorn/pvc-60e48975-b703-4aba-99d7-19dabef5bfd2 on /opt/example type xfs (rw,relatime,nouuid,attr2,inode64,logbufs=8,logbsize=32k,noquota)

Как мы и планировали, файловая система — xfs

Настройка нод, на которых Longhorn может запускать свои Pod’ы

Предположим, у нас в кластере много worker-нод, и мы хотим, чтобы Longhorn запускался только на конкретных. Для этого мы поступим следующим образом:

Пропатчим спецификацию, чтобы Longhorn использовал только ноды с этим label.

Назначим нужным нодам label

k label nodes w-01 storage=longhorn
k label nodes w-02 storage=longhorn
k label nodes w-03 storage=longhorn

и проверяем что наши ноды получили label

$ kubectl get nodes -l storage=longhorn
NAME   STATUS   ROLES    AGE    VERSION
w-01   Ready    <none>   3m4s   v1.31.1
w-02   Ready    <none>   3m5s   v1.31.1
w-03   Ready    <none>   3m5s   v1.31.1

Теперь обновим нашу установку, добавив параметры longhorn.nodeSelector.«storage»=longhorn

helm upgrade --install longhorn longhorn/longhorn \
  --namespace longhorn-system \
  --set defaultSettings.replicaCount=3 \
  --set defaultSettings.storageOverProvisioningPercentage=100 \
  --set defaultSettings.storageMinimalAvailablePercentage=15 \
  --set defaultSettings.nodeDownPodDeletionPolicy="delete-both-statefulset-and-deployment-pod" \
  --set defaultSettings.replicaAutoBalance="best-effort" \
  --set defaultSettings.dataLocality="best-effort" \
  --set defaultSettings.rebalanceDisksWhenLowSpace=true \
  --set longhorn.nodeSelector."storage"="longhorn"

Также рекомендуется пересоздать Pod.

kubectl delete pods -n longhorn-system --all

После этого добавим ещё одну рабочую ноду в кластер и проверим.

Чтобы понять, какие компоненты должны быть на всех нодах, мы можем посмотреть DaemonSet.

(DaemonSet — это объект Kubernetes, который гарантирует, что копия Pod’а, определённого в конфигурации, всегда доступна на каждом рабочем узле в кластере.)

$ k get ds -n longhorn-system
 
NAME                       DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
engine-image-ei-c2d50bcc   3         3         3       3            3           <none>          7m30s
longhorn-csi-plugin        3         3         3       3            3           <none>          6m32s
longhorn-manager           3         3         3       3            3           <none>          8m3s

В моем примере я добавлю w-04 в набор рабочих нод

[k8s_worker]
w-01.beta-82.win
w-02.beta-82.win
w-03.beta-82.win
w-04.beta-82.win

Проверяем, что наша worker-нода появилась и на неё добавились новые Pod’ы

$ k get nodes
NAME     STATUS   ROLES           AGE     VERSION
k8s-01   Ready    control-plane   46m     v1.31.1
k8s-02   Ready    control-plane   46m     v1.31.1
k8s-03   Ready    control-plane   46m     v1.31.1
w-01     Ready    <none>          19m     v1.31.1
w-02     Ready    <none>          19m     v1.31.1
w-03     Ready    <none>          19m     v1.31.1
w-04     Ready    <none>          2m49s   v1.31.1

Проверим вывод списка Pod’ов

$ k get pods -o wide
NAME                                                READY   STATUS    RESTARTS      AGE     IP            NODE   NOMINATED NODE   READINESS GATES
csi-attacher-79866cdcf8-7kvkd                       1/1     Running   0             23m     10.48.6.74    w-01   <none>           <none>
csi-attacher-79866cdcf8-hgqg8                       1/1     Running   0             23m     10.48.2.134   w-03   <none>           <none>
csi-attacher-79866cdcf8-pjm78                       1/1     Running   0             23m     10.48.4.199   w-02   <none>           <none>
csi-provisioner-664cb5bdd5-fr2s2                    1/1     Running   0             23m     10.48.6.75    w-01   <none>           <none>
csi-provisioner-664cb5bdd5-jqhtj                    1/1     Running   0             23m     10.48.2.135   w-03   <none>           <none>
csi-provisioner-664cb5bdd5-qrxt7                    1/1     Running   0             23m     10.48.4.198   w-02   <none>           <none>

Теперь остановим рабочие ноды с w-01 по w-03

k get nodes
NAME     STATUS     ROLES           AGE     VERSION
k8s-01   Ready      control-plane   53m     v1.31.1
k8s-02   Ready      control-plane   53m     v1.31.1
k8s-03   Ready      control-plane   53m     v1.31.1
w-01     NotReady   <none>          25m     v1.31.1
w-02     NotReady   <none>          25m     v1.31.1
w-03     NotReady   <none>          25m     v1.31.1
w-04     Ready      <none>          9m29s   v1.31.1

Попробуем применить Deployment, который использовали для xfs, и увидим ошибку

$k describe pod go-app-fd8f8d4c-vw496
 Warning  FailedScheduling  32s   default-scheduler  0/7 nodes are available: pod has unbound immediate PersistentVolumeClaims. preemption: 0/7 nodes are available: 7 Preemption is not helpful for scheduling.

Проверим состояние PVC

$ k describe pvc longhorn-pvc
Normal  ExternalProvisioning   18s (x7 over 84s)  persistentvolume-controller                                                               Waiting for a volume to be created either by the external provisioner 'driver.longhorn.io' or manually by the system administrator. If volume creation is delayed, please verify that the provisioner is running and correctly registered.

На этом проверка завершена.

Запуск Longhorn на выделенных серверах

Предположим, у нас есть кластер с множеством узлов, и мы хотим, чтобы компоненты Longhorn запускались только на w-01 по w-03.

Пометим все необходимые ноды нужным label

k label nodes w-01 storage=longhorn
k label nodes w-02 storage=longhorn
k label nodes w-03 storage=longhorn

проверим вывод

$ kubectl get nodes -l storage=longhorn
 
NAME   STATUS   ROLES    AGE   VERSION
w-01   Ready    <none>   68m   v1.31.1
w-02   Ready    <none>   68m   v1.31.1
w-03   Ready    <none>   68m   v1.31.1

Создадим values.yaml, который переопределит наши настройки. Почему файл? Потому что при больших объёмах настроек это удобнее и нагляднее

$ cat values.yaml

defaultSettings:
  replicaCount: 3
  storageOverProvisioningPercentage: 100
  storageMinimalAvailablePercentage: 15
  nodeDownPodDeletionPolicy: "delete-both-statefulset-and-deployment-pod"
  replicaAutoBalance: "best-effort"
  dataLocality: "best-effort"
  rebalanceDisksWhenLowSpace: true
  systemManagedComponentsNodeSelector: "storage:longhorn"

longhornManager:
  nodeSelector:
    storage: "longhorn"
longhornDriver:
  nodeSelector:
    storage: "longhorn"
longhornUI:
  nodeSelector:
    storage: "longhorn"

применим

$ helm upgrade --install longhorn longhorn/longhorn \
  --namespace longhorn-system --create-namespace --version 1.8.0 \
  -f values.yaml

Проверим, на каких серверах теперь наши компоненты

kubectl get pods -n longhorn-system -o wide
NAME                                                READY   STATUS    RESTARTS      AGE   IP            NODE   NOMINATED NODE   READINESS GATES
csi-attacher-7fd58974f5-c7947                       1/1     Running   0             23s   10.48.2.149   w-03   <none>           <none>
csi-attacher-7fd58974f5-dfrtp                       1/1     Running   0             23s   10.48.4.215   w-02   <none>           <none>
csi-attacher-7fd58974f5-zftr7                       1/1     Running   0             23s   10.48.6.82    w-01   <none>           <none>
...

Так как у нас теперь появилось ограничения, где запускается longhorn, то нам придется обновить наш storageClass, добавив allowedTopologies. Тогда поды будут запускаться только на серверах, где установлен longhorn

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: longhorn-xfs
  annotations:
    storageclass.kubernetes.io/is-default-class: "false"
provisioner: driver.longhorn.io
allowVolumeExpansion: true
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
parameters:
  numberOfReplicas: "3"
  staleReplicaTimeout: "30"
  fromBackup: ""
  fsType: "xfs"
  dataLocality: "disabled"
  unmapMarkSnapChainRemoved: "ignored"
  disableRevisionCounter: "true"
  dataEngine: "v1"
  allowedTopologies:
  - matchLabelExpressions:
      - key: storage
        values:
          - longhorn