21 KiB
Longhorn — исследование для развёртывания в кластере
Что такое Longhorn
Longhorn — распределённое блочное хранилище для Kubernetes (CNCF-проект, изначально Rancher).
Предоставляет PersistentVolume через CSI-драйвер с репликацией данных между нодами, инкрементальными снапшотами и встроенным бэкапом.
На каких нодах нужны диски
Longhorn Manager запускается как DaemonSet на нодах кластера. Каждая нода, где работает Longhorn Manager, может хранить реплики томов.
Применительно к этому кластеру:
| Нода | Группа | Роль в Longhorn |
|---|---|---|
| k8s-master-01 (10.203.0.97) | control_plane | Может участвовать (тейнт уже снят), но нежелательно в production |
| k8s-worker-NN | workers | Основные ноды для хранилища — диски должны быть здесь |
| k8s-manager-01 (10.203.0.92) | manager_nodes | Не входит в кластер, диски не нужны |
Вывод: диски нужны на worker-нодах. Желательно не смешивать роль control plane и хранилища.
Минимальное количество нод
| Режим | Нод с дисками | Репликация | Отказоустойчивость |
|---|---|---|---|
| Dev / тест | 1 | 1 | Нет |
| Minimum HA | 3 | 2 | Выдерживает отказ 1 ноды |
| Production HA | 3 | 3 | Выдерживает отказ 2 нод |
| Extended HA | 5+ | 3 | Рекомендуется для критичных данных |
Почему именно 3 ноды — минимум для стабильной работы
Longhorn по умолчанию размещает реплики тома на разных нодах (replica node anti-affinity).
- При
replication=3требуются 3 разные ноды, иначе Longhorn деградирует том или откажет в создании. - При
replication=2достаточно 2 нод, но потеря любой из них оставит данные без резерва — том продолжит работу, но уязвим. - 3 ноды +
replication=3— классическая кворум-схема: можно потерять 1 ноду и данные остаются защищёнными.
Практические варианты для этого кластера:
- Рекомендуется: 3 worker-ноды + control plane (без хранилища)
- Допустимо (временно): 2 worker-ноды + control plane с Longhorn — итого 3 ноды с дисками, но смешение ролей нежелательно
Минимальное количество дисков на ноде
- Минимум: 1 диск на ноду. Longhorn работает с одним диском.
- Рекомендуется: 1 выделенный диск (отдельно от ОС-диска
/dev/sda). - Longhorn поддерживает несколько дисков на одной ноде — реплики балансируются между ними автоматически.
ОС-диск vs выделенный диск
| Параметр | ОС-диск | Выделенный диск |
|---|---|---|
| Изоляция от системы | Нет | Да |
minimalAvailableStoragePercentage |
≥25% | 10% |
| Риск DiskPressure | Высокий | Низкий |
| Рекомендация | Только dev/тест | Production |
Минимальная жизнеспособная production-конфигурация:
3 worker-ноды × 1 выделенный диск = 3 диска суммарно
Принципы репликации
Longhorn реплицирует данные посинхронно (synchronous replication) между репликами при записи.
Pod (write) → Longhorn Engine → Replica 1 (node-1 /dev/sdb)
→ Replica 2 (node-2 /dev/sdb)
→ Replica 3 (node-3 /dev/sdb)
- Запись подтверждается только когда все реплики записали данные.
- При отказе реплики Longhorn автоматически перестраивает её на другой ноде (Rebuild).
- Значение
replicationзадаётся на уровне StorageClass или отдельного тома.
Рекомендуемые настройки anti-affinity
| Настройка | Значение | Смысл |
|---|---|---|
replicaNodeLevelSoftAntiAffinity |
false |
Запрет размещения 2 реплик на одной ноде (hard rule) |
replicaDiskLevelSoftAntiAffinity |
true |
Разрешить несколько реплик на одной ноде, но на разных дисках |
Prerequisites — что нужно установить на все ноды кластера
Пакеты (Rocky Linux 9)
dnf install -y iscsi-initiator-utils nfs-utils cryptsetup
| Пакет | Зачем |
|---|---|
iscsi-initiator-utils |
iSCSI-стек для подключения томов |
nfs-utils |
NFS-поддержка для RWX-томов и бэкапов |
cryptsetup |
LUKS2-шифрование томов (опционально) |
Сервисы
systemctl enable --now iscsid
Kernel modules
iscsi_tcp — iSCSI over TCP
dm_crypt — Device-mapper шифрование
Добавить в /etc/modules-load.d/longhorn.conf:
iscsi_tcp
dm_crypt
Утилиты (должны быть в PATH)
bash, curl, findmnt, grep, awk, blkid, lsblk — как правило, уже присутствуют на Rocky Linux 9.
SELinux workaround (Rocky Linux 9 — обязательно)
Rocky Linux 9 с container-selinux > 2.189.0 блокирует iscsiadm через SELinux, что приводит к бесконечному циклу attach/detach томов.
Ручной патч (на каждой ноде)
echo '(allow iscsid_t self (capability (dac_override)))' > /tmp/local_longhorn.cil
semodule -vi /tmp/local_longhorn.cil
Автоматически через DaemonSet (после установки Longhorn)
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/prerequisite/longhorn-iscsi-selinux-workaround.yaml
Firewall (firewalld)
Добавить на ноды кластера:
| Порт | Протокол | Зачем |
|---|---|---|
| 2049 | tcp | NFS (для RWX томов и бэкапов) |
| 111 | tcp/udp | portmapper (NFS) |
Порт 10250/tcp (kubelet API) уже открыт в существующей роли k8s_control_plane.
Установка — Helm chart (рекомендуемый метод)
helm repo add longhorn https://charts.longhorn.io
helm repo update
helm install longhorn longhorn/longhorn \
--namespace longhorn-system \
--create-namespace \
--version 1.7.2 \
--set defaultSettings.defaultReplicaCount=3 \
--set defaultSettings.replicaNodeLevelSoftAntiAffinity=false \
--set defaultSettings.minimalAvailableStoragePercentage=10
Ключевые Helm-параметры
| Параметр | Рекомендуемое значение | Описание |
|---|---|---|
defaultSettings.defaultReplicaCount |
3 |
Реплик по умолчанию на новый том |
defaultSettings.replicaNodeLevelSoftAntiAffinity |
false |
Запрет реплик на одной ноде |
defaultSettings.minimalAvailableStoragePercentage |
10 (dedicated) / 25 (OS disk) |
Резерв свободного места |
defaultSettings.storageOverProvisioningPercentage |
100 |
Overprovisioning (200 = двойной запас) |
Проверка готовности нод (preflight)
Longhorn предоставляет утилиту longhornctl:
# Скачать
curl -sSfL -o longhornctl https://github.com/longhorn/cli/releases/latest/download/longhornctl-linux-amd64
chmod +x longhornctl
# Проверить prerequisites
./longhornctl check preflight
# Автоматически установить зависимости
./longhornctl install preflight
StorageClass после установки
Longhorn создаёт StorageClass longhorn автоматически:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: longhorn
provisioner: driver.longhorn.io
parameters:
numberOfReplicas: "3"
staleReplicaTimeout: "2880"
fromBackup: ""
reclaimPolicy: Delete
volumeBindingMode: Immediate
Итоговые минимумы для production
| Параметр | Минимум (stable) | Рекомендуется |
|---|---|---|
| Нод с дисками | 3 | 3+ |
| Дисков на ноду | 1 (выделенный) | 1–2 |
| Репликация | 2 | 3 |
| Пакеты | open-iscsi + nfs-utils | + cryptsetup |
| SELinux патч | Обязательно на Rocky Linux 9 | — |
| Отдельный диск от ОС | Рекомендуется | — |
Масштабирование: добавление дисков и нод
Сценарий A: добавление диска к существующей ноде
Как это работает
Longhorn не отслеживает диски автоматически — каждый новый диск нужно явно зарегистрировать через Longhorn UI или kubectl. После регистрации диск мгновенно становится доступен для новых томов.
Подготовка диска (на уровне ОС)
# 1. Отформатировать (ext4 или xfs — обязательно extent-based)
mkfs.xfs /dev/sdb
# 2. Создать точку монтирования
mkdir -p /mnt/longhorn-disk2
# 3. Получить UUID (надёжнее device-name)
blkid /dev/sdb
# 4. Добавить в /etc/fstab (UUID, nofail — обязательно)
echo "UUID=<uuid> /mnt/longhorn-disk2 xfs defaults,nofail 0 2" >> /etc/fstab
# 5. Смонтировать
mount -a
Важно: не использовать symlink в пути — Longhorn-поды не разрешают символические ссылки корректно.
Регистрация диска в Longhorn
Через kubectl (рекомендуется для Ansible):
kubectl patch nodes.longhorn.io <node-name> -n longhorn-system \
--type merge \
-p '{"spec":{"disks":{"disk2":{"path":"/mnt/longhorn-disk2","allowScheduling":true,"diskType":"filesystem"}}}}'
Через UI: Nodes → выбрать ноду → Edit node and disks → Add Disk.
Автоматический ребалансинг реплик на новый диск?
Нет. Существующие реплики не переезжают автоматически на новый диск.
- Новый диск начинает использоваться только для новых томов.
- Если включена функция
Replica Auto Balance(режимbest-effort), Longhorn постепенно перемещает часть реплик для выравнивания нагрузки между дисками. - Настройка: Longhorn UI → Settings → Replica Auto Balance →
best-effort.
Сложности при добавлении диска
| Сложность | Причина | Решение |
|---|---|---|
| Диск не виден Longhorn | Не смонтирован до регистрации | mount | grep /mnt/longhorn-disk2 |
| Ошибка дублирования | Тот же filesystem UUID уже в кластере | Проверить lsblk -f перед добавлением |
| Disk не используется | allowScheduling: false |
Включить через UI или patch |
| Резерв места слишком велик | storageReserved ≥ объёму диска |
Понизить до 10% от объёма |
Теги дисков (routing для специфичных воркеров)
Можно пометить диск тегом (например ssd, fast) и указывать его в StorageClass:
# StorageClass
parameters:
diskSelector: "ssd"
Тогда реплики создаются только на дисках с нужными тегами.
Сценарий B: добавление ноды к кластеру
Автоматическое обнаружение
Когда новая нода присоединяется к Kubernetes, Longhorn обнаруживает её автоматически через DaemonSet — никаких ручных действий не требуется. Longhorn-manager pod поднимается на новой ноде и создаёт Longhorn Node CR.
По умолчанию Longhorn сразу создаёт диск по пути из настройки Default Data Path (/var/lib/longhorn).
Проверка после появления ноды
# Убедиться, что нода появилась в Longhorn
kubectl get node.longhorn.io -n longhorn-system
# Проверить диск на ноде
kubectl get node.longhorn.io <node-name> -n longhorn-system -o yaml
# Ищем: spec.disks, status.diskStatus — должны быть schedulable: true
Ребалансинг существующих реплик на новую ноду?
По умолчанию — нет. Существующие реплики не переезжают на новую ноду автоматически.
Чтобы включить ребалансинг:
Longhorn UI → Settings → Replica Auto Balance → best-effort
| Режим | Поведение |
|---|---|
disabled (по умолчанию) |
Реплики не перемещаются |
least-effort |
Минимальное перемещение — только для восстановления fault-tolerance |
best-effort |
Равномерное распределение по всем нодам |
Ноды с Выделенными дисками (не /var/lib/longhorn)
Если диск подключён как /dev/sdb и смонтирован в /mnt/longhorn, нужно:
- Подготовить и смонтировать диск на новой ноде (аналогично Сценарию A).
- Зарегистрировать диск в Longhorn вручную или через аннотацию ноды (до или после присоединения к кластеру):
kubectl annotate node <node-name> \
node.longhorn.io/default-disks-config='[{"path":"/mnt/longhorn","allowScheduling":true}]'
Сложности при добавлении ноды
| Сложность | Причина | Решение |
|---|---|---|
| Нода есть в K8s, но не в Longhorn | DaemonSet не запустился (taint, ресурсы) | Проверить kubectl get pods -n longhorn-system -o wide |
| Нода есть в Longhorn, но не планирует реплики | allowScheduling: false или нет свободного места |
Включить scheduling, проверить space |
| Реплики не переехали | Auto Balance выключен | Включить best-effort |
| Existing volumes не используют новую ноду | Replication count не обновлён | Обновить replica count (см. ниже) |
| Prerequisites не установлены | Нет iscsid, nfs-utils |
Запустить роль prereqs перед join |
Критично: перед добавлением ноды к кластеру на ней обязаны быть установлены
iscsi-initiator-utils,nfs-utilsи применён SELinux-патч (для Rocky Linux 9). Иначе Longhorn Manager pod запустится, но тома не смогут монтироваться на этой ноде.
Сценарий C: миграция 1 нода → 3 ноды (увеличение репликации)
Ситуация
Старт: 1 worker-нода, replication=1 — данные есть, избыточности нет.
Цель: 3 ноды, replication=3 — полная HA.
Окно риска
Пока replica count увеличивается с 1 до 3, том находится в состоянии Degraded: старая реплика работает, новые перестраиваются. В этот момент:
- Том доступен для чтения и записи (без даунтайма).
- Если нода со старой единственной репликой упадёт во время перестройки → данные потеряны.
Поэтому перед увеличением replica count — сделать снапшот или бэкап.
Процедура
# 1. Убедиться, что новые ноды видны Longhorn
kubectl get node.longhorn.io -n longhorn-system
# 2. Включить Auto Balance (опционально, для автоматического выравнивания)
# Longhorn UI → Settings → Replica Auto Balance → best-effort
# 3. Обновить replica count для существующих томов
kubectl patch volume <volume-name> -n longhorn-system \
--type merge \
-p '{"spec":{"numberOfReplicas":3}}'
# 4. Мониторинг перестройки
kubectl get volume <volume-name> -n longhorn-system \
-o jsonpath='{.status.state} {.status.replicaCount}'
# Ожидаем: "healthy 3"
Время перестройки (ориентир)
| Объём тома | Время rebuild |
|---|---|
| 10 GiB | 2–5 минут |
| 100 GiB | 10–20 минут |
| 1 TiB | 1–4 часа |
Типичные проблемы при переходе 1→3
| Проблема | Симптом | Решение |
|---|---|---|
| Том завис в Degraded | replicaCount не растёт > 1 часа |
Проверить ноды: space, scheduling, taints |
| Replica count остался 1 | spec.numberOfReplicas=3, но status.replicaCount=1 |
Новые ноды unschedulable? kubectl get node.longhorn.io |
| Только 2 реплики создались | Третья нода без свободного места | Добавить диск или ноду с бо́льшим объёмом |
Data Locality: guaranteed мешает |
Том не перемещается | Сменить на best-effort на период миграции |
Обновить StorageClass для новых томов
Изменить numberOfReplicas в StorageClass, чтобы все новые PVC создавались сразу с нужной репликацией:
kubectl patch storageclass longhorn \
-p '{"parameters":{"numberOfReplicas":"3"}}'
Это не влияет на уже существующие тома — только на новые.
Итоговая таблица: сводка по масштабированию
| Действие | Автоматически? | Даунтайм? | Главный риск | Что сделать |
|---|---|---|---|---|
| Добавить диск на ноду | Нет (ручная регистрация) | Нет | Диск не смонтирован до регистрации | Смонтировать → зарегистрировать через kubectl/UI |
| Добавить ноду в кластер | Да (DaemonSet) | Нет | Prerequisites не установлены | Запустить prereqs-роль до join |
| Ребалансинг реплик | Нет (нужно включить) | Нет | Реплики остаются на старых нодах/дисках | Включить Replica Auto Balance: best-effort |
| Поднять replica count 1→3 | Нет (вручную) | Нет (том в Degraded) | Потеря данных при падении ноды во время rebuild | Снапшот перед изменением, мониторинг rebuild |