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