Стадия жизненного цикла модуля: Preview
У модуля есть требования для установки
Работоспособность модуля гарантируется только при соблюдении требований. Работоспособность модуля в других условиях возможна, но не гарантируется.
После включения модуля sds-replicated-volume в конфигурации Deckhouse, останется только создать ReplicatedStoragePool и ReplicatedStorageClass по инструкции ниже.
Конфигурация модуля
Конфигурацию выполняет контроллер sds-replicated-volume-controller с использованием пользовательских ресурсов ReplicatedStoragePool и ReplicatedStorageClass. Для создания Storage Pool требуется, чтобы на узлах кластера были заранее настроены LVMVolumeGroup и LVM Thin Pool. Настройку LVM обеспечивает модуль sds-node-configurator.
Настройка LVM
Примеры конфигурации можно найти в документации модуля sds-node-configurator. В результате настройки в кластере окажутся ресурсы LVMVolumeGroup, которые необходимы для дальнейшей конфигурации.
Работа с ресурсами ReplicatedStoragePool
Создание ресурса ReplicatedStoragePool
- Для создания
Storage Poolпользователь создает ресурс ReplicatedStoragePool и заполняет полеspec, указывая тип пула и используемые ресурсы LVMVolumeGroup.
Пример ресурса для классических LVM-томов (Thick):
apiVersion: storage.deckhouse.io/v1alpha1
kind: ReplicatedStoragePool
metadata:
name: data
spec:
type: LVM
lvmVolumeGroups:
- name: lvg-1
- name: lvg-2Пример ресурса для Thin-томов LVM:
apiVersion: storage.deckhouse.io/v1alpha1
kind: ReplicatedStoragePool
metadata:
name: thin-data
spec:
type: LVMThin
lvmVolumeGroups:
- name: lvg-3
thinPoolName: thin-pool
- name: lvg-4
thinPoolName: thin-poolПеред работой с бэкендом контроллер провалидирует предоставленную ему конфигурацию и в случае ошибки предоставит информацию о причинах неудачи.
Для всех ресурсов LVMVolumeGroup, указанных в spec ресурса ReplicatedStoragePool должны быть соблюдены следующие правила:
- Они должны быть на разных узлах. Запрещено указывать несколько ресурсов LVMVolumeGroup, которые расположены на одном и том же узле.
- Все узлы должны иметь тип отличный от
CloudEphemeral(см. Типы узлов)
Результатом обработки ресурса ReplicatedStoragePool станет создание необходимого Storage Pool в бэкенде. Имя созданного Storage Pool будет соответствовать имени созданного ресурса ReplicatedStoragePool. Узлы, на которых будет создан Storage Pool, будут взяты из ресурсов LVMVolumeGroup.
Результатом обработки ресурса ReplicatedStoragePool станет создание необходимого Storage Pool в бэкенде LINSTOR. Имя созданного Storage Pool будет соответствовать имени созданного ресурса ReplicatedStoragePool. Узлы, на которых будет создан Storage Pool, будут взяты из ресурсов LVMVolumeGroup.
Обновление ресурса ReplicatedStoragePool
После внесения изменений в ресурс, sds-replicated-volume-controller провалидирует новую конфигурацию и в случае валидных данных выполнит необходимые операции по обновлению Storage Pool в бэкенде. Результаты данной операции также будут отображены в поле status ресурса ReplicatedStoragePool.
Обратите внимание, что поле
spec.typeресурсаReplicatedStoragePoolнеизменяемое.Контроллер не реагирует на внесенные пользователем изменения в поле
statusресурса.
Удаление ресурса ReplicatedStoragePool
В настоящий момент sds-replicated-volume-controller никак не обрабатывает удаление ресурсов ReplicatedStoragePool.
Удаление ресурса никаким образом не затрагивает созданные по нему
Storage Poolв бэкенде. Если пользователь воссоздаст удаленный ресурс с тем же именем и конфигурацией, контроллер увидит, что соответствующиеStorage Poolсозданы, и оставит их без изменений, а в полеstatus.phaseсозданного ресурса будет отображено значениеCreated.
Работа с ресурсами ReplicatedStorageClass
Создание ресурса ReplicatedStorageClass
Для создания StorageClass в Kubernetes пользователь создает ресурс ReplicatedStorageClass и заполняет поле spec, указывая необходимые параметры. (Ручное создание StorageClass для CSI-драйвера replicated.csi.storage.deckhouse.io запрещено).
Пример ресурса для создания StorageClass c использованием только локальных томов (запрещены подключения к данным по сети) и обеспечением высокой степени резервирования данных в кластере, состоящем из трех зон:
apiVersion: storage.deckhouse.io/v1alpha1
kind: ReplicatedStorageClass
metadata:
name: haclass
spec:
storagePool: storage-pool-name
volumeAccess: Local
reclaimPolicy: Delete
topology: TransZonal
zones:
- zone-a
- zone-b
- zone-cПараметр replication не указан, поскольку по умолчанию его значение устанавливается в ConsistencyAndAvailability, что соответствует требованиям высокой степени резервирования.
Пример ресурса для создания StorageClass c разрешенными подключениями к данным по сети и без резервирования в кластере, где отсутствуют зоны (например, подходит для тестовых окружений):
apiVersion: storage.deckhouse.io/v1alpha1
kind: ReplicatedStorageClass
metadata:
name: testclass
spec:
replication: None
storagePool: storage-pool-name
reclaimPolicy: Delete
topology: IgnoredБольше примеров с различными сценариями использования и схемами описаны в документации
Перед процессом создания StorageClass запустится процесс валидации предоставленной конфигурации. В случае обнаружения ошибок StorageClass создан не будет, а в поле
statusресурса ReplicatedStorageClass отобразится информация об ошибке.
Результатом обработки ресурса ReplicatedStorageClass станет создание необходимого StorageClass в Kubernetes.
Обратите внимание, что большинство полей
specресурса ReplicatedStorageClass являются неизменяемыми после создания. Изменить у существующего ресурса можно только параметры репликации (replication,failuresToTolerate,guaranteedMinimumDataRedundancy),configurationRolloutStrategy,eligibleNodesConflictResolutionStrategy, а такжеreclaimPolicy(StorageClass при этом пересоздаётся с новой политикой); изменение любого другого поля (storage,topology,zones,volumeAccess,nodeLabelSelectorи т. д.) при обновлении будет отклонено.
Поле status будет обновляться sds-replicated-volume-controller'ом для отображения информации о результатах проводимых операций.
Обновление ресурса ReplicatedStorageClass
Большинство полей spec неизменяемы после создания, и попытка их изменить отклоняется с ошибкой, называющей поле; для изменения такого поля (например storage, topology, zones, volumeAccess, nodeLabelSelector) ресурс нужно пересоздать. Параметры репликации и reclaimPolicy изменяемы: правка replication позволяет выполнить миграцию r3→r2, описанную ниже, а правка reclaimPolicy заставляет модуль пересоздать StorageClass с новой политикой.
Миграция томов с трёх реплик (r3) на две реплики + tie-breaker (r2)
Изменение spec.replication у существующего ReplicatedStorageClass меняет целевой layout сразу у всех томов этого класса. Чтобы мигрировать с ConsistencyAndAvailability (три реплики данных, layout 3D) на Availability (две реплики данных плюс diskless tie-breaker, layout 2D+1TB):
-
Измените класс:
kubectl patch replicatedstorageclass <RSC_NAME> --type=merge -p '{"spec":{"replication":"Availability"}}' -
Контроллер мигрирует каждый том на месте: одна diskful-реплика ретайпится в tie-breaker (без полного ресинка и без переноса данных), её логический том освобождается. Прогресс по каждому тому виден через condition
MembershipLayoutConvergedи колонкуMembershipLayout:kubectl get replicatedvolume -o wide kubectl get replicatedvolume <RV_NAME> -o jsonpath='{.status.membershipLayout} {range .status.conditions[?(@.type=="MembershipLayoutConverged")]}{.status}/{.reason}{end}{"\n"}'Том мигрирован, когда
MembershipLayoutConverged=True/Converged, аstatus.membershipLayout=2D+1TB. -
Прогресс по классу в целом виден через condition
ConfigurationRolledOutи счётчикиstatus.volumes:kubectl get replicatedstorageclass <RSC_NAME> -o jsonpath='{.status.volumes}{"\n"}'Раскатка завершена, когда
ConfigurationRolledOut=True; это происходит ровно тогда, когдаstatus.volumes.pendingObservationиstatus.volumes.staleConfigurationоба равны0.Равенства
alignedиtotalждать не нужно. В раскатке участвуют только тома, берущие конфигурацию у класса; том, переведённый вspec.configurationMode: Manual, несёт собственную конфигурацию, поэтому класс ничего ему не раскатывает и его не ждёт. При этом такие тома продолжают учитываться вtotal, и раскатка класса завершается приalignedменьшеtotal.
Требования. Для layout 2D+1TB кроме двух diskful-узлов нужен узел под tie-breaker: не менее 3 узлов для топологии Ignored, не менее 3 зон для TransZonal либо не менее 3 узлов в зоне тома для Zonal. Это те же требования, что и для 3D, поэтому миграция r3→r2 их не повышает.
Раскатка только на новые тома. По умолчанию (configurationRolloutStrategy.type: RollingUpdate) правка конфигурации применяется ко всем томам класса. Чтобы она применялась только к вновь создаваемым томам, переключите стратегию на NewVolumesOnly:
kubectl patch replicatedstorageclass <RSC_NAME> --type=merge -p '{"spec":{"configurationRolloutStrategy":{"type":"NewVolumesOnly","rollingUpdate":null}}}'Тома, у которых конфигурация уже есть, сохраняют её. Такой том видит новую конфигурацию (класс не зависает в ожидании тома), но не применяет её, и репортит:
kubectl get replicatedvolume <RV_NAME> -o jsonpath='{range .status.conditions[?(@.type=="ConfigurationReady")]}{.status}/{.reason}: {.message}{end}{"\n"}'
# False/NewerConfigurationHeld: ... has a newer configuration (generation N); the volume keeps its configuration (generation M) ...Такие тома попадают в счётчик status.volumes.staleConfiguration класса, а ConfigurationRolledOut становится False/ConfigurationRolloutDisabled. Удержание намеренное и сохраняется, даже если удерживаемая конфигурация перестала соответствовать кластеру: чтобы выпустить том из этого состояния, переключите стратегию обратно на RollingUpdate (все удерживаемые тома раскатаются обычным путём) либо пересоздайте том. Переключение с RollingUpdate на NewVolumesOnly ничего не откатывает — уже применённая конфигурация остаётся применённой.
Ограничение параллельности раскатки. При RollingUpdate параметр configurationRolloutStrategy.rollingUpdate.maxParallel (по умолчанию 5) задаёт, сколько томов класса мигрируют одновременно:
kubectl patch replicatedstorageclass <RSC_NAME> --type=merge -p '{"spec":{"configurationRolloutStrategy":{"type":"RollingUpdate","rollingUpdate":{"maxParallel":2}}}}'Тома, которым ещё нужна новая конфигурация, упорядочены по имени, и свободные слоты занимают первые из них — сразу все, то есть при maxParallel: 2 первые два тома мигрируют параллельно. Слот освобождается, когда его том репортит MembershipLayoutConverged=True/Converged, и переходит к следующему имени в этом порядке. Ожидающие тома сохраняют собственную конфигурацию и репортят:
kubectl get replicatedvolume <RV_NAME> -o jsonpath='{range .status.conditions[?(@.type=="ConfigurationReady")]}{.status}/{.reason}: {.message}{end}{"\n"}'
# False/ConfigurationRolloutInProgress: ... rolls its configuration (generation N) out to at most 2 volume(s) at a time ...Ожидающие тома попадают в счётчик status.volumes.staleConfiguration класса, поэтому ConfigurationRolledOut остаётся False/ConfigurationRolloutInProgress, пока не мигрирует весь класс. Уменьшение maxParallel не останавливает уже мигрирующие тома — оно лишь не пускает в раскатку новые. Том, который не может сойтись на новой конфигурации (см. ограничения ниже), удерживает свой слот бессрочно, и в этом и состоит смысл параметра: он ограничивает не только скорость раскатки удачной правки, но и число томов, до которых доберётся неудачная.
Ограничения.
- Автоматического обратного пути нет: изменение
replicationв сторону большего числа реплик (r2→r3) репортится на каждом томе какMembershipLayoutConverged=False/TransitionUnsupportedи не выполняет никаких действий — требуется ручная разборка. - Откат правки, пока том ещё мигрирует, не отменяет уже запущенный перевод реплики в tie-breaker, и такой том больше не вернётся в
Convergedсам. В зависимости от момента отката том останется либо в раскладке2D+1TBпри желаемой3D(MembershipLayoutConverged=False/TransitionUnsupported), либо с репликой, у которойspec.typeзастрял в значенииTieBreaker, тогда как раскладка по-прежнему3D(MembershipLayoutConverged=False/Converging, имя реплики указано в сообщении condition). Данные не теряются ни в одном из случаев. Во втором случае реплику нужно восстановить одним патчем: вернутьspec.typeвDiskfulи одновременно вернуть поля backing volume (spec.lvmVolumeGroupName, а для thin-пула ещё иspec.lvmVolumeGroupThinPoolName), взяв значения изstatus.datamesh.membersтома. eligibleNodesConflictResolutionStrategy.rollingRepair.maxParallelпринимается, но не реализован: перенос томов с узлов, переставших быть eligible, не ограничивается по параллельности. Это другой параметр, не тотmaxParallelиз конфигурационной раскатки выше — он-то как раз работает.
Удаление ресурса ReplicatedStorageClass
Пользователь может удалить StorageClass в Kubernetes, удалив соответствующий ресурс ReplicatedStorageClass.
sds-replicated-volume-controller отреагирует на удаление ресурса и выполнит все необходимые операции для корректного удаления дочернего StorageClass.
sds-replicated-volume-controllerвыполнит удаление дочернего StorageClass только в случае, если в полеstatus.phaseресурса ReplicatedStorageClass будет указано значениеCreated. В иных случаях будет удалён только ресурс ReplicatedStorageClass, а дочерний StorageClass затронут не будет.
Дополнительные возможности для приложений
Размещение приложения «поближе» к данным (data locality)
В случае гиперконвергентной инфраструктуры может возникнуть задача по приоритетному размещению пода приложения на узлах, где необходимые ему данные хранилища расположены локально. Это позволит получить максимальную производительность хранилища.
Для решения этой задачи модуль предоставляет специальный планировщик учитывает размещение данных в хранилище и старается размещать под в первую очередь на тех узлах, где данные доступны локально. Данный планировщик назначается автоматически для любого пода, использующего тома sds-replicated-volume.
Data locality настраивается параметром volumeAccess при создании ресурса ReplicatedStorageClass.