CentOS 6でPacemaker 1.1をつかう

CentOS 6.6(x86_64)にLinux-HA Japan版のPacemaker 1.1をインストールしてみました。

作業手順そのものはLinux-HA JapanのPacemaker-1.1.12リリース記事に書かれているものにアレンジを加えたものです。以下のURLがその内容ですので、あわせてご覧いただければと思います。
http://linux-ha.sourceforge.jp/wp/archives/4051

# 前提

* CentOS 6.6 x86_64版を最小インストール(CentOS-6.6-x86_64-minimal.isoを使用)
* CentOS 6.6インストール後は全パッケージを最新版にアップデート
* ノードは `n1`, `n2` というホスト名を持つ2台
* NICはサービス用に1つ(eth0)、死活監視用に1つ(eth1)
* サービス用(eth0)は実験ということでDHCPでIPv4アドレスを取得
* 死活監視用(eth1)は `192.168.128.1` と `192.168.128.2` のIPv4アドレスをそれぞれに設定

作業はWindows版の Virtual Box で行いました。

# インストール
Linux-HA Japanのリポジトリパッケージをインストールします。

```
yum install -y http://iij.dl.sourceforge.jp/linux-ha/62369/pacemaker-repo-1.1.12-1.1.el6.x86_64.rpm
```

CentOS6.6の場合、ディストリビューションのリポジトリに含まれるPacemakerのバージョンが1.1.12で競合するので、`CentOS-Base.repo`からPacemaker関連パッケージを除外する設定をします。

```diff:/etc/yum.repos.d/CentOS-Base.repo
--- /etc/yum.repos.d/CentOS-Base.repo   2015-02-19 15:02:14.585005234 +0900
+++ /etc/yum.repos.d/CentOS-Base.repo.new       2015-02-19 15:02:11.284585805 +0900
@@ -16,6 +16,7 @@
 #baseurl=http://mirror.centos.org/centos/$releasever/os/$basearch/
 gpgcheck=1
 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
+exclude=pacemaker*,corosync*,resource-agents*,cluster-glue*,libqb*

 #released updates
 [updates]
@@ -24,6 +25,7 @@
 #baseurl=http://mirror.centos.org/centos/$releasever/updates/$basearch/
 gpgcheck=1
 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6
+exclude=pacemaker*,corosync*,resource-agents*,cluster-glue*,libqb*

 #additional packages that may be useful
 [extras]
```

この設定で後々`yum update`したときの競合を回避することが出来ると思います。

Pacemaker 1.1の関連パッケージをインストールします。

```
yum install -y pacemaker-all
```

# 設定

## iptablesのルール作成

時と場合による作業です。
例えば、動かしてみたいだけの場合には `service iptables stop` などとしてパケットフィルタに全許可を指示してもよいでしょう。
ここではPacemakerの動作に必要な通信を許可するルールを追加します。

今回の構成はノードが2台しかないので、UDPのユニキャストで死活監視を行う方針をとります。
ノードが増えたらマルチキャストを使ったほうがトラフィックも減りますし、管理もらくになります。

現時点でのルールはインストール直後のものになっています。ちょうど以下のようなものです。

```/etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
```

これに死活監視インタフェイスでのUDP 5405番ポートの使用を許可するルールを追加します。
自分から接続に行くパターンと、相手から接続に来るパターンの両方がありますのでそれぞれ追加しています。
折り返しは先頭の `-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT` でまかなっています。

```/etc/sysconfig/iptables
# Firewall configuration written by system-config-firewall
# Manual customization of this file is not recommended.
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -i eth1 -m udp -p udp --dport 5405 -j ACCEPT
-A OUTPUT -o eth1 -m udp -p udp --dport 5405 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
COMMIT
```

## Corosyncの設定

Corosyncの動作に必要な設定を行います。
`/etc/corosync/corosync.conf.example.udpu` をコピーして `/etc/corosync/corosync.conf` を作成し、編集していくと楽だと思います。

```plain:/etc/corosync/corosync.conf
# Please read the corosync.conf.5 manual page
totem {
        version: 2

        crypto_cipher: none
        crypto_hash: none

        interface {
                ringnumber: 0
                bindnetaddr: 192.168.128.0
                mcastport: 5405
                ttl: 1
        }
        transport: udpu
}

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

nodelist {
        node {
                ring0_addr: 192.168.128.1
                nodeid: 1
        }

        node {
                ring0_addr: 192.168.128.2
                nodeid: 2
        }
}

quorum {
        # Enable and configure quorum subsystem (default: off)
        # see also corosync.conf.5 and votequorum.5
        provider: corosync_votequorum
        expected_votes: 2
}
```

編集箇所は `totem` ディレクティブの `interface` 定義部分と、`logging` ディレクティブ、`nodelist` ディレクティブの `node` 定義部分、そして `quorum` ディレクティブです。

詳細は割愛しますが、基本的にはノードのアドレスの設定です。
ログファイルは `/var/log/cluster/corosync.log` です。結構たくさん出力されますので、logrotateの設定はしておいたほうが良いと思います(今回はしません)。
`quorum` ディレクティブの `expected_votes` の値はクラスタを構成するノード数です。12ノードクラスタなら `expected_votes: 12` のようにします。

設定した内容は両方のノードで同じにしておきます(scpとかで送ったらよいです)。

```
# scp /etc/corosync/corosync.conf root@192.168.128.2:/etc/corosync/corosync.conf
root@192.168.128.2's password:
corosync.conf                                              100%  704     0.7KB/s   00:00
```

## Pacemaker設定ファイルの設定

Pacemakerそのものの設定は `/etc/sysconfig/pacemaker` で行います。この設定は「クラスタの制御の設定ではない」のでご注意ください。

Pacemakerの内部プロセスが死亡した場合にもノード故障とみなすように、次の行を末尾に追加します。

```
export PCMK_fail_fast=yes
```

この変更も両方のノードで行っておきます。

## Pacemaker起動スクリプトの設定

* ノードをシャットダウンするときに、Pacemakerを正常停止するため
* watchdogを利用するため

に `/etc/init/pacemaker.combined.conf`を修正します。

```diff

# diff -u /etc/init/pacemaker.combined.conf{.orig,}
--- /etc/init/pacemaker.combined.conf.orig      2014-12-13 11:10:18.929450536 +0900
+++ /etc/init/pacemaker.combined.conf   2014-12-13 11:13:55.044921858 +0900
@@ -2,6 +2,7 @@
 #
 # Starts Corosync cluster engine and Pacemaker cluster manager.

+stop on runlevel [0123456]
 kill timeout 3600
 respawn

@@ -20,7 +21,7 @@
 pre-start script
     # setup the software watchdog which corosync uses.
     # rewrite according to environment.
-    modprobe softdog soft_margin=60
+    [ -c /dev/watchdog ] || modprobe softdog soft_margin=60
     pidof corosync || start corosync

     # if you use corosync-notifyd, uncomment the line below.
@@ -49,7 +50,7 @@
     rm -f /var/run/$prog.pid

     # if you use watchdog of corosync, uncomment the line below.
-    #pidof corosync || false
+    pidof corosync || false

     pidof crmd || stop corosync

```

この変更も両方のノードで行っておきます。

# Pacemakerの起動

Pacemakerの起動はUpstartを使用していますので、次のようにします。

```
# initctl start pacemaker.combined
```

停止の場合は

```
# initctl stop pacemaker.combined
```

となります。

`service corosync start` ではありませんのでご注意ください。

## 起動確認

`initctl start pacemaker.combined` を両方のノードで実行したら次のコマンドを実行します。

```
# crm_mon -A
```

しばらくまって、次のように `Online: [ n1 n2 ]` が見えたら成功です。

```
Last updated: Sat Dec 13 11:19:09 2014
Last change: Sat Dec 13 11:18:39 2014
Stack: corosync
Current DC: n1 (1) - partition with quorum
Version: 1.1.12-561c4cf
2 Nodes configured
0 Resources configured


Online: [ n1 n2 ]


Node Attributes:
* Node n1:
* Node n2:
```

# クラスタの初期設定

クラスタが無事に構成できたら、基本的な初期設定を行います。もちろん、絶対に必要なものでもありませんし、この設定でないといけないわけでもありません。

## クオーラムを取得できなかったときの挙動

Pacemakerでは、ノードが通信可能なノード数がクラスタ全体の過半数を超えると、クオーラム(定足数)を取得でき、そのクラスタは有効になります。
これは障害時に重要な考え方で、例えば3台構成のクラスタで1台の死活監視ネットワークが切れてしまった場合、その1台はクラスタとして活動できないようにすることができます。これによって「生きているクラスタが複数存在する状態」を回避することができます。

ですが、今回のクラスタは2台です。ノード同士が連絡ができない状態になると、どちらも過半数の投票を獲得できず、クラスタは停止してしまいます。したがって、クオーラムを獲得できなかった場合の挙動として `ignore` (無視)を設定しなくてはいけません。

```
# crm configure property no-quorum-policy=ignore
```

詳細は http://clusterlabs.org/doc/en-US/Pacemaker/1.1/html-single/Pacemaker_Explained/#_available_cluster_options をご覧ください。

## STONITH無効化

Pacemakerは故障したノードを強制的にクラスタから離脱させる(フェンス)仕組みとして、STONITH(Shoot The Other Node In The Head)というものを持っています。
ノードがIPMIに対応していて、IPMIで電源制御が出来る場合には、STONITH設定が推奨されます。

今回はSTONITHを使用しませんので、無効化しておきます。

```
# crm configure property stonith-enabled=false
```

## ポリシエンジンの状態遷移履歴数の設定

Pacemakerの関連プロセスでポリシエンジン(pengine)というものがあります。
このポリシエンジンが、クラスタの状態を定期的にもしくは状態に変化があった時にファイルとして保存していきます。
`/var/lib/pacemaker/pengine` が保存先になっており、サイズとしては小さいのですが、無制限に作られるのもよくないので、数に制限をかけます。

設定としては3種類で、次のとおりです。

* pe-input-series-max
* pe-error-series-max
* pe-warn-series-max

今回はそれぞれ3000を設定します。

```
# crm configure property pe-input-series-max=3000
# crm configure property pe-error-series-max=3000
# crm configure property pe-warn-series-max=3000
```

## リソースのデフォルトオプション

Pacemakerでは制御対象のことをリソースと呼びます。リソースに設定するデフォルトのオプションを設定します。

### 配置固定

Pacemaker(ポリシエンジン)によってリソースが配置されるノードが決定されます。
ノードの決定は、スコアと呼ばれるものを計算することで行われますが、基本的に一旦動いたリソースはあまり配置を変えてほしくはありませんので、これを固定するようにします。

`resource-stickiness` というオプションを `INFINITY` (無限大。内部的には1000000。多分)に設定します。

```
# crm configure rsc_defaults resource-stickiness=INFINITY
```

場合によってはスコアの変化でリソースを再配置してほしいこともありますので、その際は値を調整するか、リソース個別に設定してください。
個人的には200くらいを設定しておけばだいたいOKという感覚です。

### リソースがフェイルオーバーをする故障回数境界値

リソースが故障(例えばプロセスが落ちるとか)した場合にすぐにリソースを再配置(フェイルオーバー)するか、数回再起動を試みるかを設定します。

`migration-threshold` というオプションを `1` にすると、1回故障したらすぐにフェイルオーバーします。
`2` にすると、1回目の故障は同じノードでリソースの再起動が行われ、もう一度故障(つまり2回目の故障)するとフェイルオーバーします。
`0` にすると、何度故障してもフェイルオーバーしません。

今回は `1` を設定します。

```
# crm configure rsc_defaults migration-threshold=1
```

# あとは

ここまできたら、あとは制御対象のリソースを設定していき、ルールを書いていくだけです。
といってもここからが一番むずかしいところではあるのですが。