# 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) ```bash dnf install -y iscsi-initiator-utils nfs-utils cryptsetup ``` | Пакет | Зачем | |---|---| | `iscsi-initiator-utils` | iSCSI-стек для подключения томов | | `nfs-utils` | NFS-поддержка для RWX-томов и бэкапов | | `cryptsetup` | LUKS2-шифрование томов (опционально) | ### Сервисы ```bash 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 томов. ### Ручной патч (на каждой ноде) ```bash echo '(allow iscsid_t self (capability (dac_override)))' > /tmp/local_longhorn.cil semodule -vi /tmp/local_longhorn.cil ``` ### Автоматически через DaemonSet (после установки Longhorn) ```bash 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 (рекомендуемый метод) ```bash 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`: ```bash # Скачать 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` автоматически: ```yaml 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. После регистрации диск мгновенно становится доступен для новых томов. #### Подготовка диска (на уровне ОС) ```bash # 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= /mnt/longhorn-disk2 xfs defaults,nofail 0 2" >> /etc/fstab # 5. Смонтировать mount -a ``` > **Важно:** не использовать symlink в пути — Longhorn-поды не разрешают символические ссылки корректно. #### Регистрация диска в Longhorn **Через kubectl (рекомендуется для Ansible):** ```bash kubectl patch nodes.longhorn.io -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: ```yaml # StorageClass parameters: diskSelector: "ssd" ``` Тогда реплики создаются только на дисках с нужными тегами. --- ### Сценарий B: добавление ноды к кластеру #### Автоматическое обнаружение Когда новая нода присоединяется к Kubernetes, **Longhorn обнаруживает её автоматически** через DaemonSet — никаких ручных действий не требуется. Longhorn-manager pod поднимается на новой ноде и создаёт Longhorn Node CR. По умолчанию Longhorn сразу создаёт диск по пути из настройки `Default Data Path` (`/var/lib/longhorn`). #### Проверка после появления ноды ```bash # Убедиться, что нода появилась в Longhorn kubectl get node.longhorn.io -n longhorn-system # Проверить диск на ноде kubectl get node.longhorn.io -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`, нужно: 1. Подготовить и смонтировать диск на новой ноде (аналогично Сценарию A). 2. Зарегистрировать диск в Longhorn вручную или через аннотацию ноды (до или после присоединения к кластеру): ```bash kubectl annotate node \ 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 — **сделать снапшот или бэкап**. #### Процедура ```bash # 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 -n longhorn-system \ --type merge \ -p '{"spec":{"numberOfReplicas":3}}' # 4. Мониторинг перестройки kubectl get volume -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 создавались сразу с нужной репликацией: ```bash 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 | --- ## Источники - [Longhorn Official Documentation 1.11](https://longhorn.io/docs/1.11.2/) - [Longhorn Installation Guide](https://longhorn.io/docs/1.11.2/deploy/install/) - [Longhorn Best Practices](https://longhorn.io/docs/1.11.2/best-practices/) - [Longhorn SELinux Troubleshooting](https://longhorn.io/kb/troubleshooting-volume-attachment-fails-due-to-selinux-denials/) - [Longhorn Multiple Disk Support](https://longhorn.io/docs/1.10.1/nodes-and-volumes/nodes/multidisk/)