![](https://habrastorage.org/storage1/a106a426/2e9914a1/bc4c1c5a/35f4c37a.jpg)
Вкратце суть заключается в возможности построения отказоустойчивой виртуальной инфраструктуры без внешней СХД. Для реализации устанавливается две или три виртуальные машины (по одной на каждый хост), которые реплицируют между собой свободное пространство дисковой подсистемы ESXi-серверов и предоставляют его в качестве общего хранилища все тем же хостам ESXi. Подробно на русском языке Storage Appliance описан здесь.
Интересная задумка, но кусается цена — в районе $6К. Кроме того, если задуматься о производительности, то не получится ли просадки по скорости работы дискового массива? Подходя к вопросу с другой стороны, можно придумать много других способов организации внешней СХД. Например, можно создать внешнее хранилище из практически любого железа с необходимым количеством дисков и установленным софтом Openfiler, FreeNAS, Nexenta, Open-E — в этих программных продуктах есть возможность репликации между системами.
Такой подход практикуют многие компании, у которых нет возможности приобрести дорогостоящую СХД именитого производителя, которая бы обеспечила достаточную производительность и надежность. Как правило, такие системы оснащаются двумя контроллерами, избыточной системой питания, скоростными дисками и прочее…
Впрочем, вернемся к началу и посмотрим на схему, которую предлагает VMware:
![](https://habrastorage.org/storage1/929b7181/21b1757c/267a464c/92771e30.gif)
Что мы видим? 3 хоста ESXi с развернутыми на них виртуальными машинами по одной на каждый хост. Машины собраны в кластер и отдают нам внутренние диски как внешние.
Идея собрать у себя подобное решение из доступных инструментов давно витала в воздухе, но никак не находила обоснования. А тут сама VMware дала толчок для того, чтобы опробовать все в тестовой среде.
Решений по построению отказоустойчивого хранилища — куча, например, на основе Openfiler+DRBD+Heartbeat. Но в основе всех этих решений лежит идея построения именно внешнего хранилища. Почему бы не попробовать сделать что-то подобное, но на основе виртуальных машин?
В качестве фундамента возьмем 2 виртуалки с OS Ubuntu, документацию Ubuntu по построению failover iSCSI-target и попытаемся сделать свой Appliance.
Разбиение дисков на обоих узлах кластера:
/dev/sda1 - 10 GB / (primary' ext3, Bootable flag: on)
/dev/sda5 - 1 GB swap (logical)
/dev/sdb1 - 1 GB (primary) DRBD meta-данные. Не монтируем.
/dev/sdc1 - 1 GB (primary) DRBD диск, используемый для хранения конфигурационных файлов iSCSI. Не монтируем.
/dev/sdd1 - 50 GB (primary) DRBD диск для iSCSI-target.
Размер диска sdd1 выбран для примера. На самом деле берется все оставшееся свободное место на локальном хранилище ESXi-хоста.
Сеть iSCSI:
iSCSI server1: node1.demo.local IP address: 10.11.55.55
iSCSI server2: node2.demo.local IP address: 10.11.55.56
iSCSI Virtual IP address 10.11.55.50
Приватная сеть:
iSCSI server1: node1-private IP address: 192.168.22.11
iSCSI server2: node2-private IP address: 192.168.22.12
/etc/network/interfaces:
Для node1:
auto eth0
iface eth0 inet static
address 10.11.55.55
netmask 255.0.0.0
gateway 10.0.0.1
auto eth1
iface eth1 inet static
address 192.168.22.11
netmask 255.255.255.0
Для node2:
auto eth0
iface eth0 inet static
address 10.11.55.56
netmask 255.0.0.0
gateway 10.0.0.1
auto eth1
iface eth1 inet static
address 192.168.22.12
netmask 255.255.255.0
Файл /etc/hosts для обоих узлов:
127.0.0.1 localhost
10.11.55.55 node1.demo.local node1
10.11.55.56 node2.demo.local node2
192.168.22.11 node1-private
192.168.22.12 node2-private
Установка пакетов:
apt-get -y install ntp ssh drbd8-utils heartbeat jfsutils
Перезагрузим серверы.
Меняем владельцев файлов и разрешения на них:
chgrp haclient /sbin/drbdsetup
chmod o-x /sbin/drbdsetup
chmod u+s /sbin/drbdsetup
chgrp haclient /sbin/drbdmeta
chmod o-x /sbin/drbdmeta
chmod u+s /sbin/drbdmeta
Используем /etc/drbd.conf для описания конфигурации. Определяем 2 ресурса:
1. DRBD устройство, которое будет содержать файлы конфигурации ISCSI;
2. DRBD устройство, которое станет нашим ISCSI-target.
Для node1:
/etc/drbd.conf:
resource iscsi.config {
protocol C;
handlers {
pri-on-incon-degr "echo o > /proc/sysrq-trigger ; halt -f";
pri-lost-after-sb "echo o > /proc/sysrq-trigger ; halt -f";
local-io-error "echo o > /proc/sysrq-trigger ; halt -f";
outdate-peer "/usr/lib/heartbeat/drbd-peer-outdater -t 5";
}
startup {
degr-wfc-timeout 120;
}
disk {
on-io-error detach;
}
net {
cram-hmac-alg sha1;
shared-secret "password";
after-sb-0pri disconnect;
after-sb-1pri disconnect;
after-sb-2pri disconnect;
rr-conflict disconnect;
}
syncer {
rate 100M;
verify-alg sha1;
al-extents 257;
}
on node1 {
device /dev/drbd0;
disk /dev/sdc1;
address 192.168.22.11:7788;
meta-disk /dev/sdb1[0];
}
on node2 {
device /dev/drbd0;
disk /dev/sdc1;
address 192.168.22.12:7788;
meta-disk /dev/sdb1[0];
}
}
resource iscsi.target.0 {
protocol C;
handlers {
pri-on-incon-degr "echo o > /proc/sysrq-trigger ; halt -f";
pri-lost-after-sb "echo o > /proc/sysrq-trigger ; halt -f";
local-io-error "echo o > /proc/sysrq-trigger ; halt -f";
outdate-peer "/usr/lib/heartbeat/drbd-peer-outdater -t 5";
}
startup {
degr-wfc-timeout 120;
}
disk {
on-io-error detach;
}
net {
cram-hmac-alg sha1;
shared-secret "password";
after-sb-0pri disconnect;
after-sb-1pri disconnect;
after-sb-2pri disconnect;
rr-conflict disconnect;
}
syncer {
rate 100M;
verify-alg sha1;
al-extents 257;
}
on node1 {
device /dev/drbd1;
disk /dev/sdd1;
address 192.168.22.11:7789;
meta-disk /dev/sdb1[1];
}
on node2 {
device /dev/drbd1;
disk /dev/sdd1;
address 192.168.22.12:7789;
meta-disk /dev/sdb1[1];
}
}
Копируем конфигурацию на второй узел:
scp /etc/drbd.conf root@10.11.55.56:/etc/
Инициализируем диски с мета-данными на обоих серверах:
[node1]dd if=/dev/zero of=/dev/sdс1
[node1]dd if=/dev/zero of=/dev/sdd1
[node1]drbdadm create-md iscsi.config
[node1]drbdadm create-md iscsi.target.0
[node2]dd if=/dev/zero of=/dev/sdс1
[node2]dd if=/dev/zero of=/dev/sdd1
[node2]drbdadm create-md iscsi.config
[node2]drbdadm create-md iscsi.target.0
Запускаем drbd:
[node1]/etc/init.d/drbd start
[node2]/etc/init.d/drbd start
Теперь необходимо решить, какой сервер будет выступать первичным, а какой вторичным, чтобы выполнить синхронизацию между дисками. Допустим, что первичным (Primary) будет node1.
Выполним команду на первом узле:
[node1]drbdadm -- --overwrite-data-of-peer primary iscsi.config
Вывод команды
cat /proc/drbd:
version: 8.3.9 (api:88/proto:86-95)
srcversion: CF228D42875CF3A43F2945A
0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:1048542 nr:0 dw:0 dr:1048747 al:0 bm:64 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
1: cs:Connected ro:Secondary/Secondary ds:Inconsistent/Inconsistent C r-----
ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:52428768
Отформатируем и монтируем раздел /dev/drbd0:
[node1]mkfs.ext3 /dev/drbd0
[node1]mkdir -p /srv/data
[node1]mount /dev/drbd0 /srv/data
Создадим файл на первом узле и затем переключим второй в режим Primary:
[node1]dd if=/dev/zero of=/srv/data/test.zeros bs=1M count=100
Для node1:
[node1]umount /srv/data
[node1]drbdadm secondary iscsi.config
Для node2:
[node2]mkdir -p /srv/data
[node2]drbdadm primary iscsi.config
[node2]mount /dev/drbd0 /srv/data
На втором узле будет виден файл размером 100 Мб.
ls –l /srv/data
Удаляем его и опять переключаемся на первый узел:
On node2:
[node2]rm /srv/data/test.zeros
[node2]umount /srv/data
[node2]drbdadm secondary iscsi.config
On node1:
[node1]drbdadm primary iscsi.config
[node1]mount /dev/drbd0 /srv/data
Выполним команду ls /srv/data. Если на разделе никаких данных нет, значит репликация прошла успешно.
Переходим к установке iSCSI-target. Выбираем первый узел как Primary и выполняем синхронизацию разделов:
[node1]drbdadm -- --overwrite-data-of-peer primary iscsi.target.0
cat /proc/drbd
version: 8.3.9 (api:88/proto:86-95)
srcversion: CF228D42875CF3A43F2945A
0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:135933 nr:96 dw:136029 dr:834 al:39 bm:8 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
1: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r-----
ns:1012864 nr:0 dw:0 dr:1021261 al:0 bm:61 lo:1 pe:4 ua:64 ap:0 ep:1 wo:f oos:51416288
[>....................] sync'ed: 2.0% (50208/51196)M
finish: 0:08:27 speed: 101,248 (101,248) K/sec
Дождемся синхронизации…
cat /proc/drbd
version: 8.3.9 (api:88/proto:86-95)
srcversion: CF228D42875CF3A43F2945A
0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:135933 nr:96 dw:136029 dr:834 al:39 bm:8 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
1: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
ns:52428766 nr:0 dw:0 dr:52428971 al:0 bm:3200 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
Устанавливаем пакет iscsitarget на обоих узлах:
[node1]apt-get -y install iscsitarget
[node2]apt-get -y install iscsitarget
Включаем опцию запуска iscsi как сервиса:
[node1]sed -i s/false/true/ /etc/default/iscsitarget
[node2]sed -i s/false/true/ /etc/default/iscsitarget
Удаляем записи со всех скриптов:
[node1]update-rc.d -f iscsitarget remove
[node2]update-rc.d -f iscsitarget remove
Перемещаем конфиг.файлы на drbd раздел:
[node1]mkdir /srv/data/iscsi
[node1] mv /etc/iet/ietd.conf /srv/data/iscsi
[node1]ln -s /srv/data/iscsi/ietd.conf /etc/iet/ietd.conf
[node2]rm /etc/iet/ietd.conf
[node2]ln -s /srv/data/iscsi/ietd.conf /etc/iet/ietd.conf
Описываем iSCSI-target в файле /srv/data/iscsi/ietd.conf:
Target iqn.2011-08.local.demo:storage.disk.0
# IncomingUser geekshlby secret - закомментируем, чтоб не авторизоваться при подключении
# OutgoingUser geekshlby password
Lun 0 Path=/dev/drbd1,Type=blockio
Alias disk0
MaxConnections 1
InitialR2T Yes
ImmediateData No
MaxRecvDataSegmentLength 8192
MaxXmitDataSegmentLength 8192
MaxBurstLength 262144
FirstBurstLength 65536
DefaultTime2Wait 2
DefaultTime2Retain 20
MaxOutstandingR2T 8
DataPDUInOrder Yes
DataSequenceInOrder Yes
ErrorRecoveryLevel 0
HeaderDigest CRC32C,None
DataDigest CRC32C,None
Wthreads 8
Теперь необходимо настроить heartbeat для контроля за виртуальным IP-адресом iSCSI-target’а при отказе узла.
Описываем кластер в файле /etc/heartbeat/ha.cf:
logfacility local0
keepalive 2
deadtime 30
warntime 10
initdead 120
bcast eth0
bcast eth1
node node1
node node2
Механизм аутентификации
/etc/heartbeat/authkeys:
auth 2
2 sha1 NoOneKnowsIt
Меняем разрешения на файл /etc/heartbeat/authkeys:
chmod 600 /etc/heartbeat/authkeys
Описываем ресурсы кластера в файле /etc/heartbeat/haresources — главный узел, виртуальный IP, файловые системы и службы, которые будут запускаться:
/etc/heartbeat/haresources
node1 drbddisk::iscsi.config Filesystem::/dev/drbd0::/srv/data::ext3
node1 IPaddr::10.11.55.50/8/eth0 drbddisk::iscsi.target.0 iscsitarget
Копируем конфигурацию на второй узел:
[node1]scp /etc/heartbeat/ha.cf root@10.11.55.56:/etc/heartbeat/
[node1]scp /etc/heartbeat/authkeys root@10.11.55.56:/etc/heartbeat/
[node1]scp /etc/heartbeat/haresources root@10.11.55.56:/etc/heartbeat/
Отмонтируем /srv/data, делаем первый узел как Secondary.
Стартуем heartbeat
[node1]/etc/init.d/heartbeat start
Перезагружаем оба сервера.
[node1]/etc/init.d/drbd start
[node2]/etc/init.d/drbd start
[node1]drbdadm secondary iscsi.config - необязательно
[node1]drbdadm secondary iscsi.target.0 - необязательно
[node2]drbdadm primary iscsi.config
[node2]drbdadm primary iscsi.target.0
[node1]cat /proc/drbd
[node1]/etc/init.d/heartbeat start
После старта heartbeat’а переводим первый узел в режим primary, второй — secondary (в противном случае, не заведется).
[node2]drbdadm secondary iscsi.config
[node2]drbdadm secondary iscsi.target.0
[node1]drbdadm primary iscsi.config
[node1]drbdadm primary iscsi.target.0
Смотрим tail –f /var/log/syslog
Ждем…
Спустя некоторое время…
Aug 26 08:32:14 node1 harc[11878]: info: Running /etc/ha.d//rc.d/ip-request-resp ip-request-resp
Aug 26 08:32:14 node1 ip-request-resp[11878]: received ip-request-resp IPaddr::10.11.55.50/8/eth0 OK yes
Aug 26 08:32:14 node1 ResourceManager[11899]: info: Acquiring resource group: node1 IPaddr::10.11.55.50/8/eth0 drbddisk::iscsi.target.0 iscsitarget
Aug 26 08:32:14 node1 IPaddr[11926]: INFO: Resource is stopped
Aug 26 08:32:14 node1 ResourceManager[11899]: info: Running /etc/ha.d/resource.d/IPaddr 10.11.55.50/8/eth0 start
Aug 26 08:32:14 node1 IPaddr[12006]: INFO: Using calculated netmask for 10.11.55.50: 255.0.0.0
Aug 26 08:32:14 node1 IPaddr[12006]: INFO: eval ifconfig eth0:0 10.11.55.50 netmask 255.0.0.0 broadcast 10.255.255.255
Aug 26 08:32:14 node1 avahi-daemon[477]: Registering new address record for 10.11.55.50 on eth0.IPv4.
Aug 26 08:32:14 node1 IPaddr[11982]: INFO: Success
Aug 26 08:32:15 node1 ResourceManager[11899]: info: Running /etc/init.d/iscsitarget start
Aug 26 08:32:15 node1 kernel: [ 5402.722552] iSCSI Enterprise Target Software - version 1.4.20.2
Aug 26 08:32:15 node1 kernel: [ 5402.723978] iscsi_trgt: Registered io type fileio
Aug 26 08:32:15 node1 kernel: [ 5402.724057] iscsi_trgt: Registered io type blockio
Aug 26 08:32:15 node1 kernel: [ 5402.724061] iscsi_trgt: Registered io type nullio
Aug 26 08:32:15 node1 heartbeat: [12129]: debug: notify_world: setting SIGCHLD Handler to SIG_DFL
Aug 26 08:32:15 node1 harc[12129]: info: Running /etc/ha.d//rc.d/ip-request-resp ip-request-resp
Aug 26 08:32:15 node1 ip-request-resp[12129]: received ip-request-resp IPaddr::10.11.55.50/8/eth0 OK yes
Aug 26 08:32:15 node1 ResourceManager[12155]: info: Acquiring resource group: node1 IPaddr::10.11.55.50/8/eth0 drbddisk::iscsi.target.0 iscsitarget
Aug 26 08:32:15 node1 IPaddr[12186]: INFO: Running OK
Aug 26 08:33:08 node1 ntpd[1634]: Listen normally on 11 eth0:0 10.11.55.50 UDP 123
Aug 26 08:33:08 node1 ntpd[1634]: new interface(s) found: waking up resolver
ifconfig
eth0 Link encap:Ethernet HWaddr 00:50:56:20:f9:6c
inet addr:10.11.55.55 Bcast:10.255.255.255 Mask:255.0.0.0
inet6 addr: fe80::20c:29ff:fe20:f96c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:3622 errors:0 dropped:0 overruns:0 frame:0
TX packets:8081 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:302472 (302.4 KB) TX bytes:6943622 (6.9 MB)
Interrupt:19 Base address:0x2000
eth0:0 Link encap:Ethernet HWaddr 00:50:56:20:f9:6c
inet addr:10.11.55.50 Bcast:10.255.255.255 Mask:255.0.0.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
Interrupt:19 Base address:0x2000
eth1 Link encap:Ethernet HWaddr 00:50:56:20:f9:76
inet addr:192.168.22.11 Bcast:192.168.22.255 Mask:255.255.255.0
inet6 addr: fe80::20c:29ff:fe20:f976/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:1765 errors:0 dropped:0 overruns:0 frame:0
TX packets:3064 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:171179 (171.1 KB) TX bytes:492567 (492.5 KB)
Interrupt:19 Base address:0x2080
Подключаем получившийся iSCSI-target к обоим хостам ESX(i). После того как оба хоста увидели СХД собираем HA-кластер. Хотя места для создания виртуальных машин на самих хостах и не осталось, теперь это место представляется виртуальным хранилищем. При отказе любого из узлов виртуальная машина на втором узле перейдет в режим Primary и будет продолжать работу как iSCSI-target.
С помощью hdparm замерил скорость работы диска в виртуальной машине, установленной на target'e:
![](https://habrastorage.org/storage1/b2e35253/d235ff26/7fa3660b/72e3169e.gif)
Естественно, для серьезных production-систем такая СХД не подойдет. Но если нет высоконагруженных виртуальных машин или необходимо протестировать возможность построения HA-кластера, то такой способ предоставления общего хранилища имеет право на жизнь.
Прочитав данный материал, многие возможно скажут, что это «неправильно», «будут просадки по производительности», «возможность отказа обоих узлов» и т.д. Да! Может, оно так все и будет, но ведь, зачем-то компания VMware выпустила свой Storage Appliance?
P.S.: Кстати, кому лень лопатить все вручную, существует Management Console для настройки DRBD-кластера: http://www.drbd.org/mc/screenshot-gallery/.
madbug,
старший системный инженер DEPO Computers