Pull to refresh

Создание надёжного iSCSI-хранилища на Linux, часть 2

Reading time 10 min
Views 25K
Часть первая

Продолжаем


Продолжаем создание кластера, начатое первой части.
На этот раз я расскажу про настройку кластера.

В прошлый раз мы закончили на том, что началась синхронизация DRBD.
Если мы в качестве Primary сервера для обоих ресурсов выбрали один и тот же сервер, то после завершения синхронизации должны в /proc/drbd увидеть примерно такую картину:
# cat /proc/drbd
version: 8.4.3 (api:1/proto:86-101)
GIT-hash: 89a294209144b68adb3ee85a73221f964d3ee515 build by root@debian-service, 2013-04-30 07:43:49
 0: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate B r-----
    ns:0 nr:190397036 dw:190397036 dr:1400144904 al:0 bm:4942 lo:0 pe:0 ua:0 ap:0 ep:1 wo:d oos:0
 1: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate B r-----
    ns:0 nr:720487828 dw:720485956 dr:34275816 al:0 bm:3749 lo:468 pe:0 ua:0 ap:0 ep:1 wo:d oos:0

Самое интересное поле тут ds:UpToDate/UpToDate, означающее что и локальная и удаленная копия актуальны.

После этого переведем ресурсы в secondary режим — дальше ими будет управлять кластер:
# drbdadm secondary VM_STORAGE_1
# drbdadm secondary VM_STORAGE_2

Pacemaker


Итак, менеджер кластера.

Если коротко, то это мозг всей системы, который управляет абстракциями, называемыми ресурсами.
Ресурсом кластера может быть, в принципе, что угодно: IP-адреса, файловые системы, DRBD-устройства, программы-службы и так далее. Довольно просто создать свой ресурс, что мне и пришлось сделать для управления iSCSI таргетами и LUN-ами, об этом далее.

Установим:
# apt-get install pacemaker

Corosync

Pacemaker использует инфраструктуру Corosync для взаимодействия между узлами кластера, поэтому для начала нужно будет настроить её.

Corosync имеет достаточно широкий функционал и несколько режимов для поддержки связи между нодами (unicast, multicast, broadcast), имеет поддержку RRP (Redundant Ring Protocol), которая позволяет использовать несколько разных путей для общения между нодами кластера для минимизации риска получить Split-brain, то есть ситуации, когда связь между нодами полностью пропадает, и они обе считают что сосед умер. В результате обе ноды переходят в рабочий режим и начинается хаос :)

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

Приступим к настройке

Для начала нужно сгенерировать ключ авторизации:
# corosync-keygen

Его нужно положить под именем /etc/corosync/authkey на оба сервера.

Далее создадим конфиг, он должен быть идентичен на обоих нодах:

/etc/corosync/corosync.conf
compatibility: none

totem {
    version: 2
    
    secauth: on
    threads: 3
    
    rrp_mode: active
    
    transport: udpu
    
    interface {
        member {
            memberaddr: 10.1.0.100
        }

        member {
            memberaddr: 10.1.0.200
        }

        ringnumber: 0
        bindnetaddr: 10.1.0.0
        mcastport: 5405
        ttl: 1
    }
    
    interface {
        member {
            memberaddr: 192.168.123.100
        }

        member {
            memberaddr: 192.168.123.200
        }

        ringnumber: 1
        bindnetaddr: 192.168.123.0
        mcastport: 5407
        ttl: 1
    }
}

amf {
    mode: disabled
}

service {
    ver:       1
    name:      pacemaker
}

aisexec {
    user:   root
    group:  root
}

logging {
    syslog_priority: warning
    
    fileline: off
    to_stderr: yes
    to_logfile: no
    to_syslog: yes
    syslog_facility: daemon
    debug: off
    timestamp: on
    
    logger_subsys {
        subsys: AMF
        debug: off
        tags: enter|leave|trace1|trace2|trace3|trace4|trace6
    }
}

Тут мы описываем два кольца для связи — внутреннее (через порты репликации) и внешнее (через коммутаторы), выбираем протокол udpu (UDP Unicast) и указываем IP-адреса нод в каждом кольце. У меня еще была идея соединить ноды нуль-модемным кабелем, поднять PPP-соединение и пустить через него третье кольцо, но здравый смысл вовремя подсказал что и так сойдёт.

Всё, можно запускать Pacemaker (он запустит Corosync предварительно).
# /etc/init.d/pacemaker start

Вся настройка Pacemaker происходит через утилиту crm, причем запускать её можно на любом сервере в кластере — он автоматически обновит конфигурацию на всех нодах после изменения.

Посмотрим текущий статус:
# crm status
============
Last updated: Mon Jan 20 15:33:29 2014
Last change: Fri Jan 17 18:30:48 2014 via cibadmin on server1
Stack: openais
Current DC: server1 - partition WITHOUT quorum
Version: 1.1.7-ee0730e13d124c3d58f00016c3376a1de5323cff
2 Nodes configured, 2 expected votes
0 Resources configured.
============

Online: [ server1 server2 ]

Если всё примерно так, то связь установлена и ноды друг друга видят.

Теперь нам понадобятся ресурсы для управления SCST.
Я в свое время нашел их где-то на просторах интернета, модифицировал под свои нужды и выложил на Github.

Оттуда нам понадобятся два файла:
  • SCSTLun — управляет созданием устройств
  • SCSTTarget — управляет созданием iSCSI таргетов

Это, по сути, обычные bash-скрипты, реализующие несложный API Pacemaker.
Положить их следует в /usr/lib/ocf/resource.d/heartbeat, чтобы менеджер кластера их увидел.

Далее запускаем crm и входим в режим настройки:
# crm
crm(live)# configure
crm(live)configure# edit

Открывается текстовый редактор (обычно — nano) и можно приступить к описанию ресурсов и их взаимодействия.

Приведу пример конфигурации:
node server1
node server2

primitive DRBD_VM_STORAGE_1 ocf:linbit:drbd \
        params drbd_resource="VM_STORAGE_1" drbdconf="/etc/drbd.conf" \
        op monitor interval="29" role="Master" \
        op monitor interval="31" role="Slave"
primitive DRBD_VM_STORAGE_2 ocf:linbit:drbd \
        params drbd_resource="VM_STORAGE_2" drbdconf="/etc/drbd.conf" \
        op monitor interval="29" role="Master" \
        op monitor interval="31" role="Slave"

primitive IP_iSCSI_1_1 ocf:heartbeat:IPaddr2 \
        params ip="10.1.24.10" cidr_netmask="24" nic="int1.24" \
        op monitor interval="10s"
primitive IP_iSCSI_1_2 ocf:heartbeat:IPaddr2 \
        params ip="10.1.25.10" cidr_netmask="24" nic="int2.25" \
        op monitor interval="10s"
primitive IP_iSCSI_1_3 ocf:heartbeat:IPaddr2 \
        params ip="10.1.26.10" cidr_netmask="24" nic="int3.26" \
        op monitor interval="10s"
primitive IP_iSCSI_1_4 ocf:heartbeat:IPaddr2 \
        params ip="10.1.27.10" cidr_netmask="24" nic="int4.27" \
        op monitor interval="10s"
primitive IP_iSCSI_1_5 ocf:heartbeat:IPaddr2 \
        params ip="10.1.28.10" cidr_netmask="24" nic="int5.28" \
        op monitor interval="10s"
primitive IP_iSCSI_1_6 ocf:heartbeat:IPaddr2 \
        params ip="10.1.29.10" cidr_netmask="24" nic="int6.29" \
        op monitor interval="10s"

primitive IP_iSCSI_2_1 ocf:heartbeat:IPaddr2 \
        params ip="10.1.24.20" cidr_netmask="24" nic="int1.24" \
        op monitor interval="10s"
primitive IP_iSCSI_2_2 ocf:heartbeat:IPaddr2 \
        params ip="10.1.25.20" cidr_netmask="24" nic="int2.25" \
        op monitor interval="10s"
primitive IP_iSCSI_2_3 ocf:heartbeat:IPaddr2 \
        params ip="10.1.26.20" cidr_netmask="24" nic="int3.26" \
        op monitor interval="10s"
primitive IP_iSCSI_2_4 ocf:heartbeat:IPaddr2 \
        params ip="10.1.27.20" cidr_netmask="24" nic="int4.27" \
        op monitor interval="10s"
primitive IP_iSCSI_2_5 ocf:heartbeat:IPaddr2 \
        params ip="10.1.28.20" cidr_netmask="24" nic="int5.28" \
        op monitor interval="10s"
primitive IP_iSCSI_2_6 ocf:heartbeat:IPaddr2 \
        params ip="10.1.29.20" cidr_netmask="24" nic="int6.29" \
        op monitor interval="10s"

primitive ISCSI_LUN_VM_STORAGE_1 ocf:heartbeat:SCSTLun \
        params iqn="iqn.2011-04.ru.domain:VM_STORAGE_1" device_name="VM_STORAGE_1" \
        lun="0" path="/dev/drbd0" handler="vdisk_fileio"
primitive ISCSI_LUN_VM_STORAGE_2 ocf:heartbeat:SCSTLun \
        params iqn="iqn.2011-04.ru.domain:VM_STORAGE_2" device_name="VM_STORAGE_2" \
        lun="0" path="/dev/drbd1" handler="vdisk_fileio"

primitive ISCSI_TGT_VM_STORAGE_1 ocf:heartbeat:SCSTTarget \
        params iqn="iqn.2011-04.ru.domain:VM_STORAGE_1" \
        portals="10.1.24.10 10.1.25.10 10.1.26.10 10.1.27.10 10.1.28.10 10.1.29.10" \
        tgtoptions="InitialR2T=No ImmediateData=Yes MaxRecvDataSegmentLength=1048576 MaxXmitDataSegmentLength=1048576 MaxBurstLength=1048576 FirstBurstLength=524284 MaxOutstandingR2T=32 HeaderDigest=CRC32C DataDigest=CRC32C QueuedCommands=32 io_grouping_type=never" \
        op monitor interval="10s" timeout="60s"
primitive ISCSI_TGT_VM_STORAGE_2 ocf:heartbeat:SCSTTarget \
        params iqn="iqn.2011-04.ru.domain:VM_STORAGE_2" \
        portals="10.1.24.20 10.1.25.20 10.1.26.20 10.1.27.20 10.1.28.20 10.1.29.20" \
        tgtoptions="InitialR2T=No ImmediateData=Yes MaxRecvDataSegmentLength=1048576 MaxXmitDataSegmentLength=1048576 MaxBurstLength=1048576 FirstBurstLength=524284 MaxOutstandingR2T=32 HeaderDigest=CRC32C DataDigest=CRC32C QueuedCommands=32 io_grouping_type=never" \
        op monitor interval="10s" timeout="60s"

group GROUP_ISCSI_1 IP_iSCSI_1_1 IP_iSCSI_1_2 IP_iSCSI_1_3 IP_iSCSI_1_4 \
            IP_iSCSI_1_5 IP_iSCSI_1_6 ISCSI_TGT_VM_STORAGE_1 ISCSI_LUN_VM_STORAGE_1
group GROUP_ISCSI_2 IP_iSCSI_2_1 IP_iSCSI_2_2 IP_iSCSI_2_3 IP_iSCSI_2_4 \
            IP_iSCSI_2_5 IP_iSCSI_2_6 ISCSI_TGT_VM_STORAGE_2 ISCSI_LUN_VM_STORAGE_2

ms MS_DRBD_VM_STORAGE_1 DRBD_VM_STORAGE_1 \
        meta master-max="1" master-node-max="1" clone-max="2" clone-node-max="1" \
        notify="true" target-role="Master"
ms MS_DRBD_VM_STORAGE_2 DRBD_VM_STORAGE_2 \
        meta master-max="1" master-node-max="1" clone-max="2" clone-node-max="1" \
        notify="true" target-role="Master"

location PREFER-1 MS_DRBD_VM_STORAGE_1 50: server1
location PREFER-2 MS_DRBD_VM_STORAGE_2 50: server2

colocation COLOC_ALL_1 inf: GROUP_ISCSI_1 MS_DRBD_VM_STORAGE_1:Master
colocation COLOC_ALL_2 inf: GROUP_ISCSI_2 MS_DRBD_VM_STORAGE_2:Master

order ORDER_ALL_1 inf: MS_DRBD_VM_STORAGE_1:promote GROUP_ISCSI_1:start
order ORDER_ALL_2 inf: MS_DRBD_VM_STORAGE_2:promote GROUP_ISCSI_2:start

property $id="cib-bootstrap-options" \
        dc-version="1.1.7-ee0730e13d124c3d58f00016c3376a1de5323cff" \
        cluster-infrastructure="openais" \
        expected-quorum-votes="2" \
        stonith-enabled="false" \
        no-quorum-policy="ignore" \
        default-action-timeout="240" \
        last-lrm-refresh="1367942459"
rsc_defaults $id="rsc-options" \
        resource-stickiness="100"

Общие настройки кластера

Они находятся в самом низу. Из важных тут no-quorum-policy=«ignore» и expected-quorum-votes=«2» — у нас кластер из 2 серверов и кворума тут быть не может ну никак, поэтому игнорируем его.

Ресурсы

Обычно ресурс может иметь два состояния — включен или выключен, Started/Stopped.
Например, ocf:heartbeat:IPaddr2 поднимает на интерфейсах IP-адреса и снимает их, а также рассылает gratious arp для обновления arp-таблиц. Этому ресурсу мы указываем IP адрес, маску и интерфейс.

Еще есть специальные ресурсы, например DRBD (ocf:linbit:drbd), которые имеют режимы Master/Slave.
При переходе ноды в активный режим менеджер кластера будет переводить ресурс в режим мастер и наоборот. DRBD при этом будет переключаться из Secondary в Primary. Для него мы указываем имя ресурса и путь до конфига DRBD (наверное, его можно опустить, точно не помню).

Далее идут наши самописные ресурсы.
Для ocf:heartbeat:SCSTLun мы указываем IQN таргета, в который он будет добавлен, имя устройства, номер LUN-а (у таргета обязательно должен быть LUN 0, иначе у некоторых инициаторов сносит крышу), путь до экспортируемого устройства и обработчик (handler).

На обработчике нужно остановится подробнее — это способ, которым SCST будет работать с нашим устройством.

Из интересных это:
  • disk — по сути это просто прямой проброс SCSI команд от инициатора к SCSI устройству, самый простой режим, но работает только с реальными SCSI устройствами, нам не подходит, т.к. экспортируем DRBD-устройство
  • vdisk_blockio — открывает устройство как блочное, обходя page-cache операционной системы. Используется, если не нужно кэшировать ввод-вывод
  • vdisk_fileio — открывает устройство как файл, позволяя использовать page-cache операционной системы, самый производительный режим, его и выберем

У vdisk_fileio есть важный параметр, влияющий на скорость — nv_cache=1, он прописан жестко в SCSTLun.
Этот параметр говорит SCST игнорировать команды инициатора для сброса кэша на устройство. Потенциально, это может привести к потере данных в случае аварийного отключения хранилища т.к. инициатор будет думать, что данные на диске, а они еще в памяти. Так что используйте на свой страх и риск.

Далее идёт ресурс ocf:heartbeat:SCSTTarget, которому мы присваиваем IQN, portals — это список IP-адресов, через которые будет доступен этот таргет, tgtoptions — опции iSCSI, про них можно много где почитать.

Директивы, ответственные за поведение кластера при запуске и остановке ресурсов:
  • group объединяет ресурсы в группу для работы с ними как с единым целым. Ресурсы в группе запускаются последовательно
  • location указывает на какой ноде мы по умолчанию хотим видеть этот ресурс
  • colocation задает какие ресурсы должны находиться вместе на одной ноде
  • order сообщает менеджеру кластера порядок запуска ресурсов

После настройки ресурсов выходим из редактора и применяем изменения:
crm(live)configure# commit
crm(live)configure# exit

После этого можно посмотреть текущую ситуацию:
# crm status
============
Last updated: Mon Jan 20 17:04:04 2014
Last change: Thu Jul 25 13:59:27 2013 via crm_resource on server1
Stack: openais
Current DC: server1 - partition with quorum
Version: 1.1.7-ee0730e13d124c3d58f00016c3376a1de5323cff
2 Nodes configured, 2 expected votes
20 Resources configured.
============

Online: [ server1 server2 ]

 Resource Group: GROUP_ISCSI_1
     IP_iSCSI_1_1       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_1_2       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_1_3       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_1_4       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_1_5       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_1_6       (ocf::heartbeat:IPaddr2):       Stopped
     ISCSI_TGT_VM_STORAGE_1    (ocf::heartbeat:SCSTTarget):    Stopped
     ISCSI_LUN_VM_STORAGE_1    (ocf::heartbeat:SCSTLun):       Stopped
 Resource Group: GROUP_ISCSI_2
     IP_iSCSI_2_1       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_2_2       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_2_3       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_2_4       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_2_5       (ocf::heartbeat:IPaddr2):       Stopped
     IP_iSCSI_2_6       (ocf::heartbeat:IPaddr2):       Stopped
     ISCSI_TGT_VM_STORAGE_2    (ocf::heartbeat:SCSTTarget):    Stopped
     ISCSI_LUN_VM_STORAGE_2    (ocf::heartbeat:SCSTLun):       Stopped
 Master/Slave Set: MS_DRBD_VM_STORAGE_1 [DRBD_VM_STORAGE_1]
     Slaves: [ server1 server2 ]
 Master/Slave Set: MS_DRBD_VM_STORAGE_2 [DRBD_VM_STORAGE_2]
     Slaves: [ server1 server2 ]

Мы видим, что ресурсы в неактивном состоянии, DRBD в режиме Slave (Secondary).

Теперь можно попробовать их активировать:
# crm resource start MS_DRBD_VM_STORAGE_1
# crm resource start MS_DRBD_VM_STORAGE_2

Стартуя этот ресурс мы вызываем в том числе и запуск других ресурсов т.к. они указаны у нас как зависимые (colocation), причем запускаться они будут в строго определенном порядке (order): сначала DRBD устройства перейдут в режим Primary, затем поднимутся IP-адреса, создадутся LUN-ы и в конце уже создадутся iSCSI таргеты.

Смотрим результат:
# crm status
============
Last updated: Tue Jan 21 11:54:46 2014
Last change: Thu Jul 25 13:59:27 2013 via crm_resource on server1
Stack: openais
Current DC: server1 - partition with quorum
Version: 1.1.7-ee0730e13d124c3d58f00016c3376a1de5323cff
2 Nodes configured, 2 expected votes
20 Resources configured.
============

Online: [ server1 server2 ]

 Resource Group: GROUP_ISCSI_1
     IP_iSCSI_1_1       (ocf::heartbeat:IPaddr2):       Started server1
     IP_iSCSI_1_2       (ocf::heartbeat:IPaddr2):       Started server1
     IP_iSCSI_1_3       (ocf::heartbeat:IPaddr2):       Started server1
     IP_iSCSI_1_4       (ocf::heartbeat:IPaddr2):       Started server1
     IP_iSCSI_1_5       (ocf::heartbeat:IPaddr2):       Started server1
     IP_iSCSI_1_6       (ocf::heartbeat:IPaddr2):       Started server1
     ISCSI_TGT_VM_STORAGE_1    (ocf::heartbeat:SCSTTarget):    Started server1
     ISCSI_LUN_VM_STORAGE_1    (ocf::heartbeat:SCSTLun):       Started server1
 Resource Group: GROUP_ISCSI_2
     IP_iSCSI_2_1       (ocf::heartbeat:IPaddr2):       Started server2
     IP_iSCSI_2_2       (ocf::heartbeat:IPaddr2):       Started server2
     IP_iSCSI_2_3       (ocf::heartbeat:IPaddr2):       Started server2
     IP_iSCSI_2_4       (ocf::heartbeat:IPaddr2):       Started server2
     IP_iSCSI_2_5       (ocf::heartbeat:IPaddr2):       Started server2
     IP_iSCSI_2_6       (ocf::heartbeat:IPaddr2):       Started server2
     ISCSI_TGT_VM_STORAGE_2    (ocf::heartbeat:SCSTTarget):    Started server2
     ISCSI_LUN_VM_STORAGE_2    (ocf::heartbeat:SCSTLun):       Started server2
 Master/Slave Set: MS_DRBD_VM_STORAGE_1 [DRBD_VM_STORAGE_1]
     Masters: [ server1 ]
     Slaves: [ server2 ]
 Master/Slave Set: MS_DRBD_VM_STORAGE_2 [DRBD_VM_STORAGE_2]
     Masters: [ server2 ]
     Slaves: [ server1 ]

Если всё так, то можно себя поздравить — кластер запущен!
Каждая группа ресурсов запущена на своем сервере, как это указано в конфиге директивой location.

Для подтверждения можно посмотреть лог ядра — dmesg — туда DRBD и SCST выводят свою диагностику.

Конец второй части


В третьей, заключительной, части я покажу как настроить сервера ESXi на оптимальную работу с этим кластером.
Tags:
Hubs:
+37
Comments 21
Comments Comments 21

Articles