Отказоустойчивый кластер (DRBD, HA, GFS2, TGT)

Всего физических узлов: 2

Для теста было взято «железо»: Pentium(R) Dual-Core CPU E5300 @ 2.60GHz, 2 cores, 2 Gb mem, 160 Gb HDD, 2 Ethernet 1000Mb/s

1. Подготовка систем.

1.1. Устанавливаем на каждый физический узел CentOS 5.4

1.2. Для примера я разбил жёсткий диск следующим образом:
100 Мб /dev/sda1 под boot
8 Гб /dev/sda2 под систему (входит в LVM /dev/VolGroup00/LogVol00)
2 Гб /dev/sda2 под swap (входит в LVM /dev/VolGroup00/LogVol01)
100 Гб /dev/sda3 под первый ресурс (сырой жёсткий диск его мы будем цеплять к существующему ESX используя iScsi-target, для работы виртуальных машин и хранения ISO-образов и Snapshot'ов)
50 Гб /dev/sda4 под второй ресурс (входит в LVM /dev/VolGroup04/LogVol04 его мы будем монтировать в папку /data, использовать его можно для web или ftp-сервера или просто как файлопомойку)
1.3 Имена соответственно
node1.zavddolg.ru (eth0 192.168.1.40/24 eth1 192.167.0.40/24) и
node2.zavddolg.ru (eth0 192.168.1.41/24 eth1 192.167.0.41/24)

2. Подготовка к кластеризации.
2.1. Нам потребуется ha, gfs2, drbd, tgt. Устанавливаем эти пакеты + все что они потребуют (библиотеки, зависимости). На двух узлах.
[root@node1]# yum -y --nogpgcheck install heartbeat-2.1.3-3.el5.centos.i386.rpm heartbeat-stonith-2.1.3-3.el5.centos.i386.rpm heartbeat-pils-2.1.3-3.el5.centos.i386.rpm kmod-drbd-8.0.16-5.el5_3.i386.rpm drbd-8.0.16-5.el5.centos.i386.rpm kmod-gfs-0.1.34-12.el5.centos.i386.rpm gfs2-utils-0.1.62-20.el5.i386.rpm gfs-utils-0.1.20-7.el5.i386.rpm scsi-target-utils-0.0-6.20091205snap.el5_5.3.i386.rpm


2.2. Стартуем сервисы. На двух узлах.
[root@node1]# chkconfig clvmd on
[root@node1]# chkconfig cman on
[root@node1]# chkconfig gfs on
[root@node1]# chkconfig gfs2 on
[root@node1]# chkconfig conman on
[root@node1]# chkconfig iptables off
[root@node1]# chkconfig ip6tables off
[root@node1]# chkconfig luci on
[root@node1]# chkconfig pulse on
[root@node1]# chkconfig qdiskd on
[root@node1]# chkconfig rdisc on
[root@node1]# chkconfig rgmanager on
[root@node1]# chkconfig scsi_reserve on
[root@node1]# chkconfig tgtd on #(только на перовм узле)


2.3 создаём диски. На двух узлах.

[root@node1]# pvcreate /dev/sda4
[root@node1]# vgcreate VolGroup04 /dev/sda4
[root@node1]# lvcreate -L 46G -n LogVol04 VolGroup04
3. Настройка DRBD, просто приведу свой пример с некоторыми комментариями (/etc/drbd.conf):
global { usage-count yes; }
resource r0 { # r0 имя моего первого кластера
protocol C;
startup {
wfc-timeout 0;
degr-wfc-timeout 120;
become-primary-on both;
}
disk { on-io-error detach; } # or panic, ...
net {
max-buffers 2048;
ko-count 4;
allow-two-primaries; # Важно! разрешаем быть обоим узлам primary (для зеркалирования данных)
after-sb-0pri discard-zero-changes;
after-sb-1pri discard-secondary;
after-sb-2pri disconnect;
cram-hmac-alg "sha1";
shared-secret "сложныйпароль";
}
syncer { rate 100M; # скорость обмена данными между узлами сети, оптимально для 1000 мбит/сек. сети.
al-extents 257;
}
on node1.zavddolg.ru { # имя ноды первого узла используйте uname -a
device /dev/drbd0;
disk /dev/sda3; # дополнительный раздел
address 192.167.0.40:7790; # IP адрес первой ноды
meta-disk internal;
}
on node2.zavddolg.ru { # имя ноды второго узла используйте uname -a
device /dev/drbd0;
disk /dev/sda3; # дополнительный раздел
address 192.167.0.41:7790; # IP адрес второй ноды
meta-disk internal;
}
}
resource r1 {
protocol C;
startup {
wfc-timeout 0;
degr-wfc-timeout 120;
become-primary-on both;
}
disk { on-io-error detach; } # or panic, ...
net {
max-buffers 2048;
ko-count 4;
allow-two-primaries;
after-sb-0pri discard-zero-changes;
after-sb-1pri discard-secondary;
after-sb-2pri disconnect;
cram-hmac-alg "sha1";
shared-secret "сложныйпароль";
}
syncer { rate 100M;
al-extents 257;
}
on node1.zavddolg.ru {
device /dev/drbd1;
disk /dev/VolGroup04/LogVol04;
address 192.167.0.40:7788;
meta-disk internal;
}
on node2.zavddolg.ru {
device /dev/drbd1;
disk /dev/VolGroup04/LogVol04;
address 192.167.0.41:7788;
meta-disk internal;
}
}

3.1 Важно! Не забываем прописать имена нод в фале /etc/hosts

127.0.0.1 localhost.localdomain localhost
::1 localhost6.localdomain6 localhost6
192.167.0.40 node1.zavddolg.ru node1
192.168.1.40 node1.zavddolg.ru node1
192.167.0.41 node2.zavddolg.ru node2
192.168.1.41 node2.zavddolg.ru node2

4. Подготавливаем файловую систему.

4.1. Создаем на двух серверах дополнительные разделы (из оставленного места, указано было в п.п. 1.2). Какая будет файловая система — не важно, мы ее все равно затрем.

4.2. Подготавливаем мета-разделы DRBD на обоих узлах:
[root@node1]# dd if=/dev/zero bs=1M count=1 of=/dev/sda3; sync # команда просто затирает все место
[root@node1]# dd if=/dev/zero bs=1M count=1 of=/dev/VolGroup04/LogVol04; sync # команда просто затирает все место
4.3. Далее даем команды на создание разделов DRBD:
[root@node1]# modprobe drbd
[root@node1]# drbdadm create-md r0 # r0 имя моего DRBD кластера, описано в п.п. 3.
[root@node1]# service drbd start (на первой ноде)
yes когда он ругается и не может найти вторую ноду
[root@node1]# drbdadm — -o primary r0 # эту команду даем только на первой ноде (пока).
[root@node1]# drbdadm — -o primary r1 # эту команду даем только на первой ноде (пока).
4.4. Создаем файловую систему gfs2 на первой ноде. Файловая система gfs2, предназначенная для совместного использования двумя или более Linux-системами, т.е. мы имеем возможность одновременно монтировать разделы в режиме RW на обоих узлах:
[root@node1]# mkfs.gfs2 -t cluster:gfs1 -p lock_dlm -j 2 /dev/drbd0 # drbd0 мое DRBD устройство в системе.
[root@node1]# mkfs.gfs2 -t cluster:gfs1 -p lock_dlm -j 2 /dev/drbd1 # drbd1 мое DRBD устройство в системе.

4.5. Далее нам нужно синхронизировать данные на обоих устройствах DRBD на обоих узлах:
[root@node1]# /etc/init.d/drbd restart # на обоих узлах
[root@node2]# /etc/init.d/drbd restart

4.6. Наблюдаем за синхронизацией командой:
[root@node1]# watch cat /proc/drbd

4.7. Ждем появления надписи на обоих узлах:
version: 8.0.16 (api:86/proto:86)
GIT-hash: d30881451c988619e243d6294a899139eed1183d build by mockbuild@v20z-x86-64.home.local, 2009-08-22 13:23:34
0: cs:Connected st:Primary/Primary ds:UpToDate/UpToDate C r---
ns:15763216 nr:0 dw:15763216 dr:3720 al:3931 bm:0 lo:0 pe:0 ua:0 ap:0
resync: used:0/61 hits:0 misses:0 starving:0 dirty:0 changed:0
act_log: used:0/257 hits:3936873 misses:6341 starving:0 dirty:2410 changed:3931
1: cs:Connected st:Primary/Primary ds:UpToDate/UpToDate C r---
ns:0 nr:20 dw:20 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0
resync: used:0/61 hits:0 misses:0 starving:0 dirty:0 changed:0
act_log: used:0/257 hits:0 misses:0 starving:0 dirty:0 changed:0

4.8. Переходим к настройке самой gfs2, вот мой пример конфигурации кластера (/etc/cluster/cluster.conf): для первой ноды
<?xml version="1.0"?>
<cluster config_version="3" name="cluster">
<quorumd device="/dev/drbd1" interval="1" label="r1" min_score="3" tko="10" votes="3">
<heuristic interval="2" program="ping 192.167.0.41 -c1 -t1" score="1"/>
</quorumd>
<fence_daemon post_fail_delay="0" post_join_delay="3"/>
<clusternodes>
<clusternode name="node2" nodeid="1" votes="2">
<fence/>
</clusternode>
<clusternode name="node1" nodeid="2" votes="2">
<fence/>
</clusternode>
</clusternodes>
<cman/>
<fencedevices/>
<rm>
<failoverdomains/>
<resources>
<ip address="192.168.1.40/24" monitor_link="1"/>
</resources>
</rm>
</cluster>
для второй ноды
<?xml version="1.0"?>
<cluster config_version="3" name="cluster">
<quorumd device="/dev/drbd1" interval="1" label="r1" min_score="3" tko="10" votes="3">
<heuristic interval="2" program="ping 192.167.0.40 -c1 -t1" score="1"/>
</quorumd>
<fence_daemon post_fail_delay="0" post_join_delay="3"/>
<clusternodes>
<clusternode name="node2" nodeid="1" votes="2">
<fence/>
</clusternode>
<clusternode name="node1" nodeid="2" votes="2">
<fence/>
</clusternode>
</clusternodes>
<cman/>
<fencedevices/>
<rm>
<failoverdomains/>
<resources>
<ip address="192.168.1.41/24" monitor_link="1"/>
</resources>
</rm>
</cluster>

4.9. Выводи ноды в режим online на двух серверах:
[root@node1]# /etc/init.d/cman start
[root@node2]# /etc/init.d/cman start

[root@node1 ~]# cman_tool nodes
Node Sts Inc Joined Name
1 M 32 2011-02-09 13:48:11 node2
2 M 28 2011-02-09 13:48:11 node1
[root@node1 ~]# cman_tool status
Version: 6.2.0
Config Version: 3
Cluster Name: cluster
Cluster Id: 13364
Cluster Member: Yes
Cluster Generation: 32
Membership state: Cluster-Member
Nodes: 2
Expected votes: 4
Total votes: 4
Quorum: 3
Active subsystems: 9
Flags: Dirty
Ports Bound: 0 11 177
Node name: node1
Node ID: 2
Multicast addresses: 239.192.52.104
Node addresses: 192.167.0.40


4.9. Делаем оба узла primary и монтируем файловую систему:
[root@node1 ~]# drbdadm primary r1 # на обоих узлах
[root@node1 ~]# mount -t gfs2 /dev/drbd1 /data # на обоих узлах

Если все прошло ровно и без ошибок — разделы должны были примонтироваться, для проверки можете скопировать файл на одной из нод в папку /data (туда куда монтировали drbd1) и они должны будут появитьcя в такойже папке на второй ноде.

5. Настройка HeartBeat (HA Cluster):

5.1. HA всего лишь должен будет поднимать глобальный IP адрес при выходе из строя основной системы, вот мой пример конфигурации (/etc/ha.d/ha.cf):
crm on
# debug log
debugfile /var/log/ha-debug
# log file
logfile /var/log/ha-log
# the way of output to syslog
logfacility local0
# keepalive
keepalive 2
# deadtime
deadtime 30
# deadping
deadping 40
# warntime
warntime 10
# initdead
initdead 60
# port
udpport 694
# interface and IP address of another Host
ucast eth0 192.168.1.40
# auto failback
auto_failback on
# node name (the name of "uname -n")
node node1
node node2
respawn root /usr/lib/heartbeat/pingd -m 100 -d 5s -a default_ping_set
5.2. Ресурсы кластера HA (/etc/ha.d/authkeys):
auth 1
1 crc
5.3. Ресурсы кластера HA (/etc/ha.d/haresources):
node1 IPaddr::192.167.0.40/24/eth1

6. Настраиваем iScsi-target (/etc/tgt/targets.conf):
<target iqn.2011-02.ru.zavddolg:node1.zayden>
backing-store /dev/drbd0
</target>
Вот и все, далее в раздел /data можно устанавливать нужные вам приложения (apache2, postfix, etc.), а второй раздел цепляем к ESX используя iScsi-initiator.

Бонус!

Если упали обе ноды и не могут синхронизировать данные (split-brain):

На ноде где есть актуальные данные:
[root@node2 ~]# drbdadm connect r1

На ноде где данные не актуальны:
[root@node1 ~]# drbdadm — --overwrite-data-of-peer primary r1

После удачной синхронизации перевести обе ноды в режим primary:
[root@node1 ~]# drbd primary r1, перемонтировать разделы mount /dev/drbd1 /data