image


В предыдущей статье я рассмотрел возможность создания отказоустойчивого NFS-сервера с помощью DRBD и Proxmox. Получилось довольно неплохо, но не будем останавливаться на достигнутом и теперь постараемся "выжать все соки" из нашей хранилки.


В этой статье я расскажу как подобным образом создать отказоустойчивый iSCSI-таргет, который при помощи LVM мы будем нарезать на маленькие кусочки и использовать под виртуальные машины.


Именно такой подход позволят снизить нагрузку и повысить скорость доступа к данным в несколько раз, это бывает особенно выгодно когда не требуется конкурентный доступ к данным, например в случае когда вам нужно организовать хранилище под виртуальные машины.


Пара слов о DRBD


DRBD достаточно простое и зрелое решение, код восьмой версии принят в состав ядра Linux. По сути представляет ссобой сетевое зеркало RAID1. В девятой версии появилась поддержка кворума и репликации с больше чем двумя нодами.


По сути он позволяет вам объединить блочные устройства на нескольких физических нодах в одно общее расшаренное по сети.


Используя DRBD можно добиться очень интересных кофигураций. Сегодня пойдет речь об iSCSI и LVM.


Подробнее о нем можете узнать прочитав мою предыдущую статью, где я подробно описал это решение.


Пара слов об iSCSI


iSCSI — это протокол доставки блочного устройства по сети.


В отличии от того же NBD он поддерживает авторизацию, без проблем отрабатывает сетевые сбои и поддерживает множество других полезных функций, а главное показывает очень хорошую производительность.


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


Пара слов об LVM


Стоит упомянуть, что у LINBIT существует собственное решение для Proxmox, оно должно работать из коробки и позволит добиться похожего результата, но в данной статье я не хотел бы заострять внимание только на Proxmox а описать некоторое более унивирсальное решение которое подойдет как для Proxmox так и для чего-нибудь еще, в данном примере proxmox используется только как средство оркестрации контейнеров, по сути вы можете заменить его на другое решение, например запускать контейнеры с таргетом в Kubernetes.


Что касается конкретно Proxmox, то он отлично работает с shared LUN и LVM, используя только собственные стандратные драйверы.


К плюсам LVM можно отнести то, что его использование не является чем-то революционно новым и недостаточно обкатанным, а наоборот, оно показывает сухую стабильность, что обычно и требуется от хранилища. Стоит упомянуть что LVM довольно активно используются и в других средах, например в OpenNebula или в Kubernetes и достаточно неплохо там поддерживается.


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


К сожалению, при выборе решения под хранилище всегда приходится идти на какие-нибудь компромиссы. Так и тут, данное решение не даст вам той-же гибкости как например Ceph.
Размер виртуального диска ограничен размером LVM-группы, а область размеченная под конкретный виртуальный диск обязательно будет преаллоцирована — это сильно улучшает скорость доступа к данным, но не дает возможности к Thin-Provisioning (когда виртуальный диск занимает меньше места чем есть на самом деле). Стоит упомянуть что производительность LVM достаточно сильно проседает при использовании снапшотов, в связи с чем возможность свободного их использования, часто исключается.


Да, LVM поддерживает Thin-Provision пулы, которые лишены данного недостатка, но к сожалению их использование возможно только в контексте одной ноды и нет возможности расшарить один Thin-Provision пул на несколько нод в кластере.


Но несмотря на эти недостатки, из-за своей простоты LVM по прежнему не дает возможности конкурентам обойти его и полностью вытеснить с поля боя.


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


Общая схема


  • У нас есть три ноды
  • На каждой ноде распределенное drbd-устройство.
  • Поверх drbd-устройства запущен LXC-контейнер с iSCSI-таргетом.
  • Таргет подключен ко всем трем нодам.
  • На подключенном таргете создана LVM-группа.
  • При необходимости LXC-конейнер может переехать на другую ноду, вместе с iSCSI-таргетом

Настройка


С идеей разобрались теперь перейдем к реализации.


По умолчанию в комплекте с ядром Linux поставляется модуль восьмой версии drbd, к сожалению он нам не подходит и нам необходимо установить модуль девятой версии.


Подключим репозиторий LINBIT и установим все необходимое:


wget -O- https://packages.linbit.com/package-signing-pubkey.asc | apt-key add - 
echo "deb http://packages.linbit.com/proxmox/ proxmox-5 drbd-9.0"   > /etc/apt/sources.list.d/linbit.list

apt-get update && apt-get -y install pve-headers drbd-dkms drbd-utils drbdtop

  • pve-headers — заголовки ядра необходимые для сборки модуля
  • drbd-dkms — модуль ядра в формате DKMS
  • drbd-utils — основные утилиты для управления DRBD
  • drbdtop — интерактивный инструмент, как top только для DRBD

После установки модуля проверим, все ли с ним в порядке:


# modprobe drbd
# cat /proc/drbd 
version: 9.0.14-1 (api:2/proto:86-113)

Если вы увидите в выводе команды восьмую версию значит что-то пошло не так и загружен in-tree модуль ядра. Проверьте dkms status что-бы разобраться в чем причина.


Каждая нода у нас будет иметь одно и тоже drbd-устройство запущенное поверх обычных разделов. Для начала нам нужно подготовить этот раздел под drbd на каждой ноде.


В качестве такого раздела может выступать любое блочное устройство, это может быть lvm, zvol, раздел диска или весь диск целиком. В этой статье я буду использовать отдельный nvme диск с разделом под drbd: /dev/nvme1n1p1


Стоит заметить, что имена устройств имеют свойство иногда меняться, так что лучше сразу взять за привычку использовать постоянный симлинк на устройство.


Найти такой симлинк для /dev/nvme1n1p1 можно таким образом:


# find /dev/disk/ -lname '*/nvme1n1p1'
/dev/disk/by-partuuid/847b9713-8c00-48a1-8dff-f84c328b9da2
/dev/disk/by-path/pci-0000:0e:00.0-nvme-1-part1
/dev/disk/by-id/nvme-eui.0000000001000000e4d25c33da9f4d01-part1
/dev/disk/by-id/nvme-INTEL_SSDPEKKA010T7_BTPY703505FB1P0H-part1

Опишем наш ресурс на всех трех нодах:


# cat /etc/drbd.d/tgt1.res
resource tgt1 {
  meta-disk internal;
  device    /dev/drbd100;
  protocol  C;
  net { 
    after-sb-0pri discard-zero-changes;
    after-sb-1pri discard-secondary;
    after-sb-2pri disconnect;
  }
  on pve1 {
    address   192.168.2.11:7000;
    disk      /dev/disk/by-partuuid/95e7eabb-436e-4585-94ea-961ceac936f7;
    node-id   0;
  }
  on pve2 {
    address   192.168.2.12:7000;
    disk      /dev/disk/by-partuuid/aa7490c0-fe1a-4b1f-ba3f-0ddee07dfee3;
    node-id   1;
  }
  on pve3 {
    address   192.168.2.13:7000;
    disk      /dev/disk/by-partuuid/847b9713-8c00-48a1-8dff-f84c328b9da2;
    node-id   2;
  }
  connection-mesh {
    hosts pve1 pve2 pve3;
  }
}

Желательно для синхронизации drbd использовать отдельную сеть.


Теперь создадим метаданные для drbd и запустим его:


# drbdadm create-md tgt1
initializing activity log
initializing bitmap (320 KB) to all zero
Writing meta data...
New drbd meta data block successfully created.
success
# drbdadm up tgt1

Повторим эти действия на всех трех нодах и проверим состояние:


# drbdadm status
tgt1 role:Secondary
  disk:Inconsistent
  pve2 role:Secondary
    peer-disk:Inconsistent
  pve3 role:Secondary
    peer-disk:Inconsistent

Сейчас наш диск Inconsistent на всех трех нодах, это потому, что drbd не знает какой диск должен быть взят в качестве оригинала. Мы должны пометить один из них как Primary, что бы его состояние синхронизировалось на остальные ноды:


drbdadm primary --force tgt1
drbdadm secondary tgt1

Сразу после этого начнется синхронизация:


# drbdadm status
tgt1 role:Secondary
  disk:UpToDate
  pve2 role:Secondary
    replication:SyncSource peer-disk:Inconsistent done:26.66
  pve3 role:Secondary
    replication:SyncSource peer-disk:Inconsistent done:14.20

Нам не обязательно дожидаться ее окончания и мы можем параллельно выполнять дальнейшие шаги. Их можно выполнять на любой ноде, вне зависимости от ее текущего состояния локального диска в DRBD. Все запросы будут автоматически перенаправлены на устройство с UpToDate состоянием.


Стоит не забыть активировать автозапуск drbd-сервиса на нодах:


systemctl enable drbd.service

Настройка LXC-контейнера


Опустим часть настройки кластера Proxmox из трех нод, эта часть хорошо описана в официальной wiki


Как я говорил раньше наш iSCSI-таргет будет работать в LXC-контейнере. Сам контейнер мы будем держать на устройстве /dev/drbd100, которое мы только что создали.


Сначала нам нужно создать файловую систему на нем:


mkfs -t ext4 -O mmp -E mmp_update_interval=5 /dev/drbd100

Proxmox по умолчанию включает multimount protection на уровне файловой системы, в принципе мы можем обойтись и без нее, т.к. DRBD по умолчанию имеет собственную защиту, он просто запретит второй Primary для устройства, но осторожность нам не повредит.


Теперь скачаем шаблон Ubuntu:


# wget http://download.proxmox.com/images/system/ubuntu-16.04-standard_16.04-1_amd64.tar.gz -P /var/lib/vz/template/cache/

И создадим из него наш контейнер:


pct create 101 local:vztmpl/ubuntu-16.04-standard_16.04-1_amd64.tar.gz   --hostname=tgt1   --net0=name=eth0,bridge=vmbr0,gw=192.168.1.1,ip=192.168.1.11/24   --rootfs=volume=/dev/drbd100,shared=1

В данной команде мы указываем что корневая система нашего контейнера будет находиться на устройстве /dev/drbd100 и добавим параметр shared=1 что бы разрешить миграцию контейнера между нодами.


Если что-то пошло не так, вы всегда можете поправить это через интерфейс Proxmox или в конфиге контейнера /etc/pve/lxc/101.conf


Proxmox распакует шаблон и подготовит корневую систему контейнера для нас. После этого мы можем запустить наш контейнер:


pct start 101

Настройка iSCSI-таргета.


Из всего множества таргетов я выбрал istgt, так как он обладает наибольшей производительностью и работает в пространстве пользователя.


Теперь давайте залогинимся в наш контейнер:


pct exec 101 bash

Установим обновления и istgt:


apt-get update 
apt-get -y upgrade
apt-get -y install istgt

Создадим файл который мы и будем отдавать по сети:


mkdir -p /data
fallocate -l 740G /data/target1.img

Теперь нам нужно написать конфиг для istgt /etc/istgt/istgt.conf:


[Global]
  Comment "Global section"
  NodeBase "iqn.2018-07.org.example.tgt1"
  PidFile /var/run/istgt.pid
  AuthFile /etc/istgt/auth.conf
  MediaDirectory /var/istgt
  LogFacility "local7"
  Timeout 30
  NopInInterval 20
  DiscoveryAuthMethod Auto
  MaxSessions 16
  MaxConnections 4
  MaxR2T 32
  MaxOutstandingR2T 16
  DefaultTime2Wait 2
  DefaultTime2Retain 60
  FirstBurstLength 262144
  MaxBurstLength 1048576
  MaxRecvDataSegmentLength 262144
  InitialR2T Yes
  ImmediateData Yes
  DataPDUInOrder Yes
  DataSequenceInOrder Yes
  ErrorRecoveryLevel 0
[UnitControl]
  Comment "Internal Logical Unit Controller"
  AuthMethod CHAP Mutual
  AuthGroup AuthGroup10000
  Portal UC1 127.0.0.1:3261
  Netmask 127.0.0.1
[PortalGroup1]
  Comment "SINGLE PORT TEST"
  Portal DA1 192.168.1.11:3260
[InitiatorGroup1]
  Comment "Initiator Group1"
  InitiatorName "ALL"
  Netmask 192.168.1.0/24
[LogicalUnit1]
  Comment "Hard Disk Sample"
  TargetName disk1
  TargetAlias "Data Disk1"
  Mapping PortalGroup1 InitiatorGroup1
  AuthMethod Auto
  AuthGroup AuthGroup1
  UseDigest Auto
  UnitType Disk
  LUN0 Storage /data/target1.img Auto

Перезапустим istgt:


systemctl restart istgt

На этом настройка таргета закончена


Настройка HA


Теперь мы можем перейти к кофигурации HA-manager. Создадим отдельную HA-группу для нашего устройства:


ha-manager groupadd tgt1 --nodes pve1,pve2,pve3 --nofailback=1 --restricted=1

Наш ресурс будет работать только на нодах указанных для этой группы. Добавим наш контейнер в эту группу:


ha-manager add ct:101 --group=tgt1 --max_relocate=3 --max_restart=3

Рекомендации и тюнинг


Так как мы не используем multipathing, в нашем случае рекомендуется отключить переодические проверки соединения на клиентах, а так же увеличить таймауты ожидания для восстановления сессии в /etc/iscsi/iscsid.conf.


node.conn[0].timeo.noop_out_interval = 0
node.conn[0].timeo.noop_out_timeout = 0
node.session.timeo.replacement_timeout = 86400

Использование


Proxmox


Полученный iSCSI-таргет можно сразу-же подключить в Proxmox, не забыв снять галочку с Use LUN Directly.



Сразу после этого станет возможным создание LVM поверх него, не забудьте поставить галочку напротив shared:



Другие среды


Если вы планируете использовать это решение в другой среде возможно вам потребуется установить кластерное расширение для LVM на данный момент из существует две реализации. CLVM и lvmlockd.


Настройка CLVM не совесм тривиальна и требует работающего кластер менеджера.
Куда как второй метод lvmlockd — еще не до конца протестирован и только-только начинает появляться в стабильных репозиториях.


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


При использовании LVM с Proxmox кластерное дополнение не требуется, так как управление томами обеспечивается самим proxmox, который обновляет и следит за метаданными LVM самостоятельно. Тоже касается и OpenNebula, на что явно указывает официальная документация.

Комментарии (4)


  1. MagicGTS
    22.08.2018 22:05

    LVM уже давольно давно умеет ThinProvision, где нет проблем с производительностью снапшотов.


    1. kvaps Автор
      22.08.2018 22:34

      Да, но LVM не поддерживает конкурентный доступ к thin-provision пулу с нескольких нод.
      Есть способ под каждую виртуалку генерить отдельный thin-provision пул в общем LVM, правда это не в контексте проксмоса уже.


      1. MagicGTS
        23.08.2018 07:47

        Тогда фразу в статье стоит изменить. А то создалось впичатление, что вы не знали про ThinProvision, а вопрос был в поддержке кластеризации.


        1. kvaps Автор
          23.08.2018 10:29

          Спасибо за замечание, поправил.