Текущая версия модуля устарела и больше не поддерживается. Переключитесь на использование модуля sds-drbd.

Работоспособность модуля гарантируется только в следующих случаях:

Работоспособность модуля в других условиях возможна, но не гарантируется.

Когда следует использовать LVM, а когда — LVMThin?

Если кратко, то:

  • LVM проще и обладает производительностью, сравнимой с производительностью накопителя;
  • LVMThin позволяет использовать snapshot’ы и overprovisioning, но медленнее в два раза.

Производительность и надежность LINSTOR, сравнение с Ceph

Мы придерживаемся практического взгляда на вопрос. Разница в несколько десятков процентов на практике никогда не имеет значения. Имеет значение разница в несколько раз и более.

Факторы сравнения:

  • Последовательное чтение и запись не имеют никакого значения, потому что на любой технологии они всегда упираются в сеть (что 10 Гбит/с, что 1 Гбит/с). С практической точки зрения этот показатель можно полностью игнорировать.
  • Случайное чтение и запись (что на 1 Гбит/с, что на 10 Гбит/с):
    • DRBD + LVM в 5 раз лучше, чем Ceph RBD (latency в 5 раз меньше, IOPS в 5 раз больше);
    • DRBD + LVM в 2 раза лучше, чем DRBD + LVMThin.
  • Если одна из реплик расположена локально, скорость чтения будет примерно равна скорости устройства хранения.
  • Если нет реплик, расположенных локально, скорость записи будет примерно ограничена половиной пропускной способности сети при двух репликах или ⅓ пропускной способности сети при трех репликах.
  • При большом количестве клиентов (больше 10, при iodepth 64) Ceph начинает отставать сильнее (до 10 раз) и потреблять значительно больше CPU.

В сухом остатке получается, что на практике неважно, какие параметры менять, и есть всего три значимых фактора:

  • локальность чтения — если все чтение производится локально, оно работает со скоростью (throughput, IOPS, latency) локального диска (разница практически незаметна);
  • 1 сетевой hop при записи — в DRBD репликацией занимается клиент, а в Ceph — сервер, поэтому у Ceph latency на запись всегда минимум в два раза больше, чем у DRBD;
  • сложность кода — latency вычислений на datapath (сколько процессорных команд выполняется на каждую операцию ввода/вывода) — DRBD + LVM проще, чем DRBD + LVMThin, и значительно проще, чем Ceph RBD.

Что использовать в какой ситуации?

По умолчанию модуль использует две реплики (третья — так называемая diskless — используется для поддержания кворума и создается автоматически). Такой подход гарантирует защиту от split-brain и достаточный уровень надежности хранения, но нужно учитывать следующие особенности:

  • В момент недоступности одной из реплик (реплики A) данные записываются только в единственную реплику (реплику B). Это означает, что:
    • если в этот момент отключится и вторая реплика (реплика B), запись и чтение будут недоступны;
    • если при этом вторая реплика (реплика B) утеряна безвозвратно, данные будут частично потеряны (есть только старая реплика A);
    • если старая реплика (реплика A) была тоже утеряна безвозвратно, данные будут потеряны полностью.
  • Чтобы включиться обратно при отключении второй реплики (без вмешательства оператора), требуется доступность обеих реплик. Это необходимо, чтобы корректно отработать ситуацию split-brain.
  • Включение третьей реплики решает обе проблемы (в любой момент времени доступно минимум две копии данных), но увеличивает накладные расходы (сеть, диск).

Настоятельно рекомендуется иметь одну реплику локально. Это в два раза увеличивает возможную скорость записи (при двух репликах) и значительно увеличивает скорость чтения. Но даже если реплики на локальном хранилище нет, все также будет работать нормально, за исключением того, что чтение будет осуществляться по сети и будет двойная утилизация сети при записи.

В зависимости от задачи нужно выбрать один из следующих вариантов:

  • DRBD + LVM — быстрее (в 2 раза) и надежнее (LVM — проще);
  • DRBD + LVMThin — поддержка snapshot’ов и возможность overprovisioning.

Как получить информацию об используемом пространстве?

Есть два варианта:

  • Через дашборд Grafana: перейдите Dashboards –> Storage –> LINSTOR/DRBD.
    В правом верхнем углу вы найдете информацию об используемом пространстве в кластере.

    Внимание! Эта информация отражает состояние всего сырого пространства в кластере. То есть если вы создаете тома в двух репликах, то эти значения стоит поделить на два. Это нужно, чтобы получить примерное представление о том, сколько таких томов может быть размещено в вашем кластере.

  • Через командный интерфейс LINSTOR:

    kubectl exec -n d8-linstor deploy/linstor-controller -- linstor storage-pool list
    

    Внимание! Эта информация отражает состояние сырого пространства для каждого узла в кластере. То есть если вы создаете тома в двух репликах, то эти две реплики обязательно должны целиком поместиться на двух узлах вашего кластера.

Как назначить StorageClass по умолчанию

Отобразите список всех StorageClass’ов:

kubectl get storageclass

Снимите аннотацию с предыдущего StorageClass’а по умолчанию:

kubectl annotate storageclass local-path storageclass.kubernetes.io/is-default-class-

Добавьте аннотацию для назначения нового StorageClass’а по умолчанию:

kubectl annotate storageclass linstor-data-r2 storageclass.kubernetes.io/is-default-class=true

Как добавить существующий LVM- или LVMThin-пул?

Основной метод описан на странице конфигурации хранилища LINSTOR. В отличие от команд, перечисленных ниже, он также автоматически настроит StorageClass’ы.

Пример добавления LVM-пула:

linstor storage-pool create lvm node01 lvmthin linstor_data

Пример добавления LVMThin-пула:

linstor storage-pool create lvmthin node01 lvmthin linstor_data/data

Можно добавлять и пулы, в которых уже созданы какие-то тома. LINSTOR просто будет создавать в пуле новые тома.

Как настроить Prometheus на использование хранилища LINSTOR?

Чтобы настроить Prometheus на использование хранилища LINSTOR, необходимо:

  • Настроить пулы хранения и StorageClass.
  • Указать параметры longtermStorageClass и storageClass в конфигурации модуля prometheus.

    Пример:

    apiVersion: deckhouse.io/v1alpha1
    kind: ModuleConfig
    metadata:
      name: prometheus
    spec:
      version: 2
      enabled: true
      settings:
        longtermStorageClass: linstor-data-r2
        storageClass: linstor-data-r2
    
  • Дождаться перезапуска подов Prometheus.

Как выгнать ресурсы с узла?

  • Загрузите скрипт evict.sh на хост, имеющий доступ к API Kubernetes с правами администратора (для работы скрипта потребуются установленные kubectl и jq):

    • Последнюю версию скрипта можно скачать с GitHub:

      curl -fsSL -o evict.sh https://raw.githubusercontent.com/deckhouse/deckhouse/main/modules/041-linstor/tools/evict.sh
      chmod 700 evict.sh
      
    • Также скрипт можно скачать из пода deckhouse:

      kubectl -n d8-system cp -c deckhouse $(kubectl -n d8-system get po -l app=deckhouse -o jsonpath='{.items[0].metadata.name}'):/deckhouse/modules/041-linstor/tools/evict.sh ./evict.sh
      chmod 700 evict.sh
      
  • Исправьте все ошибочные ресурсы LINSTOR в кластере. Чтобы найти их, выполните следующую команду:

    kubectl -n d8-linstor exec -ti deploy/linstor-controller -- linstor resource list --faulty
    
  • Убедитесь, что все поды в пространстве имен d8-linstor находятся в состоянии Running:

    kubectl -n d8-linstor get pods | grep -v Running
    

Выгнать ресурсы с узла без удаления его из LINSTOR и Kubernetes

Запустите скрипт evict.sh в интерактивном режиме, указав режим удаления --delete-resources-only:

./evict.sh --delete-resources-only

Для запуска скрипта evict.sh в неинтерактивном режиме необходимо добавить флаг --non-interactive при его вызове, а так же имя узла, с которого необходимо выгнать ресурсы. В этом режиме скрипт выполнит все действия без запроса подтверждения от пользователя. Пример вызова:

./evict.sh --non-interactive --delete-resources-only --node-name "worker-1"

Важно! После завершении работы скрипта узел в Kubernetes останется в статусе SchedulingDisabled, а в LINSTOR у данного узла будет выставлен параметр AutoplaceTarget=false, что запретит планировщику LINSTOR создавать на этом узле ресурсы.

Если необходимо снова разрешить размещать ресурсы и поды на узле, то необходимо выполнить команды:

alias linstor='kubectl -n d8-linstor exec -ti deploy/linstor-controller -- linstor'
linstor node set-property "worker-1" AutoplaceTarget
kubectl uncordon "worker-1"

Проверить параметр AutoplaceTarget у всех узлов можно так (поле AutoplaceTarget будет пустым у тех узлов, на которых разрешено размещать ресурсы LINSTOR):

alias linstor='kubectl -n d8-linstor exec -ti deploy/linstor-controller -- linstor'
linstor node list -s AutoplaceTarget

Выгнать ресурсы с узла с последующим его удалением из LINSTOR и Kubernetes

Запустите скрипт evict.sh в интерактивном режиме, указав режим удаления --delete-node:

./evict.sh --delete-node

Для запуска скрипта evict.sh в неинтерактивном режиме необходимо добавить флаг --non-interactive при его вызове, а так же имя узла, который необходимо удалить. В этом режиме скрипт выполнит все действия без запроса подтверждения от пользователя. Пример вызова:

./evict.sh --non-interactive --delete-node --node-name "worker-1"

Важно! В процессе выполнения скрипт удалит узел как из Kubernetes, так и из LINSTOR.

В этом режиме ресурсы физически с узла не удаляются. Для зачистки узла необходимо зайти на нее и выполнить следующие действия:

Внимание! Выполнение этих действий приведет к уничтожению всех ваших данных на узле.

  • Получите список групп томов (vg), которые использовались для LVM-пулов хранения LINSTOR, а затем удалите их с узла:

    vgs -o+tags | awk 'NR==1;$NF~/linstor-/'
    vgremove -y <имена групп томов (vg) из вывода предыдущей команды>
    
  • Получите список логических томов (lv), которые использовались для LVM_THIN пулов хранения LINSTOR, а затем удалите их с узла:

    lvs -o+tags | awk 'NR==1;$NF~/linstor-/'
    lvremove -y /dev/<имя группы томов (vg) из вывода предыдущей команды>/<имя логического тома(lv) из вывода предыдущей команды>
    
  • Следуйте инструкции, начиная со второго пункта для дальнейшей очистки узла.

Диагностика проблем

Проблемы могут возникнуть на разных уровнях работы компонентов. Эта простая шпаргалка поможет вам быстро сориентироваться при диагностике различных проблем с томами, созданными в LINSTOR:

LINSTOR шпаргалка

Некоторые типичные проблемы описаны ниже.

linstor-node не может запуститься из-за невозможности загрузки drbd-модуля

Проверьте состояние подов linstor-node:

kubectl get pod -n d8-linstor -l app=linstor-node

Если вы видите, что некоторые из них находятся в состоянии Init:CrashLoopBackOff, проверьте логи контейнера kernel-module-injector:

kubectl logs -n d8-linstor linstor-node-xxwf9 -c kernel-module-injector

Наиболее вероятные причины, почему он не может загрузить модуль ядра:

  • Возможно, у вас уже загружена in-tree-версия модуля DRBDv8, тогда как LINSTOR требует DRBDv9. Проверить версию загруженного модуля: cat /proc/drbd. Если файл отсутствует, значит, модуль не загружен и проблема не в этом.

  • Возможно, у вас включен Secure Boot. Так как модуль DRBD, который мы поставляем, компилируется динамически для вашего ядра (аналог dkms), он не имеет цифровой подписи. На данный момент мы не поддерживаем работу модуля DRBD в конфигурации с Secure Boot.

Под не может запуститься из-за ошибки FailedMount

Под завис на стадии ContainerCreating

Если под завис на стадии ContainerCreating, а в выводе kubectl describe pod есть ошибки вида:

rpc error: code = Internal desc = NodePublishVolume failed for pvc-b3e51b8a-9733-4d9a-bf34-84e0fee3168d: checking
for exclusive open failed: wrong medium type, check device health

значит, устройство все еще смонтировано на одном из других узлов.

Проверить это можно с помощью следующей команды:

linstor resource list -r pvc-b3e51b8a-9733-4d9a-bf34-84e0fee3168d

Флаг InUse укажет, на каком узле используется устройство.

Под не может запуститься из-за отсутствия CSI-драйвера

Пример ошибки в kubectl describe pod:

kubernetes.io/csi: attachment for pvc-be5f1991-e0f8-49e1-80c5-ad1174d10023 failed: CSINode b-node0 does not
contain driver linstor.csi.linbit.com

Проверьте состояние подов linstor-csi-node:

kubectl get pod -n d8-linstor -l app.kubernetes.io/component=csi-node

Наиболее вероятно, что они зависли в состоянии Init, ожидая, пока узел сменит статус на Online в LINSTOR. Проверьте список узлов с помощью следующей команды:

linstor node list

Если вы видите какие-либо узлы в состоянии EVICTED, значит, они были недоступны в течение 2 часов. Чтобы вернуть их в кластер, выполните:

linstor node rst <name>

Ошибки вида Input/Output error

Такие ошибки обычно возникают на стадии создания файловой системы (mkfs).

Проверьте dmesg на узле, где запускается под:

dmesg | grep 'Remote failed to finish a request within'

Если вывод команды не пустой (в выводе dmesg есть строки вида «Remote failed to finish a request within …»), скорее всего, ваша дисковая подсистема слишком медленная для нормального функционирования DRBD.