夜明け前の最も暗いとき

技術的なやったことをメモするブログ

Pacemakerによる冗長構成を試す

PacemakerはLinuxで使われる冗長化ソフトウェアです。複数ノードでACT/SBY構成などによる冗長を確保したい場合に使用されます。 今回は仮想環境上に3ノードのクラスターを構成し、Apaceh Webサーバを実行します。

VMを下記の通り作成します。

■cluster1.example.net
 IP:192.168.11.121/24
■cluster2.example.net
 IP:192.168.11.122/24
■cluster3.example.net
 IP:192.168.11.123/24

Pacemakerの構築はこのサイトを参考にさせていただきました。今回は複数ノードあるため、構成管理ツールであるansibleで環境を構築します。 作業用の環境にansibleをインストールし、下記のplaybookをcluster_setup.ymlという名前で作成します。

 - hosts: cluster_nodes
   become: yes
   vars:
           - CLUSTER_PASS: 'cluster_passw0rd'

   tasks:
           - name: Update packages latest
             yum:
                     name: '*'
                     state: latest

           - name: Install pacemaker packages
             yum:
                     name: pacemaker,pcs,fence-agents,httpd
                     state: installed

           - name: Start services
             systemd:
                     name: "{{ item }}"
                     enabled: yes
                     state: started
             with_items:
                     - pcsd

           - name: Enable Corosync and Pacemaker service
             systemd:
                     name: "{{ item }}"
                     enabled: yes
             with_items:
                     - corosync
                     - pacemaker

           - name: Change hacluster password
             user:
                     name: hacluster
                     password: "{{ CLUSTER_PASS | password_hash('sha512') }}"

           - name: Allow Pacemaker Connection
             firewalld:
                     service: "{{ item }}"
                     permanent: yes
                     immediate: yes
                     state: enabled
             with_items:
                     - high-availability
                     - http

           - name: Check hosts file
             shell: "grep 192.168.11.12 /etc/hosts | wc -l"
             register: test_hosts

           - name: Add cluster hosts to /etc/hosts
             lineinfile:
                     path: "/etc/hosts"
                     state: present
                     line: |
                             192.168.11.121    cluster1.example.net
                             192.168.11.122    cluster2.example.net
                             192.168.11.123    cluster3.example.net
             when: test_hosts.stdout == "0"

           - name: Configure HTTPD status page
             copy:
                     dest: "/etc/httpd/conf.d/status.conf"
                     content: |
                             ExtendedStatus On
                             <Location /server-status>
                               SetHandler server-status
                               Require local
                             </Location>

           - name: Make sure Apache server disable by default
             systemd:
                     name: httpd
                     enabled: no
                     state: stopped

           - name: Add Test content
             shell: "echo \"running on `hostname`\" > /var/www/html/test.txt"

inventory.txtを作成し、作業対象のサーバを記述します。

[cluster_nodes]
192.168.11.121
192.168.11.122
192.168.11.123

playbookを実行します。

[jinglan@ansible-server ~]# ansible-playbook -i inventory.txt cluster_setup.yml  --ask-become-pass -vv

しばらくすると環境構築が終わります。結果にfailedが表示されていないことを確かめてください。

次からの作業はクラスタのうち一つにログインして作業します。3つのノードを登録しクラスターとして動作させます。

[root@cluster1 ~]# pcs cluster auth cluster1.example.net cluster2.example.net cluster3.example.net -u hacluster
Password: (playbookで定義したパスワードを入力)
cluster2.example.net: Authorized
cluster1.example.net: Authorized
cluster3.example.net: Authorized

[root@cluster1 ~]# pcs cluster setup --name httpcluster cluster1.example.net cluster2.example.net cluster3.example.net
Destroying cluster on nodes: cluster1.example.net, cluster2.example.net, cluster3.example.net...
cluster3.example.net: Stopping Cluster (pacemaker)...
cluster1.example.net: Stopping Cluster (pacemaker)...
cluster2.example.net: Stopping Cluster (pacemaker)...
cluster1.example.net: Successfully destroyed cluster
cluster2.example.net: Successfully destroyed cluster
cluster3.example.net: Successfully destroyed cluster

Sending 'pacemaker_remote authkey' to 'cluster1.example.net', 'cluster2.example.net', 'cluster3.example.net'
cluster1.example.net: successful distribution of the file 'pacemaker_remote authkey'
cluster2.example.net: successful distribution of the file 'pacemaker_remote authkey'
cluster3.example.net: successful distribution of the file 'pacemaker_remote authkey'
Sending cluster config files to the nodes...
cluster1.example.net: Succeeded
cluster2.example.net: Succeeded
cluster3.example.net: Succeeded

Synchronizing pcsd certificates on nodes cluster1.example.net, cluster2.example.net, cluster3.example.net...
cluster2.example.net: Success
cluster1.example.net: Success
cluster3.example.net: Success
Restarting pcsd on the nodes in order to reload the certificates...
cluster2.example.net: Success
cluster1.example.net: Success
cluster3.example.net: Success

[root@cluster1 ~]# pcs cluster start --all
cluster1.example.net: Starting Cluster (corosync)...
cluster2.example.net: Starting Cluster (corosync)...
cluster3.example.net: Starting Cluster (corosync)...
cluster1.example.net: Starting Cluster (pacemaker)...
cluster3.example.net: Starting Cluster (pacemaker)...
cluster2.example.net: Starting Cluster (pacemaker)...

[root@cluster1 ~]# pcs property set stonith-enabled=false
[root@cluster1 ~]#

クラスターを構成したので現在の状態を確認します。

[root@cluster1 ~]# pcs status
Cluster name: httpcluster
Stack: unknown
Current DC: NONE
Last updated: Sat Jun 27 15:55:09 2020
Last change: Sat Jun 27 15:55:04 2020 by root via cibadmin on cluster1.example.net

3 nodes configured
0 resources configured

OFFLINE: [ cluster1.example.net cluster2.example.net cluster3.example.net ]

No resources


Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled

3つのノードが認識されていますが、リソースが設定されていないためOFFLINE状態になっています。 そのため、クラスターで冗長化するリソースについて設定します。今回は冗長化されたIPアドレス(192.168.11.120)とHTTPサーバを定義します。

[root@cluster1 ~]# pcs resource create VIP ocf:heartbeat:IPaddr2 ip=192.168.11.120 cidr_netmask=24 op monitor interval=10s on-fail="standby" --group httpgroup
[root@cluster1 ~]# pcs resource create HTTPD ocf:heartbeat:apache configfile="/etc/httpd/conf/httpd.conf" statusurl="http://127.0.0.1/server-status" --group httpgroup

HTTPDとVIPは同じリソースグループに属しているので一緒に切り替わります。 再度、pacemakerの状態を表示します。

[root@cluster1 ~]# pcs status
Cluster name: httpcluster
Stack: corosync
Current DC: cluster1.example.net (version 1.1.21-4.el7-f14e36fd43) - partition with quorum
Last updated: Sat Jun 27 10:25:59 2020
Last change: Fri Jun 26 22:00:25 2020 by root via cibadmin on cluster1.example.net

3 nodes configured
2 resources configured

Online: [ cluster1.example.net cluster2.example.net cluster3.example.net ]

Full list of resources:

 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster1.example.net
     HTTPD      (ocf::heartbeat:apache):        Started cluster1.example.net

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

Resource Groupの表示に「Started cluster1.example.net」と記載があり、cluster1で実行されていることがわかります。実際にVIPアドレスへHTTPリクエストを飛ばして確認してみます。

$ curl http://192.168.11.120/test.txt
running on cluster1.example.net

応答からcluster1でHTTP処理が行われたことが分かります。 続いてcluster1を疑似的に停止します。その前に、別ターミナルから連続でHTTPリクエストを飛ばし、切り替え状態をモニターします。

$ while : ; do curl http://192.168.11.120/test.txt ; sleep 1; done;
running on cluster1.example.net

VMを実行しているホストにて下記コマンドでVMを停止します。

# virsh suspend cluster1

モニターしているターミナルでは一時疎通不可になったのち、切り替わることが確認できます。

running on cluster1.example.net
running on cluster1.example.net
curl: (7) Failed to connect to 192.168.11.120 port 80: Connection refused
curl: (7) Failed to connect to 192.168.11.120 port 80: Connection refused
running on cluster2.example.net
running on cluster2.example.net
running on cluster2.example.net

次に、cluster3を停止します。

# virsh suspend cluster3

モニター側ではWebサイトからの応答がなくなります。 cluster2側で状態を確認します。

[jinglan@cluster2 ~]$ sudo pcs status
Cluster name: httpcluster
Stack: corosync
Current DC: cluster2.example.net (version 1.1.21-4.el7-f14e36fd43) - partition WITHOUT quorum
Last updated: Sat Jun 27 13:54:09 2020
Last change: Sat Jun 27 13:52:53 2020 by root via cibadmin on cluster1.example.net

3 nodes configured
2 resources configured

Online: [ cluster2.example.net ]
OFFLINE: [ cluster1.example.net cluster3.example.net ]

Full list of resources:

 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Stopped
     HTTPD      (ocf::heartbeat:apache):        Stopped

Daemon Status:
  corosync: active/enabled
  pacemaker: active/enabled
  pcsd: active/enabled

Resource Groupが停止していることが確認できます。3ノード構成ではquorumによりアクティブになるノードが決定されます。これにより、2ノードから疎通ができなくなったノードは冗長構成から切り離されたと判断し、リソースの競合を防ぐため停止します。

停止させたcluster1とcluster3を再開します。

# virsh resume cluster1
# virsh resume cluster3

cluster1とcluster3が復帰したことでリソースはcluster1に戻ります。

[root@cluster1 ~]# pcs status
 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster1.example.net
     HTTPD      (ocf::heartbeat:apache):        Started cluster1.example.net

特定のホストでリソースを実行したい場合はstandbyを使います。cluster1とcluster2をstandby状態にして、cluster3で実行させるようにします。

[root@cluster1 ~]# pcs cluster standby cluster1.example.net
[root@cluster1 ~]# pcs cluster standby cluster2.example.net
[root@cluster1 ~]# pcs status
Cluster name: httpcluster
Stack: corosync
Current DC: cluster3.example.net (version 1.1.21-4.el7-f14e36fd43) - partition with quorum
Last updated: Sat Jun 27 15:59:00 2020
Last change: Sat Jun 27 15:58:54 2020 by root via cibadmin on cluster1.example.net

3 nodes configured
2 resources configured

Node cluster1.example.net: standby
Node cluster2.example.net: standby
Online: [ cluster3.example.net ]

Full list of resources:

 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster3.example.net
     HTTPD      (ocf::heartbeat:apache):        Started cluster3.example.net

リソースはcluster3で実行を続けます。なお、この時にcluster3が停止状態になるとリソースの移動先がないために切り替わりが起きません。 standby状態はunstandbyコマンドにより解除することができます。

[root@cluster1 ~]# pcs cluster unstandby --all

standbyによるACT/SBY構成の切り替えはシングル障害点になってしまいます。特定のノードにリソースを移したい場合はresource moveにより切り替えます。

[root@cluster1 ~]# pcs resource move httpgroup cluster1.example.net
[root@cluster1 ~]# pcs status
(略)
 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster1.example.net
     HTTPD      (ocf::heartbeat:apache):        Started cluster1.example.net

次に、リソース起動に失敗した場合の動作について確認してみます。Apacheの設定ファイルを取り除きます。

[root@cluster1 ~]# cd /etc/httpd/conf/
[root@cluster1 conf]# mv httpd.conf httpd.conf.bak

現在動いているプロセスをkillします。

[root@cluster1 ~]# ps aux | grep httpd
root     24998  0.0  0.3 224080  3468 ?        Ss   Jun27   0:18 /sbin/httpd -DSTATUS -f /etc/httpd/conf/httpd.conf -c PidFile /var/run/httpd.pid

[root@cluster1 ~]# kill 24998

ログを確認すると起動に失敗したため系切り替えが発生したことが分かります。

[root@cluster1 conf]# tail /var/log/messages
Jun 29 22:24:19 cluster1 lrmd[22953]:  notice: HTTPD_start_0:17745:stderr [ ocf-exit-reason:Configuration file /etc/httpd/conf/httpd.conf not found! ]
Jun 29 22:24:19 cluster1 lrmd[22953]:  notice: HTTPD_start_0:17745:stderr [ ocf-exit-reason:environment is invalid, resource considered stopped ]
Jun 29 22:24:19 cluster1 crmd[22956]:  notice: Result of start operation for HTTPD on cluster1.example.net: 5 (not installed)
Jun 29 22:24:19 cluster1 crmd[22956]:  notice: cluster1.example.net-HTTPD_start_0:24 [ ocf-exit-reason:Configuration file /etc/httpd/conf/httpd.conf not found!\nocf-exit-reason:environment is invalid, resource considered stopped\n ]
Jun 29 22:24:19 cluster1 apache(HTTPD)[17773]: ERROR: Configuration file /etc/httpd/conf/httpd.conf not found!
Jun 29 22:24:19 cluster1 apache(HTTPD)[17773]: INFO: environment is invalid, resource considered stopped
Jun 29 22:24:19 cluster1 lrmd[22953]:  notice: HTTPD_stop_0:17773:stderr [ ocf-exit-reason:Configuration file /etc/httpd/conf/httpd.conf not found! ]
Jun 29 22:24:19 cluster1 crmd[22956]:  notice: Result of stop operation for HTTPD on cluster1.example.net: 0 (ok)
Jun 29 22:24:19 cluster1 IPaddr2(VIP)[17800]: INFO: IP status = ok, IP_CIP=
Jun 29 22:24:19 cluster1 crmd[22956]:  notice: Result of stop operation for VIP on cluster1.example.net: 0 (ok)

現在の状態を確認します。

[root@cluster1 conf]# pcs status
Cluster name: httpcluster
Stack: corosync
Current DC: cluster3.example.net (version 1.1.21-4.el7-f14e36fd43) - partition with quorum
Last updated: Mon Jun 29 22:24:27 2020
Last change: Sat Jun 27 16:07:21 2020 by root via crm_resource on cluster1.example.net

3 nodes configured
2 resources configured

Online: [ cluster1.example.net cluster2.example.net cluster3.example.net ]

Full list of resources:

 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster2.example.net
     HTTPD      (ocf::heartbeat:apache):        Started cluster2.example.net

Failed Resource Actions:
* HTTPD_start_0 on cluster1.example.net 'not installed' (5): call=24, status=complete, exitreason='environment is invalid, resource considered stopped',
    last-rc-change='Mon Jun 29 22:24:19 2020', queued=0ms, exec=36ms

起動に失敗したことがFailed Resource Actionsに表示されています。取り除いたApacheの設定ファイルを元に戻します。

mv httpd.conf.bak httpd.conf

これでcluster1のApacheは正常に起動できるはずです。cluster2とcluster3をstanbyにしてみます。

[root@cluster1 conf]# pcs cluster standby cluster2.example.net
[root@cluster1 conf]# pcs cluster standby cluster3.example.net
[root@cluster1 conf]# pcs status
Cluster name: httpcluster
Stack: corosync
Current DC: cluster3.example.net (version 1.1.21-4.el7-f14e36fd43) - partition with quorum
Last updated: Mon Jun 29 22:34:30 2020
Last change: Mon Jun 29 22:34:13 2020 by root via cibadmin on cluster1.example.net

3 nodes configured
2 resources configured

Node cluster2.example.net: standby
Node cluster3.example.net: standby
Online: [ cluster1.example.net ]

Full list of resources:

 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster1.example.net
     HTTPD      (ocf::heartbeat:apache):        Stopped

Failed Resource Actions:
* HTTPD_start_0 on cluster1.example.net 'not installed' (5): call=24, status=complete, exitreason='environment is invalid, resource considered stopped',
    last-rc-change='Mon Jun 29 22:24:19 2020', queued=0ms, exec=36ms

HTTPDについてはリソースは停止したままです。たとえノードがOnline状態であっても、Failed Resource Actionsとして傷害の記録が残っているものは切り替わりません。そのため、下記コマンドで障害の状態をリセットする必要があります。

[root@cluster1 conf]# pcs resource cleanup
Cleaned up VIP on cluster3.example.net
Cleaned up VIP on cluster2.example.net
Cleaned up VIP on cluster1.example.net
Cleaned up HTTPD on cluster3.example.net
Cleaned up HTTPD on cluster2.example.net
Cleaned up HTTPD on cluster1.example.net
Waiting for 1 reply from the CRMd. OK

[root@cluster1 conf]# pcs status
Cluster name: httpcluster
Stack: corosync
Current DC: cluster3.example.net (version 1.1.21-4.el7-f14e36fd43) - partition with quorum
Last updated: Mon Jun 29 22:41:35 2020
Last change: Mon Jun 29 22:41:30 2020 by hacluster via crmd on cluster1.example.net

3 nodes configured
2 resources configured

Node cluster2.example.net: standby
Node cluster3.example.net: standby
Online: [ cluster1.example.net ]

Full list of resources:

 Resource Group: httpgroup
     VIP        (ocf::heartbeat:IPaddr2):       Started cluster1.example.net
     HTTPD      (ocf::heartbeat:apache):        Started cluster1.example.net

Failed Resource Actionsについては見落としやすいので注意したほうがよいです。