Настройка выделенной сети для LINSTOR
В этом руководстве описано, как повысить надёжность и производительность хранилища, перенаправив трафик репликации LINSTOR на выделенный сетевой интерфейс.
Введение
Платформа Cozystack создана для поддержки высокодоступных (HA) рабочих нагрузок, а значит, система должна продолжать работать, даже если один или несколько узлов выйдут из строя. Kubernetes хорошо справляется с этим для нагрузок без сохранения состояния (stateless). Однако нагрузкам с сохранением состояния (stateful), таким как файловые хранилища или диски виртуальных машин, требуется надёжная система хранения.
Когда вы выбираете класс хранения replicated для PersistentVolumeClaim (PVC) или DataVolume,
LINSTOR создаёт несколько синхронных реплик данных на разных узлах.
Благодаря этому при отказе узла (из-за отключения питания, проблем с оборудованием и т.п.)
данные мгновенно остаются доступными на другом узле.
За такой уровень надёжности приходится платить: репликация хранилища может создавать значительный сетевой трафик в зависимости от интенсивности рабочей нагрузки.
Если у узлов несколько сетевых интерфейсов, производительность можно повысить, выделив один из них под трафик хранилища. Это изолирует трафик репликации от остальных нагрузок и предотвращает возможные узкие места в сети.
Когда нужна выделенная сеть для хранилища?
Не всегда необходимо настраивать выделенную сеть для трафика хранилища с самого начала. В небольших кластерах и кластерах для проверки концепции (PoC) стандартной конфигурации сети, как правило, достаточно. Преждевременная оптимизация может привести к неоправданному усложнению.
Однако в более крупных кластерах трафик репликации хранилища часто становится узким местом производительности. Он может исчерпать доступную пропускную способность и мешать другим нагрузкам, использующим ту же сеть.
Если у узлов только один сетевой интерфейс и вы не уверены, нужен ли выделенный интерфейс, начните с наблюдения за фактическим трафиком хранилища под реалистичной нагрузкой. Один из практичных подходов - выделить VLAN на существующем интерфейсе под трафик репликации хранилища. Это позволит отслеживать использование пропускной способности без добавления оборудования.
Если уровень трафика остаётся стабильно высоким или влияет на производительность приложений, переход на выделенную сеть становится оправданной оптимизацией.
Термины и определения
Прежде чем продолжить, полезно уточнить терминологию, используемую для сетевых интерфейсов в конфигурации на основе LINSTOR:
Маршрут по умолчанию узла Kubernetes
Это маршрут по умолчанию, используемый для исходящего трафика узла. Его можно посмотреть командойip route show default.IP-адрес источника по умолчанию узла Kubernetes
Это IP-адрес, связанный с маршрутом по умолчанию. Обычно это адрес источника для всего исходящего трафика; его можно проверить той же командой.Внутренний IP-адрес узла Kubernetes
Это адрес, используемый Kubernetes для внутреннего взаимодействия. Часто он совпадает с адресом источника по умолчанию, но не всегда. Его можно проверить командойkubectl get nodes -o wide.Интерфейс по умолчанию LINSTOR satellite
Здесь конфигурация становится менее очевидной. Когда оператор Piraeus запускает LINSTOR Satellite, он задаёт один или два интерфейса по умолчанию:default-ipv4иdefault-ipv6. Как правило, доступен только IPv4. Интерфейс по умолчанию устанавливается в IP-адрес источника по умолчанию узла при запуске и не меняется до перезапуска Satellite. Этот интерфейс можно изменить во время работы Satellite, но оператор Piraeus сбросит его при следующем перезапуске.Дополнительные интерфейсы LINSTOR satellite
К LINSTOR Satellite можно вручную добавить дополнительные интерфейсы. Они хранятся в базе данных контроллера LINSTOR и сохраняются между перезапусками. Оператор Piraeus не изменяет и не удаляет их. На момент написания оператор Piraeus не поддерживает объявление дополнительных интерфейсов через пользовательские ресурсы Kubernetes.Активное подключение LINSTOR satellite
Контроллер LINSTOR использует ровно один интерфейс для взаимодействия с каждым Satellite. По умолчанию это интерфейсdefault-ipv4. Хотя CLI LINSTOR позволяет его изменить, оператор Piraeus вернёт его обратно при следующем перезапуске Satellite.Соединение узлов LINSTOR (путь)
Оно определяет, как LINSTOR Satellite взаимодействуют друг с другом при синхронной репликации. Именно эту настройку мы будем выполнять в данном руководстве. Соединения узлов можно определять либо через CRD Piraeus, либо командами CLI. Оператор Piraeus не управляет ими и не переопределяет их. При этом приоритет имеет конфигурация, применённая последней.
Как назначаются IP-адреса по умолчанию
Вот типичный вывод node list в LINSTOR:
LINSTOR ==> node list
╭───────────────────────────────────────────────────────╮
┊ Node ┊ NodeType ┊ Addresses ┊ State ┊
╞═══════════════════════════════════════════════════════╡
┊ node01 ┊ SATELLITE ┊ 10.78.22.146:3367 (SSL) ┊ Online ┊
┊ node02 ┊ SATELLITE ┊ 10.78.22.37:3367 (SSL) ┊ Online ┊
┊ node03 ┊ SATELLITE ┊ 10.78.22.53:3367 (SSL) ┊ Online ┊
┊ node04 ┊ SATELLITE ┊ 10.78.22.230:3367 (SSL) ┊ Online ┊
┊ node05 ┊ SATELLITE ┊ 10.78.22.150:3367 (SSL) ┊ Online ┊
╰───────────────────────────────────────────────────────╯
Эти IP-адреса обычно совпадают с внутренними IP-адресами узлов Kubernetes и адресами маршрута по умолчанию. По умолчанию именно они используются для трафика репликации хранилища.
Может показаться, что достаточно изменить их, чтобы перенаправить трафик хранилища на другой интерфейс. Однако это не сработает.
Оператор Piraeus получает текущий IP-адрес пода Satellite при каждом перезапуске. Затем он использует этот IP - как правило, внутренний адрес узла Kubernetes - для настройки интерфейса LINSTOR по умолчанию.
Даже если попытаться изменить внутренний IP-адрес Kubernetes, трафик репликации хранилища не перейдёт на другой интерфейс. Более того, такое изменение затронет весь трафик узла, а не только репликацию LINSTOR.
Чтобы корректно изолировать трафик хранилища от остальных нагрузок, используйте соединения узлов, как описано в следующем разделе.
Интерфейсы Satellite
По умолчанию LINSTOR настраивает только один интерфейс на каждый satellite: default-ipv4,
полученный из IP-адреса по умолчанию узла Kubernetes.
Вот пример того, как выглядит список интерфейсов по умолчанию LINSTOR satellite:
LINSTOR ==> node interface list node01
╭─────────────────────────────────────────────────────────────────╮
┊ node01 ┊ NetInterface ┊ IP ┊ Port ┊ EncryptionType ┊
╞═════════════════════════════════════════════════════════════════╡
┊ + StltCon ┊ default-ipv4 ┊ 10.78.22.146 ┊ 3367 ┊ SSL ┊
╰─────────────────────────────────────────────────────────────────╯
Этот IP берётся с узла Kubernetes при запуске Satellite. Если на узле есть дополнительные интерфейсы, автоматически они не добавляются.
Чтобы разрешить трафик хранилища через другую сеть, можно вручную добавить второй интерфейс:
LINSTOR ==> node interface create node01 optic-san 10.78.24.201
SUCCESS:
Description:
New netInterface 'optic-san' on node 'node01' registered.
Details:
NetInterface 'optic-san' on node 'node01' UUID is: aa28f583-ca91-4cac-b749-67fe54e72c10
LINSTOR ==> node interface list node01
╭─────────────────────────────────────────────────────────────────╮
┊ node01 ┊ NetInterface ┊ IP ┊ Port ┊ EncryptionType ┊
╞═════════════════════════════════════════════════════════════════╡
┊ + StltCon ┊ default-ipv4 ┊ 10.78.22.146 ┊ 3367 ┊ SSL ┊
┊ + ┊ optic-san ┊ 10.78.24.201 ┊ ┊ ┊
╰─────────────────────────────────────────────────────────────────╯
Знать имя базового сетевого интерфейса Linux не обязательно. Можно использовать любое имя - LINSTOR не проверяет, действительно ли этот IP назначен узлу.
Флагом StltCon помечен только интерфейс default-ipv4.
Это означает, что именно его контроллер LINSTOR использует для взаимодействия с Satellite.
Хотя активное подключение Satellite можно изменить вручную через CLI LINSTOR, оператор Piraeus сбросит его при следующем перезапуске. Это поведение относится только к установкам вне Kubernetes.
Чтобы использовать новый интерфейс для репликации хранилища, нужно определить соединения узлов. Но сначала повторите создание интерфейса на остальных узлах:
LINSTOR ==> node interface create node02 optic-san 10.78.24.202
LINSTOR ==> node interface create node03 optic-san 10.78.24.203
LINSTOR ==> node interface create node04 optic-san 10.78.24.204
LINSTOR ==> node interface create node05 optic-san 10.78.24.205
Соединения узлов
Соединения узлов LINSTOR определяют, как satellite взаимодействуют друг с другом при синхронной репликации данных. Для каждой пары satellite должен быть определён путь соединения.
В отличие от интерфейсов satellite, соединения узлов можно определять как вручную через CLI, так и декларативно через пользовательские ресурсы Kubernetes. Для небольших кластеров создание соединений вручную обычно не вызывает трудностей. Однако по мере роста кластера эффективнее использовать соглашение об именовании и описать все пути соединений в одном определении ресурса.
В следующих разделах рассматриваются оба подхода.
Ручной способ
Соединения узлов можно создать вручную с помощью CLI LINSTOR. Вот как посмотреть синтаксис команды:
LINSTOR ==> node-connection path create -h
usage: linstor node-connection path create [-h]
node_a node_b path_name
netinterface_a netinterface_b
Creates a new node connection path.
positional arguments:
node_a 1. Node of the connection
node_b 2. Node of the connection
path_name Name of the created path
netinterface_a Netinterface name to use for 1. node
netinterface_b Netinterface name to use for the 2. node
Пример: создание соединения между node01 и node02 с использованием интерфейса optic-san с обеих сторон:
LINSTOR ==> node-connection path create node01 node02 node01-02 optic-san optic-san
SUCCESS:
Successfully set property key(s): Paths/node01-02/node01,Paths/node01-02/node02
SUCCESS:
Description:
Node connection between nodes 'node01' and 'node02' modified.
Details:
Node connection between nodes 'node01' and 'node02' UUID is: c1f4ee6a-776e-46ba-9e74-99afce38d90f
SUCCESS:
(node02) Node changes applied.
SUCCESS:
(node02) Resource '`pvc-6f535d3a-82c1-46ab-80fe-5a59ee8bff44`' [DRBD] adjusted.
....
После создания соединения LINSTOR сразу обновляет все затронутые ресурсы DRBD, чтобы они использовали новый путь.
Путь создаётся один раз для каждой пары узлов. Определять отдельный обратный путь не нужно.
Проверить конфигурацию можно так:
LINSTOR ==> node-connection path list node01 node02
╭────────────────────────────────────╮
┊ Key ┊ Value ┊
╞════════════════════════════════════╡
┊ Paths/node01-02/node01 ┊ optic-san ┊
┊ Paths/node01-02/node02 ┊ optic-san ┊
╰────────────────────────────────────╯
LINSTOR ==> node-connection path list node02 node01
╭────────────────────────────────────╮
┊ Key ┊ Value ┊
╞════════════════════════════════════╡
┊ Paths/node01-02/node01 ┊ optic-san ┊
┊ Paths/node01-02/node02 ┊ optic-san ┊
╰────────────────────────────────────╯
LINSTOR ==> node-connection list node01 node02
╭─────────────────────────────────────────────────────╮
┊ Node A ┊ Node B ┊ Properties ┊
╞═════════════════════════════════════════════════════╡
┊ node01 ┊ node02 ┊ node01=optic-san,node02=optic-... ┊
╰─────────────────────────────────────────────────────╯
LINSTOR ==> node-connection list node02 node01
╭─────────────────────────────────────────────────────╮
┊ Node A ┊ Node B ┊ Properties ┊
╞═════════════════════════════════════════════════════╡
┊ node01 ┊ node02 ┊ node01=optic-san,node02=optic-... ┊
╰─────────────────────────────────────────────────────╯
Способ с CRD
Рассмотрим способ с использованием Kubernetes CRD (Custom Resource Definition).
На момент написания у оператора Piraeus есть известная проблема с обработкой отсутствующих интерфейсов. Между попытками согласования нет задержки (backoff). Если отсутствует хотя бы один интерфейс, контроллер может потреблять 100% своего лимита CPU.
Всегда проверяйте, что все необходимые интерфейсы существуют, прежде чем применять CRD. Следите за подом контроллера, чтобы убедиться, что после изменения он не перегружен.
С увеличением числа узлов количество необходимых соединений быстро растёт. Для 3 узлов нужно 3 соединения. Для 5 узлов - 10. Для 10 узлов - 45, и так далее.
Вместо создания каждого соединения вручную можно определить все пути сразу с помощью одного пользовательского ресурса LinstorNodeConnection.
Для использования этого способа должны выполняться следующие условия:
- На всех участвующих узлах интерфейс должен называться одинаково.
- Интерфейс должен быть создан на всех узлах до применения CRD.
Пример пользовательского ресурса LinstorNodeConnection:
apiVersion: piraeus.io/v1
kind: LinstorNodeConnection
metadata:
name: dedicated
spec:
paths:
- name: dedicated
interface: optic-san
Примените CRD командой:
kubectl apply -f linstor-node-connections.yaml
После применения можно проверить соединения:
LINSTOR ==> node-connection list
╭─────────────────────────────────────────────────────╮
┊ Node A ┊ Node B ┊ Properties ┊
╞═════════════════════════════════════════════════════╡
┊ node01 ┊ node02 ┊ last-applied=["Paths/dedicated... ┊
┊ node01 ┊ node03 ┊ last-applied=["Paths/dedicated... ┊
┊ node01 ┊ node04 ┊ last-applied=["Paths/dedicated... ┊
┊ node01 ┊ node05 ┊ last-applied=["Paths/dedicated... ┊
┊ node02 ┊ node03 ┊ last-applied=["Paths/dedicated... ┊
┊ node02 ┊ node04 ┊ last-applied=["Paths/dedicated... ┊
┊ node02 ┊ node05 ┊ last-applied=["Paths/dedicated... ┊
┊ node03 ┊ node04 ┊ last-applied=["Paths/dedicated... ┊
┊ node03 ┊ node05 ┊ last-applied=["Paths/dedicated... ┊
┊ node04 ┊ node05 ┊ last-applied=["Paths/dedicated... ┊
╰─────────────────────────────────────────────────────╯
Старые пути, созданные вручную, могут по-прежнему отображаться. Приоритет имеет соединение, применённое последним.
В этом примере видны старые пути для node01 и node02:
LINSTOR ==> node-connection path list node01 node02
╭────────────────────────────────────╮
┊ Key ┊ Value ┊
╞════════════════════════════════════╡
┊ Paths/dedicated/node01 ┊ optic-san ┊
┊ Paths/dedicated/node02 ┊ optic-san ┊
┊ Paths/node01-02/node01 ┊ optic-san ┊
┊ Paths/node01-02/node02 ┊ optic-san ┊
╰────────────────────────────────────╯
LINSTOR ==> node-connection path list node01 node03
╭────────────────────────────────────╮
┊ Key ┊ Value ┊
╞════════════════════════════════════╡
┊ Paths/dedicated/node01 ┊ optic-san ┊
┊ Paths/dedicated/node03 ┊ optic-san ┊
╰────────────────────────────────────╯
Чтобы конфигурация оставалась аккуратной, старый ручной путь можно удалить:
LINSTOR ==> linstor node-connection path delete node01 node02 node01-02
SUCCESS:
Successfully deleted property key(s): Paths/node01-02/node02,Paths/node01-02/node01
....
После удаления:
LINSTOR ==> node-connection path list node01 node02
╭────────────────────────────────────╮
┊ Key ┊ Value ┊
╞════════════════════════════════════╡
┊ Paths/dedicated/node01 ┊ optic-san ┊
┊ Paths/dedicated/node02 ┊ optic-san ┊
╰────────────────────────────────────╯
Расширенный способ с CRD
См. пример в руководстве Выделенная сеть хранилища для нескольких дата-центров