Pacemaker + Heartbeat でアクティブ・スタンバイを構成するレシピ

#[SoftLayerクッキングLABO] (http://qiita.com/MahoTakara/items/464da29ccf932698b753)

# このレシピで出来ること

Debian や Ubuntu で、Pacemaker + Heartbeatを利用して、アクティブ・スタンバイの２重化構成を作ります。 Debianのリポジトリでは、Heartbeat のパッケージの依存パッケージに Pacemaker が含まれています。　ところが、現在推奨となっている Pacemaker + Corosync でインストールする事ができませんでした。 頑張って自力でコンパイルするのも、なかなか面倒なので Debianで、Pacemaker + Heartbeatを使って２重化すレシピです。次の図では、右側の主と待機サーバーの２台の設定を実施するものです。
それから、CentOS/RedHat では Heartbeat が既にリポジトリに登録されていないため、Pacemaker + Corosync の記事を書きましたので、そちらを参照頂ければ幸いです。


![スクリーンショット 2015-10-12 21.39.12.png](https://qiita-image-store.s3.amazonaws.com/0/42829/487957ec-1292-95c6-4340-386945f61445.png)


# レシピの要約
この pm_heartbeat01 レシピは、以下の設定を適用します。

- heartbeat のパッケージ導入
- アクティブとスタンバイのIPアドレス、ホスト名の設定
- ホスト名の再設定 (Heartbeat用)
- 認証キー設定
- hostsファイルに追加登録
- ha.cf 設定
- haresources 設定

# レシピの説明


## 代表IPの準備
アクティブ・スタンバイのクラスタを代表して、サービスを提供するIPアドレスを 仮想IPアドレス (VIP) と呼ばれます。このVIPは、元々サーバーに付与されているIPアドレスではなく、クラスタ・ソフトウェアによって、サービス提供側のサーバーに付与されるIPアドレスです。 このアドレスをオーダーするには、ソフトレイヤー活用ガイド第2部「コンフィグレーション・ガイド」 [4.2 サーバーを替えても同じIPアドレスを継続するには？] (https://www.change-makers.jp/post/10345) をご参照ねがいます。

このレシピのために確保したサブネットのidは、758078 で、このサブネットの中からIPアドレスを選んで割当ます。このサブネットの管理は、ユーザーが自己管理しなければなりません。

```
$ slcli subnet list -d tok02 --sortby identifier
:.........:....................:...................:............:.........:.....:..........:....:
:    id   :     identifier     :        type       : datacenter : vlan_id : IPs : hardware : vs :
:.........:....................:...................:............:.........:.....:..........:....:
: 1038857 :  10.132.253.0/26   :      PRIMARY      :   tok02    :  978115 :  64 :    0     : 3  :
:  758078 :  10.132.5.128/26   : SECONDARY_ON_VLAN :   tok02    :  978115 :  64 :    0     : 0  :
: 1038909 : 161.202.142.192/28 :      PRIMARY      :   tok02    :  978113 :  16 :    0     : 3  :
:.........:....................:...................:............:.........:.....:..........:....:
```


## レシピのファイル
クックブックの中で設定するのは６本のファイルです。

```
chef@ChefWs:~/chef-repo/site-cookbooks$ tree pm_heartbeat01/
pm_heartbeat01/
├── CHANGELOG.md
├── README.md
├── attributes
│   └── default.rb (1) アクティブとスタンバイのIPアドレス、ホスト名を設定
├── definitions
├── files
├── libraries
├── metadata.rb  (2) hostsファイル操作の共通レシピを追加
├── providers
├── recipes
│   └── default.rb (3) レシピ本体
├── resources
└── templates
    └── default
        ├── authkeys.erb  (4) HeartBeat 認証キー
        ├── ha.cf.erb     (5) HeartBeat 設定ファイル
        └── haresources.erb  (6) リソースファイル

```
上記のディレクトリのスグ上の Berksfileに cookbook 'hostsfile' を追加しておきます。

```
chef@ChefWs:~/chef-repo$ cat Berksfile
site :opscode
source "https://api.berkshelf.com"
cookbook 'hostsfile'
```


## サーバーの準備
ご参考までに、このレシピを実行するための最小スペックのサーバーをオーダーするシェルを以下に挙げておきます。

```
#!/bin/bash
#
slcli vs create \
--hostname server1 --domain softlayer.com \
--datacenter tok02 \
--cpu 1 --memory 1 \
--os DEBIAN_8_64 \
--billing hourly \
--public \
--postinstall https://raw.githubusercontent.com/takara9/ProvisioningScript/master/debian_basic_config \
--key 370981 \
--network 100
#
slcli vs create \
--hostname server2 --domain softlayer.com \
--datacenter tok02 \
--cpu 1 --memory 1 \
--os DEBIAN_8_64 \
--billing hourly \
--public \
--postinstall https://raw.githubusercontent.com/takara9/ProvisioningScript/master/debian_basic_config \
--key 370981 \
--network 100
```
上記のシェルでオーダーした結果は、以下の様になりました。このバックエンド側のIPアドレスを使って、レシピのアトリビュートファイルの設定します。

```
chef@ChefWs:~/shells$ slcli vs list
:..........:..........:.................:...............:............:........:
:    id    : hostname :    primary_ip   :   backend_ip  : datacenter : action :
:..........:..........:.................:...............:............:........:
: 13095065 : server1  : 161.202.142.196 :  10.132.253.7 :   tok02    :   -    :
: 13095069 : server2  : 161.202.142.203 : 10.132.253.17 :   tok02    :   -    :
:..........:..........:.................:...............:............:........:
```
## (1) 両サーバーのIPアドレスなどパラメータ

**VIPだけを設定する場合**
サーバーのIPアドレスなどの毎回設定が必要な部分は、attributes のディレクトリ下のファイルに集めてあります。 注釈を参考に環境に合わせて値をセットします。

```lang:attributes/default.rb
default["mystate"] = 'MASTER'    <--- 自ノードが主系の場合、待機系にする時はBACKUPとする
default["master"]["hostname"] = 'node1'       <--- 主系のホスト名、IPアドレスをセット 
default["master"]["ipaddr"] = '10.132.253.7'   
default["backup"]["hostname"] = 'node2'       <--- 待機系のホスト名、IPアドレスをセット
default["backup"]["ipaddr"] = '10.132.253.17'

default["vip"]["addr"] = "10.132.5.132/26/eth0"   <--- 仮想IPアドレス、ネットマスク、インタフェース
default["vip"]["storage"] = ""   <--- 以下の例を参考に必要に応じて設定
default["vip"]["service"] = ""
```

**サービスを共用ディスクを指定する場合の変更部分**
以下の例は、VIPを持つサーバー側に、iSCSIストレージを /data1 にマウントする場合の設定例です。

```lang:attributes/default.rb
default["vip"]["addr"] = "10.132.5.132/26/eth0"   
default["vip"]["storage"] = "Filesystem::/dev/mapper/iscsimp1::/data1::ext4"
default["vip"]["service"] = "mysql"
```


## (2) hostsファイル操作の共通レシピを追加
hostsファイルに、IPアドレス、ホスト名を追加するレシピは、自分で書くと、結構なコード量になるので、[CHEF SUPERMARKET https://supermarket.chef.io/] (https://supermarket.chef.io/) の中から利用できるものを選んできます。 
ここでは、hostsfile https://supermarket.chef.io/cookbooks/hostsfile/versions/0.1.1 を利用する設定をおこないます。

```lang:metadata.rb
name             'pm_heartbeat01'
maintainer       'YOUR_COMPANY_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures pm_heartbeat01'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version          '0.1.0'

depends          'hostsfile'  <-- ここを追加
```

## (3) レシピ本体
このレシピの本物は、GitHubに登録してあります。 ポイントとなる部分は、このリストに注釈します。

```lang:recipes/default.rb

# -*- coding: utf-8 -*-
#
# Cookbook Name:: pm_heartbeat01
# Recipe:: default

# 
# パッケージのインストール 
#
execute 'apt-get update' do
  command 'apt-get update'
  ignore_failure true
end

%w{
  heartbeat   <-- これを指定すれば、pacemakerも一緒に入るが、pacemakerを指定してインストールできない点注意
}.each do |pkgname|
  package "#{pkgname}" do
    action :install
  end
end

#
# アクティブとスタンバイのIPアドレス設定
#
mystate = node["mystate"]   <-- アトリビュートに指定した文字列で切換え MASTER <-> BACKUP
if mystate == 'MASTER' then
  peer_ip = node["backup"]["ipaddr"]
  myname = node["master"]["hostname"]
else
  peer_ip = node["master"]["ipaddr"]
  myname = node["backup"]["hostname"]
end

#
# ホスト名の変更    <-- クラスタのノード名をホスト名となる様に上書きします。
#
file "/etc/hostname" do
  owner "root"
  group "root"
  mode 0644
  hostname = "#{myname}\n"
  content hostname
  action :create
end
execute 'change_hostname' do
  command 'hostname -F /etc/hostname'
  action :run
end

#
# ハートビートの認証キー設定
#
template "/etc/heartbeat/authkeys" do
  source "authkeys.erb"
  owner "root"
  group "root"
  mode 0600
end

#
# パラメータの取り込み
#
vip_master = node["master"]["hostname"]
vip_backup = node["backup"]["hostname"]
vip_addr = node["vip"]["addr"]
vip_storage = node["vip"]["storage"]
vip_service = node["vip"]["service"]

#
# HOSTSファイルへノード名の追加
# 
master_hostname = node["master"]["hostname"]
master_ipaddr = node["master"]["ipaddr"]
hostsfile_entry "#{master_ipaddr}" do
  hostname master_hostname
  action :create
end
backup_hostname = node["backup"]["hostname"]
backup_ipaddr = node["backup"]["ipaddr"]
hostsfile_entry "#{backup_ipaddr}" do
  hostname backup_hostname
  action :create
end

#
# ハートビートの設定
#
template "/etc/heartbeat/ha.cf" do
  source "ha.cf.erb"
  owner "root"
  group "root"
  mode 0644
  variables({
    :master => vip_master,
    :backup => vip_backup,
    :peer => peer_ip,
  })
end

#
# リソースの設定
#
template "/etc/heartbeat/haresources" do
  source "haresources.erb"
  owner "root"
  group "root"
  mode 0644
  variables({
    :master => vip_master,
    :addr   => vip_addr,
    :storage => vip_storage,
    :service => vip_service,
  })
end

#
# ペースメーカー＆ハートビートの開始
#
service 'heartbeat' do
  action [ :enable, :start ]
end
```

## (4) heartbeat 認証キー
クラスタを構成するサーバー同士で同じ内容のファイルがあれば良い

```
auth 1
1 sha1 5692c19f3beb20008a590d05d52f59aed1f1b4fd
```

## (5) heartbeat 設定ファイル
コメントを除いて設定だけを抜く出したものです。プラベートVLAN側の eth0 をクラスタ間の相互監視用に設定します。ソフトレイヤーでは、マルチキャストが通るので利用します。　ノード名はレシピからセットします。

```
debugfile /var/log/ha-debug
logfile /var/log/ha-log
logfacility     local0
keepalive 2
deadtime 20
warntime 10
initdead 60
bcast   eth0 　　　<-- eth0 プライベート側でハートビートを取ります
mcast eth0 225.0.0.1 694 1 0  <-- マルチキャスト も同じ
auto_failback off <-- 自動フェイルバック無し
node    <%= @master %>  <-- ノード名指定
node    <%= @backup %>  
```

## (6) heartbeat リソースファイル
VIP、共有ストレージのマウントポインt、サービス名の項目ですが、すべれレシピからセットします。

```
<%= @master %> IPaddr::<%= @addr %> <%= @storage %> <%= @service %>
```

#レシピの適用手順

このレシピは、物理サーバーと仮想サーバーのどちらでも対応しますが、簡単に試せる様に最小仮想サーバーでの適用例をご紹介します。次のシェルを利用して、仮想サーバーを注文します。 slcli コマンドの説明は "slcli vs create -h " で見る事ができます。

```
$ slcli vs list
:..........:..........:.................:...............:............:........:
:    id    : hostname :    primary_ip   :   backend_ip  : datacenter : action :
:..........:..........:.................:...............:............:........:
: 13040349 :  webap1  : 161.202.142.196 :  10.132.253.7 :   tok02    :   -    :
:..........:..........:.................:...............:............:........:
```
Chef Solo のリポジトリのあるサーバーから、ssh コマンドで ssh鍵を使ってログインしています。　ログインできれば、Chefでセットアップする準備の完了です。　ここでは何もしないでログアウトします。


```
$ ssh root@10.132.253.7 -i ~/key/chefkey
Welcome to Ubuntu 14.04.2 LTS (GNU/Linux 3.13.0-55-generic x86_64)

 * Documentation:  https://help.ubuntu.com/

The programs included with the Ubuntu system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Ubuntu comes with ABSOLUTELY NO WARRANTY, to the extent permitted by
applicable law.

root@webap1:~# logout
```
次のコマンドで、マスターとバックアップと両方に対して、chef のインスール と レシピの適用を実施します。 

最初にマスター（主側）の設定をおこないます。このコマンドを実行する前に、アトリビュートのdefault[mystate]が、「**MASTER**」に設定されていることを確認してから実行します。 

```
chef@ChefWs:~/chef-repo$ knife solo bootstrap 10.132.253.7 -x root -r 'recipe[pc_heartbeat01]' -i ~/key/chefkey
```
以下の部分に注意です。

```lang:attributes/default.rb
default["mystate"] = 'MASTER'    <--- 自ノードが主系の場合、待機系にする時はBACKUPとする
```

次にバックアップ（待機側）の設定をおこないます。　前述のアトリビュートのdefault[mystate]が、「**BACKUP**」になっていなければなりません。それからIPアドレスを間違えない様に注意が必要ですね。

```
chef@ChefWs:~/chef-repo$ knife solo bootstrap 10.132.253.17 -x root -r 'recipe[pc_heartbeat01]' -i ~/key/chefkey
```

設定完了時のメッセージでは、設定作業が16秒で完了していることがわかります。 

```
  * service[heartbeat] action enable (up to date)
  * service[heartbeat] action start
    - start service service[heartbeat]

Running handlers:
Running handlers complete
Chef Client finished, 12/13 resources updated in 16.00316382 seconds
```
ifconfig コマンドで、VIPが確保している事を確認します。 以下の実行例では、eth0:0 にVIPが設定されていることが判ります。

```
root@node1:~# ifconfig eth0:0
eth0:0    Link encap:Ethernet  HWaddr 06:a9:3d:0e:8a:7c  
          inet addr:10.132.5.132  Bcast:10.132.5.191  Mask:255.255.255.192
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

root@node1:~# ifconfig eth0  
eth0      Link encap:Ethernet  HWaddr 06:a9:3d:0e:8a:7c  
          inet addr:10.132.253.7  Bcast:10.132.253.63  Mask:255.255.255.192
          inet6 addr: fe80::4a9:3dff:fe0e:8a7c/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:84054 errors:0 dropped:0 overruns:0 frame:0
          TX packets:15339 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:113952626 (108.6 MiB)  TX bytes:2299736 (2.1 MiB)
```



# 対応するソフトレイヤー活用ガイド
このレシピを利用することで、以下の設計パターンや設定作業を自動化することができます。

- [ソフトレイヤー活用ガイド第3部「デザインパターン」2.3 IPアドレスの動的な移動（HA構成のIP付替え)] (https://www.change-makers.jp/post/10245)
- [ソフトレイヤー活用ガイド第2部「コンフィグレーション・ガイド」3.4 アクティブ・スタンバイのクラスタを構成するには？](https://www.change-makers.jp/post/10336)


# テスト済みのLinuxディストリビューション
SoftLayerでサーバーオーダー時に選択できるOSの中から、確認できたもののリストです。

- Ubuntu 14.04 64bit minimal install
- Debian 8.1 64bit minimal install


# レシピの置き場所
最新版のレシピはGitHubにあります。
- GitHub takara9/chef-repo/ iscsiStorage01  https://github.com/takara9/chef-repo/tree/master/site-cookbooks/pm_heartbeat01


# Chef 関連マニュアル
このレシピを作るにあたって参照したCHEFマニュアルのリンクです。
- script  (https://docs.chef.io/resource_script.html )
- execute (https://docs.chef.io/resource_execute.html )
- package (https://docs.chef.io/resource_package.html )
- template (https://docs.chef.io/resource_template.html)
- file (https://docs.chef.io/resource_file.html)


# 参考資料
- [Pacemaker Homepage] (http://clusterlabs.org/)
- [第1回　Pacemakerの歴史を見てみよう！](http://gihyo.jp/admin/serial/01/pacemaker/0001?page=2)
- [Pacemaker、Heartbeat、Corosyncの概要](https://www.3ware.co.jp/product/linbit-cluster-support/pacemaker-heartbeat)