Sibilia octopress blog

notes on memory.

Установка и настройка кластера Pacemaker

| Comments

Pacemaker Pacemaker

Для построения кластеров high availability (высокой доступности) я в своей работе использую Pacemaker. Он себя хорошо зарекомендовал на многих проектах, очень гибкий, динамически развивается. Здесь я приведу краткую инструкцию себе на память по его установке и начальной настройке. Я не претендую на полноту изложения, за этим лучше идти в официальную документацию, благо она неплохо написана. Используемый дистрибутив CentOS 6. Пример будет описан на двух однотипных серверах.

Подготовка

Описывать установку CentOS я не буду, этого материала хватает. Я рекомендую устанавливать минимальный netinstall, всё что нужно сами доставим.

Вкратце опишу что нам нужно перед тем как приступить непосредственно к установке pacemaker:

  • Установленная CentOS.
  • Настроенная сеть: сервера должны быть в одной сети (по крайней мере для этого примера).
  • hostname прописаны в /etc/hosts (как свой так и соседа). В данном примере будут использоваться имена node1 и node2.
  • Установлен и настроен SSH. Сгенерированы RSA ключи и разнесены по нодам. Доступ между node1 и node2 по ssh осуществляется без пароля. Есть в принципе способ генерировать ключи непосредственно внутри pacemaker, но этот способ я не рассматриваю, если интересно то вам нужно после установки кластера запустить corosync-keygen и разнести файл /etc/corosync/authkey по нодам.
  • Установлен и настроен NTP.

Устанавливать будем из репозитрия pacemaker - clusterlabs, там стабильная версия и более свежая по сравнение с репозиторием CentOS. Добавляем репозиторий.

1
wget -O /etc/yum.repos.d/pacemaker.repo http://clusterlabs.org/rpm-next/rhel-6/clusterlabs.repo

Для работы с pacemaker я использую crm shell. К моему сожалению он теперь поставляется отдельно, добавим репозиторий для его установки. Можно его не ставить, тогда можно работать с pcmk, но мне удобен больше crm shell.

1
wget -O /etc/yum.repos.d/ha-clustering.repo http://download.opensuse.org/repositories/network:/ha-clustering/CentOS_CentOS-6/network:ha-clustering.repo

Установка

Текущая стабильная версия pacemaker использует архитектуру CMAN (вместо openais). Вообще, история развития кластера pacemaker/corosync очень багатая на глобальные изменения, но это отделная тема. Если интересна история развития кластеров то могу порекомендовать вот эту презентацию от Владислава Богданова, ему кстати большая благодарность.

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

1
# yum install pacemaker cman crmsh ccs

После завершения установки, у меня были следующие версии основных пакетов:

1
2
3
4
5
6
7
8
9
# rpm -qa |grep -e pacemaker -e cman -e corosync -e crmsh
pacemaker-cli-1.1.9-1512.el6.x86_64
pacemaker-1.1.9-1512.el6.x86_64
corosync-1.4.5-35.1.x86_64
pacemaker-libs-1.1.9-1512.el6.x86_64
pacemaker-cluster-libs-1.1.9-1512.el6.x86_64
cman-3.0.12.1-49.el6.x86_64
corosynclib-1.4.5-35.1.x86_64
crmsh-1.2.5-55.6.x86_64

Копируем пример конфига:

1
cp /etc/corosync/corosync.conf.example.udpu /etc/corosync/corosync.conf

Я использую для связи между нодами клсатера unicast вместо multicast, на сеть нагрузки меньше, защита лучше. Редактируем конфиг для нашей ситауции. Для тонкой настройки рекомендую почитать man corosync.conf. Привожу конфиг /etc/corosync/corosync.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Please read the corosync.conf.5 manual page
compatibility: whitetank

totem {
        version: 2
        secauth: off
        threads: 0
        transport: udpu
        interface {
                member {
                        memberaddr: 10.10.0.210
                }
                member {
                        memberaddr: 10.10.0.211
                }
                ringnumber: 0
                bindnetaddr: 10.10.0.0
                mcastaddr: 226.98.1.1
                mcastport: 5500
                ttl: 1
        }
}

logging {
        fileline: off
        to_stderr: no
        to_logfile: yes
        to_syslog: yes
        logfile: /var/log/cluster/corosync.log
        debug: on
        timestamp: on
        logger_subsys {
                subsys: AMF
                debug: off
        }
}

amf {
        mode: disabled
}

Так же не забываем включить сервис Pacemaker:

1
2
3
4
5
6
# cat << END >> /etc/corosync/service.d/pcmk
service {
        name: pacemaker
        ver:  1
}
END

По поводу значения ver: 1, он указывает что сервис pacemaker мы будем запускать сами. Для начала оставим так, в дальнейшем его можно поменять на ver: 0 тогда pacemaker будет запускаться сам после запуска кластера.

Для CMAN необходим ещё один конфигурационный файл /etc/cluster/cluster.conf. Он имеет формат xml. Писать ручками его не практично, будем использовать установленную ранее ccs. Для начала пропишем имя кластеру и добавим ноды:

1
2
3
4
5
# ccs -f /etc/cluster/cluster.conf --createcluster my_cluster
# ccs -f /etc/cluster/cluster.conf --addnode node1
Node node1 added.
# ccs -f /etc/cluster/cluster.conf --addnode node2
Node node2 added.

Затем, как написано в документации pacemaker:

Далее нам нужно научить CMAN как посылать запросы fencing для pacemaker. Мы прописываем это независимо от того, включен fencing в pacemaker, или нет.

1
2
3
4
5
6
7
# ccs -f /etc/cluster/cluster.conf --addfencedev pcmk agent=fence_pcmk
# ccs -f /etc/cluster/cluster.conf --addmethod pcmk-redirect node1
Method pcmk-redirect added to node1.
# ccs -f /etc/cluster/cluster.conf --addmethod pcmk-redirect node2
Method pcmk-redirect added to node2.
# ccs -f /etc/cluster/cluster.conf --addfenceinst pcmk node1 pcmk-redirect port=node1
# ccs -f /etc/cluster/cluster.conf --addfenceinst pcmk node2 pcmk-redirect port=node2

После смотрим что у нас получилось, проверяем синтаксис с помощью ccs_config_validate и копируем этот конфиг на вторую ноду.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# cat /etc/cluster/cluster.conf
<cluster config_version="8" name="my_cluster">
  <fence_daemon/>
  <clusternodes>
    <clusternode name="node1" nodeid="1">
      <fence>
        <method name="pcmk-redirect">
          <device name="pcmk" port="node1"/>
        </method>
      </fence>
    </clusternode>
    <clusternode name="node2" nodeid="2">
      <fence>
        <method name="pcmk-redirect">
          <device name="pcmk" port="node2"/>
        </method>
      </fence>
    </clusternode>
  </clusternodes>
  <cman/>
  <fencedevices>
    <fencedevice agent="fence_pcmk" name="pcmk"/>
  </fencedevices>
  <rm>
    <failoverdomains/>
    <resources/>
  </rm>
</cluster>
# ccs_config_validate
Configuration validates
# scp /etc/cluster/cluster.conf node2:/etc/cluster/cluster.conf

Всё отлично. Повторяем все предыдущие шаги на node2. Теперь мы имеем подготовленные node1 и node2.

Теперь можно запускать кластер, но перед этим ещё одно замечание.

Первоначально, CMAN была написана для rgmanager и предполагает, что кластер не должен запускаться, пока нода не имеет кворума. Поэтому прежде чем пытаться запустить кластер, мы отключим эту особеннсть. Выполняем на node1 и node2:

1
# echo "CMAN_QUORUM_TIMEOUT=0" >> /etc/sysconfig/cman

Теперь пробуем запустить кластер. Выполняем на node1 и node2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# service cman start
Starting cluster: 
   Checking if cluster has been disabled at boot...        [  OK  ]
   Checking Network Manager...                             [  OK  ]
   Global setup...                                         [  OK  ]
   Loading kernel modules...                               [  OK  ]
   Mounting configfs...                                    [  OK  ]
   Starting cman...                                        [  OK  ]
   Waiting for quorum...                                   [  OK  ]
   Starting fenced...                                      [  OK  ]
   Starting dlm_controld...                                [  OK  ]
   Tuning DLM kernel config...                             [  OK  ]
   Starting gfs_controld...                                [  OK  ]
   Unfencing self...                                       [  OK  ]
   Joining fence domain...                                 [  OK  ]

Проверяем ноды:

1
2
3
4
# cman_tool nodes
Node  Sts   Inc   Joined               Name
   1   M     44   2013-06-20 15:20:20  node1
   2   M     40   2013-06-20 15:20:20  node2

Вроде всё чисто, проверяем в /var/log/cluster/corosync.log. Ищем там любые warning и error. Если и там всё отлично, пробуем стартовать pacemaker. Опять же запускаем на node1 и node2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# service pacemaker start
Starting cluster: 
   Checking if cluster has been disabled at boot...        [  OK  ]
   Checking Network Manager...                             [  OK  ]
   Global setup...                                         [  OK  ]
   Loading kernel modules...                               [  OK  ]
   Mounting configfs...                                    [  OK  ]
   Starting cman...                                        [  OK  ]
   Waiting for quorum...                                   [  OK  ]
   Starting fenced...                                      [  OK  ]
   Starting dlm_controld...                                [  OK  ]
   Tuning DLM kernel config...                             [  OK  ]
   Starting gfs_controld...                                [  OK  ]
   Unfencing self...                                       [  OK  ]
   Joining fence domain...                                 [  OK  ]
Starting Pacemaker Cluster Manager:                        [  OK  ]

Снова проверяем /var/log/cluster/corosync.log. Там будет несколько warning по поводу отсутствующей конфигурации /var/lib/pacemaker/cib/cib.xml, но это нормально, мы её сейчас будем создавать.

Проверяем состяние кластера:

1
2
3
4
5
6
7
8
# crm_mon -1
Stack: cman
Current DC: node1 - partition with quorum
Version: 1.1.9-1512.el6-2a917dd
2 Nodes configured, unknown expected votes
0 Resources configured.

Online: [ node1 node2 ]

Установка закончена. Теперь можно приступать к конфигурированию кластера.

Конфигурирование pacemaker

Для управлением конфигурацией кластера будем использовать, как уже раньше отмечалось, crm shell. За разъяснением как работать с pcmk обращайтесь в официальную документацию.

Для начала посмотрим что имеем:

1
2
3
4
5
6
# crm configure show
node node1
node node2
property $id="cib-bootstrap-options" \
        dc-version="1.1.9-1512.el6-2a917dd" \
        cluster-infrastructure="cman"

Пропишем основные параметры:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[root@node2 ~]  # crm
crm(live)# configure 
crm(live)configure# cib new new_conf
INFO: new_conf shadow CIB created
crm(new_conf)configure# cib use new_conf 
crm(new_conf)configure# property stonith-enabled=false
crm(new_conf)configure# property no-quorum-policy=ignore
crm(new_conf)configure# property pe-error-series-max=128
crm(new_conf)configure# property pe-input-series-max=128
crm(new_conf)configure# property pe-warn-series-max=128
crm(new_conf)configure# property symmetric-cluster=false
crm(new_conf)configure# commit 
crm(new_conf)configure# cib use live
crm(live)configure# cib commit new_conf
crm(live)configure# show 
node node1
node node2
property $id="cib-bootstrap-options" \
        dc-version="1.1.9-1512.el6-2a917dd" \
        cluster-infrastructure="cman" \
        stonith-enabled="false" \
        no-quorum-policy="ignore" \
        pe-error-series-max="128" \
        pe-input-series-max="128" \
        pe-warn-series-max="128" \
        symmetric-cluster="false"

Так, теперь немного комментариев:

  • crm(live)configure# cib new new_conf - Создаём новую конфигурацию в CIB, в которой и будем делать все изменения. Не рекомендую работать в основной cib (live). Все изменения в новой конфигурации (new_conf) не применяются на кластер до тех пор пока мы её не перенесём в cib live с помощью cib commit new_conf.

  • property stonith-enabled=false и property no-quorum-policy=ignore - Выключаем fencing и действия по умолчанию при потере кворума.

  • property symmetric-cluster=false - Переводим кластер в несимметричный режим. В отличии от симметричного, он не запускает нигде никакие ресурсы, если это явно не разрешено в location (об этом ниже). В принципе, в данном случае это нам не нужно, даже добавляет неудобства. Однако это добавляет удобства в конфигурировании если нод больше двух и много ресурсов, которые привязаны только к определённым из них. Я не настаиваю на этом параметре, необходимость в нём зависит от архитектуры кластера.

Ресурсы кластера

Ресурсами в кластере могут являться программы, скрипты, ip адреса, файловые системы и т.д. Вариаций много. Скрипты для управления ресурсами находятся в /usr/lib/ocf/resource.d/. К примеру вот список доступных ресурс агентов для провайдера Heartbeat:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# crm ra list ocf heartbeat
AoEtarget           AudibleAlarm        CTDB                ClusterMon
Delay               Dummy               EvmsSCC             Evmsd
Filesystem          ICP                 IPaddr              IPaddr2
IPsrcaddr           IPv6addr            LVM                 LinuxSCSI
MailTo              ManageRAID          ManageVE            Pure-FTPd
Raid1               Route               SAPDatabase         SAPInstance
SendArp             ServeRAID           SphinxSearchDaemon  Squid
Stateful            SysInfo             VIPArip             VirtualDomain
WAS                 WAS6                WinPopup            Xen
Xinetd              anything            apache              conntrackd
db2                 drbd                eDir88              ethmonitor
exportfs            fio                 iSCSILogicalUnit    iSCSITarget
ids                 iscsi               jboss               lsyncd
lxc                 mysql               mysql-proxy         nfsserver
nginx               oracle              oralsnr             pgsql
pingd               portblock           postfix             proftpd
rsyncd              scsi2reservation    sfex                symlink
syslog-ng           tomcat              vmware

Если нет нужного, можно написать свой. Написаны ресурс агенты на bash.­

Приступим к добавлению ресурсов. Создадим к примеру следующую конфигурацию:

Имеется две ноды, на них установлен и настроен nginx, для синхронизации рабочей директории nginx будет использоваться lsyncd/unison. Балансировка будет присходить по двум плавающим ip адресам.

Для начала устанавливаем всё необходимое:

1
yum install nginx lsyncd unison

Про настройку lsyncd я уже писал. Просто меняем в source и в команде запуска unison /mnt/lsynced на что-нибудь вроде /usr/share/nginx/html. Это конечно зависит от nginx.

Проверяем lsyncd. Запускаем на node2 и создаём файлик на ней же /usr/share/nginx/html/test. В выводе будет что-то вроде:

1
2
3
4
5
6
7
[root@node2 ~]  # lsyncd -nodaemon /etc/lsyncd.conf
16:37:59 Normal: Event Create spawns action "/usr/bin/unison -retry 5 -owner -group -batch /usr/share/nginx/html ssh://node1//usr/share/nginx/html"
Contacting server...
Connected [//node1//usr/share/nginx/html -> //node2//usr/share/nginx/html]
...
Synchronization complete  (1 item transferred, 0 skipped, 0 failures)
16:37:59 Normal: Retrying Create on /usr/share/nginx/html//test = 0

Всё отлично, прерываем lsyncd по ctrl-c. Ресурс агент для lsyncd я буду использовать свой. Для этого добавляем его на node1 и node2:

1
wget -O /usr/lib/ocf/resource.d/heartbeat/lsyncd https://raw.github.com/Sibilia/scripts/master/lsyncd

Настройку nginx приводить не буду, подключайте фантазию.

Теперь приступим к созданию ресурсов в кластере. Для lsyncd я буду использовать clone ресурс, а для nginx два разных ресурса для каждой ноды просто для примера. Выбор того или иного способа описания ресурсов зависит лишь от ситуации и ваших личных предпочтений.

1
2
3
4
# crm
crm(live)# configure 
crm(live)configure# cib use new_conf
crm(new_conf)configure# edit

И приводим конфигурацию к следующему виуу:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
node node1
node node2
primitive ipaddr_215 ocf:heartbeat:IPaddr2 \
        params ip="10.10.0.215"
primitive ipaddr_216 ocf:heartbeat:IPaddr2 \
        params ip="10.10.0.216"
primitive lsyncd ocf:heartbeat:lsyncd \
        params cmdline_options="-log scarce"
primitive nginx1 ocf:heartbeat:nginx
primitive nginx2 ocf:heartbeat:nginx
clone lsyncd-cl lsyncd
location ip_215-on-node1 ipaddr_215 1000: node1
location ip_215-on-node2 ipaddr_215 500: node2
location ip_216-on-node1 ipaddr_216 500: node1
location ip_216-on-node2 ipaddr_216 1000: node2
location lsyncd-on-node1 lsyncd-cl 500: node1
location lsyncd-on-node2 lsyncd-cl 500: node2
location nginx1-on-node1 nginx1 inf: node1
location nginx2-on-node2 nginx2 inf: node2
property $id="cib-bootstrap-options" \
        dc-version="1.1.9-1512.el6-2a917dd" \
        cluster-infrastructure="cman" \
        stonith-enabled="false" \
        no-quorum-policy="ignore" \
        pe-error-series-max="128" \
        pe-input-series-max="128" \
        pe-warn-series-max="128" \
        symmetric-cluster="false"

После выходим из редактора и применяем конфигурацию на кластер:

1
2
3
4
5
crm(new_conf)configure# commit
crm(new_conf)configure# cib use
crm(live)configure# cib commit new_conf 
INFO: commited 'new_conf' shadow CIB to the cluster
crm(live)configure# show

Теперь проверяем как всё запустилось:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# crm_mon -fnr1
Stack: cman
Current DC: node2 - partition with quorum
Version: 1.1.9-1512.el6-2a917dd
2 Nodes configured, unknown expected votes
6 Resources configured.

Node node1: online
        nginx1  (ocf::heartbeat:nginx): Started 
        ipaddr_215      (ocf::heartbeat:IPaddr2):       Started 
        lsyncd:1        (ocf::heartbeat:lsyncd):        Started 
Node node2: online
        nginx2  (ocf::heartbeat:nginx): Started 
        lsyncd:0        (ocf::heartbeat:lsyncd):        Started 
        ipaddr_216      (ocf::heartbeat:IPaddr2):       Started 

Inactive resources:

Migration summary:
* Node node2: 
* Node node1: 

Проверим случай выпадения одной ноды, после её вернём обратно:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# crm node standby node1
# crm_mon -fnr1
Stack: cman
Current DC: node2 - partition with quorum
Version: 1.1.9-1512.el6-2a917dd
2 Nodes configured, unknown expected votes
6 Resources configured.

Node node1: standby
Node node2: online
        nginx2  (ocf::heartbeat:nginx): Started 
        ipaddr_215      (ocf::heartbeat:IPaddr2):       Started 
        lsyncd:0        (ocf::heartbeat:lsyncd):        Started 
        ipaddr_216      (ocf::heartbeat:IPaddr2):       Started 

Inactive resources:

 nginx1 (ocf::heartbeat:nginx): Stopped 
 Clone Set: lsyncd-cl [lsyncd]
     Started: [ node2 ]
     Stopped: [ lsyncd:1 ]

Migration summary:
* Node node2: 
* Node node1:

# crm node online node1

Убедились что оба ip адреса переплыли на одну ноду.

Работа с кластером

В рабочем процессе, мы можем управлять состояниями нод и состоянием/размещением ресурсов. К примеру выведем ноду из кластера и вернём обратно:

1
2
# crm node standby node1
# crm node online node1

Можем остановить/переместить ресурс:

1
2
3
4
# crm resource move ipaddr_216 node1
# crm resource stop ipaddr_216
# crm resource start ipaddr_216
# crm resource unmove ipaddr_216

Все эти действия сразу выполняются. Бывает ситуация, когда ресурс вылетает, тогда pacemaker определяет по мониторингу что он не запущен и сново запускает, увеличевая при этом счётчик таких ошибок. К примеру убъём процесс nginx:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# ps aux |grep nginx |grep -v grep
root     10796  0.0  0.4  96024  2040 ?        Ss   18:48   0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx    10798  0.0  0.5  96376  2708 ?        S    18:48   0:00 nginx: worker process                   
# kill -KILL 10796 10798
# crm_mon -fnr1
...
Node node1: online
        nginx1  (ocf::heartbeat:nginx): Started 
        ipaddr_215      (ocf::heartbeat:IPaddr2):       Started 
        lsyncd:1        (ocf::heartbeat:lsyncd):        Started 
Node node2: online
        nginx2  (ocf::heartbeat:nginx): Started 
        ipaddr_216      (ocf::heartbeat:IPaddr2):       Started 
        lsyncd:0        (ocf::heartbeat:lsyncd):        Started 

Inactive resources:

Migration summary:
* Node node2: 
* Node node1: 
   nginx1: migration-threshold=1000000 fail-count=2 last-failure='Thu Jun 20 19:17:19 2013'

Failed actions:
    nginx1_monitor_5000 (node=node1, call=276, rc=7, status=complete): not running

Появилась запись что были ошибки. Если же ресурс не может запуститься, или слишком часто вылетает, то значение счётчика fail-count выставляется в 1000000 и после этого этот ресурс на этой ноде не будет восстонавливаться. А для сброса счётчика можно сделать:

1
# crm resource cleanup nginx1

P.S.

Это лишь самые базовые возможности Pacemaker. Есть ещё очерёдность запуска (order), совместное размещение (colocation), группы и т.д. Если есть какие замечания, пожелания, неточности в статье, оставляйте в комментариях или дишите на почту.

Comments