====== Kubernetes: Longhorn, настройка ====== Небольшое how-to по базовой настройке Longhorn. ===== Допущения и ограничения ===== * У вас уже есть готовый кластер K8s. * У вас установлен и настроен Longhorn, например, по статье [[https://fatalex.cifro.net/devops/k8s/kubernetes_loghorn|Kubernetes: Longhorn, установка]] ===== Что будем настраивать ===== * Файловые системы * Привязка Longhorn к конкретным нодам ===== Настройка файловой системы ===== По умолчанию Longhorn создаёт StorageClass (SC), который использует ''ext4''. Убедиться в этом можно, изучив манифест деплоя. Это наводит нас на мысль, что Longhorn поддерживает и другие файловые системы: * [[https://raw.githubusercontent.com/longhorn/longhorn/v1.8.0/deploy/longhorn.yaml|Longhorn Deployment Manifest]] * [[https://github.com/longhorn/charts/tree/v1.8.x/charts/longhorn|Longhorn Charts Repository]] Либо, что проще и быстрее: 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 Поддерживаемые файловые системы Список поддерживаемых файловых систем доступен в [[https://longhorn.io/docs/1.8.0/deploy/install/#installation-requirements|документации 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 3m4s v1.31.1 w-02 Ready 3m5s v1.31.1 w-03 Ready 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 7m30s longhorn-csi-plugin 3 3 3 3 3 6m32s longhorn-manager 3 3 3 3 3 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 19m v1.31.1 w-02 Ready 19m v1.31.1 w-03 Ready 19m v1.31.1 w-04 Ready 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 csi-attacher-79866cdcf8-hgqg8 1/1 Running 0 23m 10.48.2.134 w-03 csi-attacher-79866cdcf8-pjm78 1/1 Running 0 23m 10.48.4.199 w-02 csi-provisioner-664cb5bdd5-fr2s2 1/1 Running 0 23m 10.48.6.75 w-01 csi-provisioner-664cb5bdd5-jqhtj 1/1 Running 0 23m 10.48.2.135 w-03 csi-provisioner-664cb5bdd5-qrxt7 1/1 Running 0 23m 10.48.4.198 w-02 Теперь остановим рабочие ноды с ''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 25m v1.31.1 w-02 NotReady 25m v1.31.1 w-03 NotReady 25m v1.31.1 w-04 Ready 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 на выделенных серверах ====== ==== Документация ==== * [[https://longhorn.io/kb/tip-only-use-storage-on-a-set-of-nodes/|Использование хранилища только на определённых нодах]] * [[https://longhorn.io/docs/archives/1.2.2/advanced-resources/deploy/node-selector/|Настройка Node Selector]] * [[https://github.com/longhorn/longhorn/blob/master/chart/values.yaml|Конфигурация в values.yaml]] Предположим, у нас есть кластер с множеством узлов, и мы хотим, чтобы компоненты 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 68m v1.31.1 w-02 Ready 68m v1.31.1 w-03 Ready 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 csi-attacher-7fd58974f5-dfrtp 1/1 Running 0 23s 10.48.4.215 w-02 csi-attacher-7fd58974f5-zftr7 1/1 Running 0 23s 10.48.6.82 w-01 ... Так как у нас теперь появилось ограничения, где запускается 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