Pacemakerを使ったHA構成を動かしてみた

pacemakerを使ったことがないので、Nginxの冗長化とVIPを設定して管理したいと思う。
pacemakerだけではなく、HA構成を実現する方法は知っておくべきだと思うでのセットアップから理解していきたい。


## 環境

Vagrantを使ってRockeyLinux9をVMとして起動。
eth0はVagrantがPrimaryとSecondaryに固定のIPアドレスを設定してしまうので、eth1を使用する。

![HA構成.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3837682/1d9db09c-792e-bcb7-5725-d388f7d92213.png)

| サーバー | IPアドレス |
| :-----  | :----- |
| Primary | 192.168.56.10 |
| Secondary | 192.168.56.11 |

## 手順

下記のサイトを参考にしました。

https://inaba-serverdesign.jp/blog/20230428/nginx_cluster_by_pacemaker1.html
https://inaba-serverdesign.jp/blog/20230428/nginx_cluster_by_pacemaker2.html

### 0. ネットワーク設定

VagrantでVMを起動する際に、Vagrantfileでprivate_networkの設定をしているが、そのままだとVIPが設定されなかった。
VIPが設定されるように、`auto_config`をfalseにしてVMが起動後にネットワークを再設定する。

```Vagrantfile
config.vm.network "private_network", ip: "192.168.56.10", auto_config: false
```

VMが起動後にネットワークの設定を確認する。
自分の環境では、`Wired connection 1`というのが`eth1`にあたるものなので削除して、`ifcfg-eth1`ファイルを作成してネットワークを設定する。

```shell
# nmcli con show
NAME                UUID                                  TYPE      DEVICE 
System eth0         5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03  ethernet  eth0   
lo                  4c06f3d1-d066-4c30-9a7d-873edbdc396e  loopback  lo     
ens3                dec760c6-22a2-4eed-baeb-c67b2a9ee810  ethernet  --     
Wired connection 1  e2b58963-e02a-3f9e-a1ba-16a58a906cc1  ethernet  --     

# nmcli con delete "Wired connection 1"
# vi /etc/sysconfig/network-scripts/ifcfg-eth1

TYPE="Ethernet"
BOOTPROTO="none"
IPV4_FAILURE_FATAL="no"
NAME="eth1"
DEVICE="eth1"
ONBOOT="yes"

# systemctl restart NetworkManager
```

primaryとsecondaryのIPアドレスを設定して、コメントを実行する。

```shell
# nmcli c mod eth1 ipv4.method manual ipv4.addresses "192.168.56.11/24"
```

```shell
# nmcli c up eth1
# nmcli con show
NAME         UUID                                  TYPE      DEVICE 
System eth0  5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03  ethernet  eth0   
eth1         9c92fad9-6ecb-3e6c-eb4d-8a47c6f50c04  ethernet  eth1   
lo           4c06f3d1-d066-4c30-9a7d-873edbdc396e  loopback  lo     
ens3         dec760c6-22a2-4eed-baeb-c67b2a9ee810  ethernet  --     
```

### 1. Nginxの設定

#### 1-1. Nginxのインストール

```shell
dnf install -y nginx
```

#### 1-2. HTMLファイルの作成

/usr/share/nginx/html/test.html に下記の内容のファイルを用意。
secondaryの場合は、primaryのところを変更する。

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Test Page</title>
</head>
  
<body>
<h1>Test Page</h1>
test page on primary.
</body>
</html>
```

### 2. PacemakerとCorosyncをインストールする

#### 2-1. pacemakerをインストール

highavailabilityリポジトリはデフォルトで無効になっているので、リポジトリを有効にしてインストールする。

```shell
# dnf --enablerepo=highavailability -y install pacemaker pcs
```

#### 2-2. haclusterユーザの確認

```shell
# id hacluster
```

#### 2-3. pcsサービスの有効化

Pacemakerの設定用pcsコマンドを使用するために、pcsdサービスを起動する。
その際に、自動起動設定も行う。

```shell
# systemctl enable --now pcsd
# systemctl status pcsd
```

### 3. Pacemakerの設定｀

#### 3-1. /etc/hostsの編集

primary側の`hosts`ファイルを編集する。
pacemakerがsecondary側にも設定を反映してくれるので、primary側でのみ編集。

```shell
# vi /etc/hosts

# 以下を追加

192.168.56.10  primary
192.168.56.11  secondary
```

#### 3-2. haclusterユーザのパスワードの設定

パスワード変更は、primaryとsecondaryの両方で設定する。
パスワードはprimaryとsecondaryで同じものを設定しないとクラスタの認証に失敗する。

```shell
# passwd hacluster
```

#### 3-3. クラスタの認証設定

```shell
# pcs host auth primary secondary -u hacluster
Password: 3-2で設定したhaclusterユーザのパスワードを入力

# 以下が出力される
secondary: Authorized
primary: Authorized
```

#### 3-4. クラスターの作成

クラスター名はnginx-clusterとする
`pcs cluster setup`でクラスターを作成する。

```shell
# pcs cluster setup nginx-cluster --start primary addr=192.168.56.10 secondary addr=192.168.56.11
```

以下のメッセージが出力されれば、作成完了。
```text
Cluster has been successfully set up.
Starting cluster on hosts: 'primary', 'secondary'...
```

`pcs status`でクラスターの状態を確認する

```shell
# pcs status
```

Node List が Onlineで出力され、クラスターのノードが含まれていればOK。

```
Cluster name: nginx-cluster

WARNINGS:
No stonith devices and stonith-enabled is not false

Cluster Summary:
  * Stack: corosync (Pacemaker is running)
  * Current DC: primary (version 2.1.7-5.el9_4-0f7f88312) - partition with quorum
  * Last updated: Fri Jul  5 23:59:13 2024 on primary
  * Last change:  Fri Jul  5 23:57:37 2024 by hacluster via hacluster on primary
  * 2 nodes configured
  * 0 resource instances configured

Node List:
  * Online: [ primary secondary ]

Full List of Resources:
  * No resources

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

クラスターの管理通信を確認する。
 
```shell
# corosync-cfgtool -s
 ```

 クォーラムの状態を無視する設定をする

```shell
# pcs property set no-quorum-policy=ignore
```

STONITHを無効とする設定をする
```shell
# pcs property set stonith-enabled=false
```

現在の設定を確認する
```shell
# pcs property
```

#### 3-5. クラスターリソースの設定

- VIP制御リソースの設定

リソース名をrs-vipとして、リソースエージェントに`ocf:heartbeat:IPaddr2`を設定する。
eth1のインタフェースに対して、Virtual IPの 192.168.56.12 を設定する。

- Nginx制御リソースの設定

リソース名をrs-systemd-nginxとして、リソースエージェントに`systemd:nginx`を設定する。
systemdを使用して、Nginxサービスの起動・停止する。

- ネットワーク監視用Pingリソースの設定

リソース名をrs-ping-gwとして、リソースエージェントに`ocf:pacemaker:ping`を設定する。

NginxとVIPは、フェイルオーバーさせるためのリソースグループを作成する。


##### 3-5-1. VIP制御リソースを作成する

```shell
# pcs resource create --future rs-vip ocf:heartbeat:IPaddr2 ip=192.168.56.12 cidr_netmask=24 nic=eth1 op monitor interval=10s group rg01
```

##### 3-5-2. Nginx制御リソースを作成する

```shell
# pcs resource --future create rs-systemd-nginx systemd:nginx group rg01
```

##### 3-5-3. ネットワーク監視用Pingリソースを作成する

デフォルトゲートウェイを確認する

```shell
# ip r
# 出力結果
default via 10.0.2.2 dev eth0 proto dhcp src 10.0.2.15 metric 100 
10.0.2.0/24 dev eth0 proto kernel scope link src 10.0.2.15 metric 100 
192.168.56.0/24 dev eth0 proto kernel scope link src 192.168.56.12 
192.168.56.0/24 dev eth1 proto kernel scope link src 192.168.56.10 metric 101 
```

```shell
# pcs resource create rs-ping-gw ocf:pacemaker:ping dampen=5s multiplier=1000 host_list=192.168.56.0
 
# pcs resource clone rs-ping-gw
```

ロケーションの制約設定を追加

```shell
# pcs constraint location rg01 rule score=-INFINITY pingd lt 1 or not_defined pingd
```

##### 3-5-4. 制約設定の確認

ロケーションの制約設定を確認する

```shell
# pcs constraint
```

```text
Location Constraints:
  resource 'rg01'
    Rules:
      Rule: boolean-op=or score=-INFINITY
        Expression: pingd lt 1
        Expression: not_defined pingd
```

##### 3-6. 動作状況確認

動作状況を確認すると、rs-vipとrs-systemd-nginxがStoppedになっている。
cleanupもしてもダメなので、再登録し直す。

```shell
# pcs status
Node List:
  * Online: [ primary secondary ]

Full List of Resources:
  * Resource Group: rg01:
    * rs-vip	(ocf:heartbeat:IPaddr2):	 Stopped
    * rs-systemd-nginx	(systemd:nginx):	 Stopped
  * Clone Set: rs-ping-gw-clone [rs-ping-gw]:
    * Started: [ primary secondary ]

# pcs resource delete rs-vip
Deleting Resource - rs-vip
# pcs resource delete rs-systemd-nginx
Removing Constraint - location-rg01
Deleting Resource (and group) - rs-systemd-nginx
# pcs resource create --future rs-vip ocf:heartbeat:IPaddr2 ip=192.168.56.12 cidr_netmask=24 nic=eth1 op monitor interval=10s group rg01
# pcs resource --future create rs-systemd-nginx systemd:nginx group rg01
# pcs status
Node List:
  * Online: [ primary secondary ]

Full List of Resources:
  * Clone Set: rs-ping-gw-clone [rs-ping-gw]:
    * Started: [ primary secondary ]
  * Resource Group: rg01:
    * rs-vip	(ocf:heartbeat:IPaddr2):	 Started primary
    * rs-systemd-nginx	(systemd:nginx):	 Started primary
```

再登録し直したら、起動した。

**primary**

VIPが設定されているおり、Nginxも起動している。

```shell
# ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:d5:3e:ef brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet 192.168.56.12/24 brd 192.168.56.255 scope global secondary eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fed5:3eef/64 scope link 
       valid_lft forever preferred_lft forever

# systemctl status nginx
● nginx.service - Cluster Controlled nginx
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
    Drop-In: /run/systemd/system/nginx.service.d
             └─50-pacemaker.conf
     Active: active (running) since Thu 2024-07-11 10:08:12 UTC; 13min ago
    Process: 3994 ExecStartPre=/usr/bin/rm -f /run/nginx.pid (code=exited, status=0/SUCCESS)
    Process: 3995 ExecStartPre=/usr/sbin/nginx -t (code=exited, status=0/SUCCESS)
    Process: 3996 ExecStart=/usr/sbin/nginx (code=exited, status=0/SUCCESS)

```

**secondary**

VIPも設定されておらず、Nginxも起動していないことがわかる。

```shell
# ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:27:7b:05 brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.56.11/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe27:7b05/64 scope link 
       valid_lft forever preferred_lft forever

# systemctl status nginx
○ nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
     Active: inactive (dead)
```
ブラウザから `http://192.168.56.12/test.html`にアクセスして、表示できることも確認できた。

### 4. 手動フェイルオーバー

手動ファイルオーバーを試す方法としては、以下の３つの方法がある。

- pcs resource move コマンドでリソースを移動
- pcs node standby コマンドでアクティブなノードをスタンバイ状態にする
- アクティブなノードでpacemakerサービスを停止する

今回は `pcs node standby`コマンドを使用する。

```shell
# pcs node standby primary
```

primaryとsecondaryのそれぞれを確認する。

**primary**

VIPも設定されておらず、nginxも起動していないことがわかる。

```shell
# ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:d5:3e:ef brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.56.10/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fed5:3eef/64 scope link 
       valid_lft forever preferred_lft forever

# systemctl status nginx
○ nginx.service - The nginx HTTP and reverse proxy server
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
     Active: inactive (dead)
```

**secondary**

VIPが設定されて、nginxも起動していることがわかる。

```shell
# ip addr show eth1
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 08:00:27:27:7b:05 brd ff:ff:ff:ff:ff:ff
    altname enp0s8
    inet 192.168.56.11/24 brd 192.168.56.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
    inet 192.168.56.12/24 brd 192.168.56.255 scope global secondary eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::a00:27ff:fe27:7b05/64 scope link 
       valid_lft forever preferred_lft forever

# systemctl status nginx
● nginx.service - Cluster Controlled nginx
     Loaded: loaded (/usr/lib/systemd/system/nginx.service; disabled; preset: disabled)
    Drop-In: /run/systemd/system/nginx.service.d
             └─50-pacemaker.conf
     Active: active (running) since Thu 2024-07-11 10:30:49 UTC; 32min ago
```

ブラウザから `http://192.168.56.12/test.html`にアクセスして、表示できることも確認できた。


## 最後に

pacemakerをインストールして、フェールオーダーでVIPやNginxの起動が切り替わること確認できた。
ただ、リソースの再登録をしないと起動しなかったのがわからないままなので、もう少し調べてみようと思う。
また、他のコメントの使い方も理解できていないので、実際に動かしてみて理解していきたい。
VIPやNginxのリソースを登録した直後に起動しない理由がわからない。