pacemakerでapacheを冗長化してみた on Cent OS 7
前提
mac 10.15.3
まず3台のVMを作ります。
- n1: apache + VIP
- n2: apache + VIP
- n3: 何もしない人。n1/n2 へのアクセスをしてみる傍観者
n1, n2 両方に pacemaker を通して共通のVIPを割り当てます。
共通のVIPに対するアクセスが、n1/n2 どちらかが止まっても通ることを確認します
referrence to https://www.digitalocean.com/community/tutorials/how-to-set-up-an-apache-active-passive-cluster-using-pacemaker-on-centos-7
最初にひとこと
困ったらreboot! 困ったら cleanup!!
reboot
pcs resource cleanup
1. VMを作る
vagrant + virtualboxを使います
- virtual box をinstall
- vagrantでvmを作る
それぞれのVMのIPは↓を見てください。
brew install vagrant
mkdir ~/vagrant
cd ~/vagrant
# Vagrantfile を作る
cat > Vagrantfile << EOL
Vagrant.configure("2") do |config|
config.vm.box = "bento/centos-7"
config.vm.provision "shell" do |s|
s.inline = "yum install -y vim"
end
config.vm.define "n1" do |server|
server.vm.hostname = "n1"
server.vm.network "private_network", ip: "192.168.33.11"
end
config.vm.define "n2" do |server|
server.vm.hostname = "n2"
server.vm.network "private_network", ip: "192.168.33.12"
end
config.vm.define "n3" do |server|
server.vm.hostname = "n3"
server.vm.network "private_network", ip: "192.168.33.13"
end
end
EOL
# vm x 3 を起動する
vagrant up
VM ができたら、shellを3つ開きます
# shell 1
vagrant ssh n1
# shell 2
vagrant ssh n2
# shell 3
vagrant ssh n3
全部で実施
# rootになる
vagrant$ sudo su -
# hostnameでアクセスできるようにしておく。pacemakerで必要っぽい。
cat <<EOL >> /etc/hosts
192.168.33.11 n1
192.168.33.12 n2
192.168.33.13 n3
192.168.33.99 vip
EOL
cat /etc/hosts
# access check. 全部通れば ok
ping -c1 n1
ping -c1 n2
ping -c1 n3
# vipは通らなくて ok
ping -c1 vip
2. apacheを入れる
n1, n2 で実行します。
# rootになる
vagrant$ sudo su -
# install apache
sudo yum install -y httpd
systemctl enable httpd
# /server-statusを有効にする。pacemakerのhealth checkのdefaultがここになっているためです。
echo -e "\n\
<Location /server-status>\n\
SetHandler server-status\n\
Require all granted\n\
</Location>" > /etc/httpd/conf.d/status.conf
sudo systemctl restart httpd
sudo systemctl status httpd
# nodeがわかるようにする
sudo hostname > /var/www/html/index.html
# アクセスチェック
curl -s localhost # それぞれのhostnameが返ればok
curl -s localhost/server-status | grep title
# これが返ればok → <title>Apache Status</title>
3. pacemaker する!
n1, n2 で実行します。
# rootになる
vagrant$ sudo su -
# install pacemaker etc
sudo yum install -y pacemaker pcs
sudo systemctl enable pcsd.service
sudo systemctl status pcsd.service
sudo systemctl enable corosync.service
sudo systemctl enable pacemaker.service
sudo systemctl restart corosync.service
sudo systemctl restart pacemaker.service
sudo systemctl status corosync.service
sudo systemctl status pacemaker.service
3-1. cluster auth <ハマりpoint>
clusterにnodeを登録する。 n1, n2 を参加させる.
pcs cluster auth n1 n2
Username: hacluster <--- pacemakerが作るこのユーザじゃないとできなかった。ハマった
# パスワードがわからないのでやり直します
sudo passwd hacluster
# firewall止めます
sudo systemctl stop firewalld.service
sudo systemctl mask firewalld.service
再度トライ
pcs cluster auth n1 n2
# しかしどうしても通らないのでrebootしたら通った。
pcs status nodes
Pacemaker Nodes:
Online: n1
Standby:
Standby with resource(s) running:
Maintenance:
Offline:
Pacemaker Remote Nodes:
Online:
Standby:
Standby with resource(s) running:
Maintenance:
Offline:
hacluster ユーザじゃないとダメなのは、おそらく group = haclient か nologin が原因というのを想像しています
今回は深堀りしない. PEMのなにかかもしれない.
groups hacluster
hacluster : haclient
grep hac /etc/passwd
hacluster:x:189:189:cluster user:/home/hacluster:/sbin/nologin
ちなみに vagrant userは
[root@n1 ~]# groups vagrant
vagrant : vagrant
2-2. clusetr setup
n1 だけで実行します
[root@n1 ~]# pcs cluster setup --name webcluster n1 n2
成功すると
cat /etc/corosync/corosync.conf
ここに設定が入ります。
/etc/corosync/corosync.conf がない、というエラーが出たときはrebootしたら直りました。
# start cluster
sudo pcs cluster start --all
全部で
pcs status
結果は
Daemon Status:
corosync: active/enabled
pacemaker: active/enabled
pcsd: active/enabled
disabledのものがあったらrebootすればいいっぽいです。
# 不要な設定を除外します。後でやろうとしたらうまくいかずハマったのでやっぱり先にやったほうがよさそう。
sudo pcs property set stonith-enabled=false
sudo pcs property set no-quorum-policy=ignore
2-3. VIP
ここで、3台のどこにも所属しないVIP 192.168.33.99
を作ります。
n1 だけで実行します。ここでハマったら ocf:heartbeat:IPaddr2
のドキュメントを参照すればいいんですが、 linux-ha.org が大本らしいがサービスダウン?終了?していてろくに情報を集められませんでいsた。google力のなさ。
とりあえず、 ocf:heartbeat:IPaddr2
は
Open Cluster Framework の heartbeat の中の IPaddr2 というモジュール?を使うということのようです。
# nicの指定が大切です。nicを指定しないと、成功するのにNICにVIPが作られませんでした。192.168.33.0/24にいるnicを指定しましょう。
sudo pcs resource create Cluster_VIP ocf:heartbeat:IPaddr2 nic=eth1 ip=192.168.33.99 cidr_netmask=24 op monitor interval=20s
pcs status
成功してるけどVIPがなかったのでcleanupしたら・・
pcs resource cleanup
キタ―――(゚∀゚)―――― !!
[root@n1 ~]# ip a | grep 33
inet 192.168.33.11/24 brd 192.168.33.255 scope global noprefixroute eth1
[root@n2 ~]# ip a | grep 33
inet6 fe80::e233:1e8a:be94:91d9/64 scope link noprefixroute
inet 192.168.33.12/24 brd 192.168.33.255 scope global noprefixroute eth1
inet 192.168.33.99/24 brd 192.168.33.255 scope global secondary eth1
今回は n2 が VIPを取得しました。
# 接続テスト
3台から ping が通るか確認しましょう。
ping -c1 192.168.33.99
# このアドレスは誰が持ってるの?
対向の n1 から、arp で .99 の Mac Address を見てみましょう。
[root@n1 ~]# arp | grep 99
192.168.33.99 ether 08:00:27:8d:10:4f C eth1
これは n2 の eth1 が持っている mac address と一致していますね!
[root@n2 ~]# ifconfig eth1 | grep ether
ether 08:00:27:8d:10:4f txqueuelen 1000 (Ethernet)
これで VIP の設定は終わりです。便利だ。
2-4. apacheを冗長化する
正直、VIPさえ冗長化できればapacheはいらないのではとも思ったりするけど
pacemakerはセットで冗長化できるのでやってみましょう。
これにより、 VIP: active, Apache: 落ちてる みたいな悲しい状況を防ぐことができます。
n1 だけで実行します
# apacheをclusterに登録
sudo pcs resource create WebServer ocf:heartbeat:apache configfile=/etc/httpd/conf/httpd.conf statusurl="http://127.0.0.1/server-status" op monitor interval=20s
# VIPとapacheがセットで切り替わるようにする
sudo pcs constraint colocation add WebServer Cluster_VIP INFINITY
# pcs status
Cluster_VIP (ocf::heartbeat:IPaddr2): Started n1
WebServer (ocf::heartbeat:apache): Stopped
Failed Resource Actions:
* WebServer_start_0 on n1 'unknown error' (1): call=12, status=Timed Out, exitreason='',
last-rc-change='Sun Sep 12 01:39:36 2021', queued=0ms, exec=40004ms
* WebServer_start_0 on n2 'unknown error' (1): call=10, status=Timed Out, exitreason='',
last-rc-change='Sun Sep 12 01:40:17 2021', queued=0ms, exec=40005ms
# エラーが出たら、cleanupしたら直りました
pcs resource cleanup
これで、apacheが落ちてるサーバに VIP がつくことが防げました!
この ocf:heartbeat:apache
は リソースクラス:ネームスペース:リソースエージェント名
ということです
The first field is the resource class, which is the standard the resource agent conforms to. It also tells Pacemaker where to find the script. The IPaddr2 resource agent conforms to the OCF (Open Cluster Framework) standard.
The second field depends on the standard. OCF resources use the second field for the OCF namespace.
The third field is the name of the resource agent.
OCF = Open Cluster Framework
つまり
Open Cluster Framework の heartbeat の中の apache という設定を使うということですね
Resource cluster list
OCF
LSB
Upstart
Systemd
Service
Fencing
Nagios Plugins
https://clusterlabs.org/pacemaker/doc/deprecated/en-US/Pacemaker/1.1/html/Pacemaker_Explained/s-resource-supported.html
しかし、残念ながら linux-ha.org が落ちていて、マニュアルは確認できず。
4. httpアクセスしてみよう! 片方落としてみよう!
早速やってみよう! VIPにアクセスしてみます
[root@n1 ~]# curl -s 192.168.33.99
n2
2号機がactiveです。2号機を止めてみます。
n2# systemctl stop httpd
でも、pacemakerが自動で起動するようです。止まりませんでした。
pacemakerが触らなそうな、nicを止めてしまいます。通常であればsshも切れてしまいますが、このvagrant(virtualbox)では eth0 の 10.0.2.15 で ssh 通信しているので 192系の eth1 は止めても大丈夫です。
n2# ifdown eth1
すると、見事にsplit brainにできました。
# n2の死亡に気づいて、自分をactiveにしているn1くん。優秀。
[root@n1 ~]# pcs status
WebServer (ocf::heartbeat:apache): Started n1
Cluster_VIP (ocf::heartbeat:IPaddr2): Started n1
# 自分の死亡に気付かず、サービス提供し続けるn2。やめてくれ!!
[root@n2 ~]# pcs status
WebServer (ocf::heartbeat:apache): Started n2
Cluster_VIP (ocf::heartbeat:IPaddr2): Started n2
このとき、n2がもっていた .99 のVIPは ifdown とともに死にます。それを検知して n1 が引き継ぎます。
[root@n1 ~]# ip a | grep 99
inet 192.168.33.99/24 brd 192.168.33.255 scope global secondary eth1
[root@n2 ~]# ip a | grep 99
なし
ということで、どこからでも 今度は curl が n1 に行きます。
[root@n1 ~]# curl -s 192.168.33.99
n1
[root@n2 ~]# curl -s 192.168.33.99
n1
[root@n3 ~]# curl -s 192.168.33.99
n1
このとき、standby -> active に変わった n1 ではこんな /var/log/messages
が出ています。
Sep 12 02:19:04 n1 corosync[989]: [TOTEM ] A processor failed, forming new configuration.
Sep 12 02:19:05 n1 corosync[989]: [TOTEM ] A new membership (192.168.33.11:70) was formed. Members left: 2
Sep 12 02:19:05 n1 corosync[989]: [TOTEM ] Failed to receive the leave message. failed: 2
Sep 12 02:19:05 n1 corosync[989]: [CPG ] downlist left_list: 1 received
Sep 12 02:19:05 n1 corosync[989]: [QUORUM] Members[1]: 1
Sep 12 02:19:05 n1 corosync[989]: [MAIN ] Completed service synchronization, ready to provide service.
Sep 12 02:19:05 n1 pacemakerd[1038]: notice: Node n2 state is now lost
Sep 12 02:19:05 n1 crmd[1095]: notice: Node n2 state is now lost
Sep 12 02:19:05 n1 crmd[1095]: warning: No reason to expect node 2 to be down
Sep 12 02:19:05 n1 crmd[1095]: notice: Stonith/shutdown of n2 not matched
Sep 12 02:19:05 n1 crmd[1095]: notice: State transition S_IDLE -> S_POLICY_ENGINE
Sep 12 02:19:05 n1 crmd[1095]: warning: No reason to expect node 2 to be down
Sep 12 02:19:05 n1 crmd[1095]: notice: Stonith/shutdown of n2 not matched
Sep 12 02:19:05 n1 attrd[1093]: notice: Node n2 state is now lost
Sep 12 02:19:05 n1 attrd[1093]: notice: Removing all n2 attributes for peer loss
Sep 12 02:19:05 n1 attrd[1093]: notice: Purged 1 peer with id=2 and/or uname=n2 from the membership cache
Sep 12 02:19:05 n1 cib[1085]: notice: Node n2 state is now lost
Sep 12 02:19:05 n1 cib[1085]: notice: Purged 1 peer with id=2 and/or uname=n2 from the membership cache
Sep 12 02:19:05 n1 stonith-ng[1086]: notice: Node n2 state is now lost
Sep 12 02:19:05 n1 stonith-ng[1086]: notice: Purged 1 peer with id=2 and/or uname=n2 from the membership cache
Sep 12 02:19:06 n1 pengine[1094]: notice: * Start WebServer ( n1 )
Sep 12 02:19:06 n1 pengine[1094]: notice: * Start Cluster_VIP ( n1 )
Sep 12 02:19:06 n1 pengine[1094]: notice: Calculated transition 6, saving inputs in /var/lib/pacemaker/pengine/pe-input-22.bz2
Sep 12 02:19:06 n1 crmd[1095]: notice: Initiating start operation WebServer_start_0 locally on n1
Sep 12 02:19:06 n1 crmd[1095]: notice: Initiating start operation Cluster_VIP_start_0 locally on n1
Sep 12 02:19:06 n1 IPaddr2(Cluster_VIP)[4191]: INFO: Adding inet address 192.168.33.99/24 with broadcast address 192.168.33.255 to device eth1
Sep 12 02:19:06 n1 IPaddr2(Cluster_VIP)[4191]: INFO: Bringing device eth1 up
Sep 12 02:19:06 n1 apache(WebServer)[4190]: INFO: AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 192.168.33.11. Set the 'ServerName' directive globally to suppress this message
Sep 12 02:19:06 n1 IPaddr2(Cluster_VIP)[4191]: INFO: /usr/libexec/heartbeat/send_arp -i 200 -r 5 -p /var/run/resource-agents/send_arp-192.168.33.99 eth1 192.168.33.99 auto not_used not_used
Sep 12 02:19:06 n1 crmd[1095]: notice: Result of start operation for Cluster_VIP on n1: 0 (ok)
Sep 12 02:19:06 n1 crmd[1095]: notice: Initiating monitor operation Cluster_VIP_monitor_3000 locally on n1
Sep 12 02:19:06 n1 crmd[1095]: notice: Result of start operation for WebServer on n1: 0 (ok)
Sep 12 02:19:06 n1 crmd[1095]: notice: Initiating monitor operation WebServer_monitor_20000 locally on n1
Sep 12 02:19:06 n1 crmd[1095]: notice: Transition 6 (Complete=4, Pending=0, Fired=0, Skipped=0, Incomplete=0, Source=/var/lib/pacemaker/pengine/pe-input-22.bz2): Complete
Sep 12 02:19:06 n1 crmd[1095]: notice: State transition S_TRANSITION_ENGINE -> S_IDLE
Sep 12 02:19:10 n1 IPaddr2(Cluster_VIP)[4191]: INFO: ARPING 192.168.33.99 from 192.168.33.99 eth1#012Sent 5 probes (5 broadcast(s))#012Received 0 response(s)
ざっと解説
crmdというデーモンがチェックしてるみたい
n2 死亡を確認
notice: Node n2 state is now lost
メンバーから n2 を除外
notice: Purged 1 peer with id=2 and/or uname=n2 from the membership cache
サービスを有効にする
notice: Initiating start operation WebServer_start_0 locally on n1
notice: Initiating start operation Cluster_VIP_start_0 locally on n1
ここで IPaddr2 が VIP を作る
IPaddr2(Cluster_VIP)[4191]: INFO: Adding inet address 192.168.33.99/24 with broadcast address 192.168.33.255 to device eth1
VIP宛の通信が n2 にいかないように、arp を `not_used` で更新してくれるみたい! 優秀。
IPaddr2(Cluster_VIP)[4191]: INFO: /usr/libexec/heartbeat/send_arp -i 200 -r 5 -p /var/run/resource-agents/send_arp-192.168.33.99 eth1 192.168.33.99 auto not_used not_used
VIP宛のarpを自分で更新した? 時間差があるから外からのrequestによって?
IPaddr2(Cluster_VIP)[4191]: INFO: ARPING 192.168.33.99 from 192.168.33.99 eth1#012Sent 5 probes (5 broadcast(s))#012Received 0 response(s)
素晴らしい!!! VIPだけじゃなくて apacheのstateもセットで管理できるのすごいわ。
pacemaker完全に理解した!