ラベル NGINX の投稿を表示しています。 すべての投稿を表示
ラベル NGINX の投稿を表示しています。 すべての投稿を表示
2023年7月2日日曜日

NGINXの負荷分散装置(ロードバランサ)をPacemakerで冗長化する

先日、NGINXを使って負荷分散装置(ロードバランサ)を構築してみた。

2台のサーバに対して負荷分散して通信できることで、リソースを分散させるだけでなく冗長化も図ることができたが、肝心の負荷分散装置であるNGINX自体がシングルポイントとなっているため、可用性の観点から不十分である。

しかし、OSSのNGINXではNGINXによる冗長化機能はないため、もし冗長化したい場合は別の手法を検討する必要がある。そこで、以前から本ブログで紹介したことがある「Pacemaker+Corosync」を使って、クラスタ構成による冗長化を図ることにした。

今回はPacemaker+Corosyncを使ってNGINXをクラスタ化し冗長構成された負荷分散装置(ロードバランサ)を構築する。

環境

環境としては以下の通りAlmaLinuxを利用したが、そのほかのRed Hat系のディストリビューションであれば、ほぼ同様の手順で構築できるはずだ。

  • AlmaLinux 8.5 及び AlmaLinux 9.2
  • NGINX 1.14.1

負荷分散装置の構成は以下の通りとする。クライアントからの通信と負荷分散対象サーバが同一のインタフェースとなる「ワンアーム」構成となる。なお、NGINXでは、通信は必ずSource NATされるため、ワンアーム構成としたとしても特別な設定は不要となる。

Pacemaker+CorosyncによるNGINX冗長化手順

1. 2台のサーバでNGINXを構築

Pacemaker+Corosyncでクラスタを構成する前に、事前にクラスタ対象サーバでNGINXを負荷分散装置として動作するよう構築しておこう。再掲となるが、手順は以下を参照してほしい。

2. Pacemaker+Corosyncを構築

Pacemaker+Corosyncの構築手順は、以前別記事にて記載している。こちらを参考に、クラスタの起動までできるように構築する。

補足として、AlmaLinux 8.5においては、Pacemaker+Corosyncのインストールに必要なリポジトリがHighAvailabilityではなくhaになっている。

# dnf repolist all
repo id                    repo の名前                                    状態
~(中略)~
ha                         AlmaLinux 8 - HighAvailability                 無効化
ha-debuginfo               AlmaLinux 8 - HighAvailability debuginfo       無効化
ha-source                  AlmaLinux 8 - HighAvailability Source          無効化
~(以下略)~

したがって、dnfによるインストール実施時に、リポジトリを以下のように指定して対応しよう。なお、AlmaLinux 9.2ではリポジトリ名がhighavailability(全部小文字)になっていたので、OSバージョンに合わせて適切なリポジトリを選択しよう。

# dnf --enablerepo=ha install pacemaker pcs fence-agents-all pcp-zeroconf -y

3. クラスタリソース及び制約設定

Pacemaker+Corosyncのインストールが終わったら、以下の通りクラスタリソースと制約の設定を行う。

リソース種類 リソース名 設定値
VIP rs-vip-33 ens192のインタフェースに対して192.168.33.23/24のIPアドレスを設定する。
NGINX rs-systemd-nginx NGINXをsystemdにて起動・停止する。
Ping rs-ping-33 ゲートウェイに対して各サーバからPingを実行し、Ping疎通ができないサーバではリソースを起動できないよう制約 (constraint) を設定する。
# pcs resource create rs-vip-33 ocf:heartbeat:IPaddr2 ip=192.168.33.23 cidr_netmask=24 nic=ens192 --group rg-01
# pcs resource create rs-systemd-nginx systemd:nginx --group rg-01

# pcs resource create rs-ping-33 ocf:pacemaker:ping dampen=5s multiplier=1000 host_list=192.168.33.31
# pcs resource clone rs-ping-33
# pcs constraint location rg-01 rule score=-INFINITY pingd lt 1 or not_defined pingd

最終的なリソース及び制約の設定は以下の通り。

# pcs resource show --full
Warning: This command is deprecated and will be removed. Please use 'pcs resource config' instead.
 Group: rg-01
  Resource: rs-vip-33 (class=ocf provider=heartbeat type=IPaddr2)
   Attributes: cidr_netmask=24 ip=192.168.33.23 nic=ens192
   Operations: monitor interval=10s timeout=20s (rs-vip-33-monitor-interval-10s)
               start interval=0s timeout=20s (rs-vip-33-start-interval-0s)
               stop interval=0s timeout=20s (rs-vip-33-stop-interval-0s)
  Resource: rs-systemd-nginx (class=systemd type=nginx)
   Operations: monitor interval=60 timeout=100 (rs-systemd-nginx-monitor-interval-60)
               start interval=0s timeout=100 (rs-systemd-nginx-start-interval-0s)
               stop interval=0s timeout=100 (rs-systemd-nginx-stop-interval-0s)
 Clone: rs-ping-33-clone
  Resource: rs-ping-33 (class=ocf provider=pacemaker type=ping)
   Attributes: dampen=5s host_list=192.168.33.31 multiplier=1000
   Operations: monitor interval=10s timeout=60s (rs-ping-33-monitor-interval-10s)
               start interval=0s timeout=60s (rs-ping-33-start-interval-0s)
               stop interval=0s timeout=20s (rs-ping-33-stop-interval-0s)

# pcs constraint
Location Constraints:
  Resource: rg-01
    Constraint: location-rg-01
      Rule: boolean-op=or score=-INFINITY
        Expression: pingd lt 1
        Expression: not_defined pingd
Ordering Constraints:
Colocation Constraints:
Ticket Constraints:

4. 動作確認

クラスタリソースが稼働しているサーバをシャットダウンした際に、もう1台のサーバにフェイルオーバーすることを確認する。

フェイルオーバー前の状態は以下の通り。

# pcs status
Cluster name: clst-01
Cluster Summary:
  * Stack: corosync
  * Current DC: t3041ngnx (version 2.1.0-8.el8-7c3f660707) - partition with quorum
  * Last updated: Sun Apr 24 11:47:32 2022
  * Last change:  Sat Apr 23 08:50:12 2022 by root via cibadmin on t3041ngnx
  * 2 nodes configured
  * 4 resource instances configured

Node List:
  * Online: [ t3041ngnx t3042ngnx ]

Full List of Resources:
  * Resource Group: rg-01:
    * rs-vip-33 (ocf::heartbeat:IPaddr2):        Started t3041ngnx
    * rs-systemd-nginx  (systemd:nginx):         Started t3041ngnx
  * Clone Set: rs-ping-33-clone [rs-ping-33]:
    * Started: [ t3041ngnx t3042ngnx ]

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

稼働系のサーバをシャットダウンすると、以下の通り残りのサーバでクラスタリソースが再起動されていることがわかる。

# pcs status
Cluster name: clst-01
Cluster Summary:
  * Stack: corosync
  * Current DC: t3042ngnx (version 2.1.0-8.el8-7c3f660707) - partition with quorum
  * Last updated: Sun Apr 24 11:48:15 2022
  * Last change:  Sat Apr 23 08:50:12 2022 by root via cibadmin on t3041ngnx
  * 2 nodes configured
  * 4 resource instances configured

Node List:
  * Online: [ t3042ngnx ]
  * OFFLINE: [ t3041ngnx ]

Full List of Resources:
  * Resource Group: rg-01:
    * rs-vip-33 (ocf::heartbeat:IPaddr2):        Started t3042ngnx
    * rs-systemd-nginx  (systemd:nginx):         Started t3042ngnx
  * Clone Set: rs-ping-33-clone [rs-ping-33]:
    * Started: [ t3042ngnx ]
    * Stopped: [ t3041ngnx ]

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

以上で、Pacemaker+Corosyncを使ってNGINXをクラスタ化し冗長構成された負荷分散装置を構築する手順は完了となる。

更新履歴

  • 2022/6/11 新規作成
  • 2023/7/2 AlmaLinux 9.2の記載を追記

2022年6月18日土曜日

NGINXの負荷分散対象サーバに対してポートチェックするスクリプト

先日、NGINXを使って負荷分散装置(ロードバランサ)を構築する手順を記載した。

NGINXは非常に簡単に負荷分散装置として構築できる反面、BIG-IPなどの負荷分散装置にあるような、現在の負荷分散装置対象サーバの状態を確認するコマンドなどは用意されていない。

そこで今回、NGINXの負荷分散対象サーバに対してポート開放状態のチェックを行うスクリプトを作成してみた。

環境

環境としては以下の通りAlmaLinuxを利用した。NGINXは前述したURLの通り、負荷分散装置として構築済みである前提とする。

  • AlmaLinux 8.5
  • NGINX 1.14.1

スクリプト導入手順

1. 前提パッケージの導入

ポートチェックはncコマンドで行うため、以下の通りパッケージインストールを行う。

# dnf install nc -y

2. スクリプトを配置

スクリプトの内容は以下の通りとなる。スクリプトはGitHubに公開している。

作りとしては、NGINXの設定ファイルを読み込み、負荷分散対象サーバに対してポート開放チェックをする。設定ファイルの記載フォーマットが以前の記事の通りとなっていない場合うまく動作しない可能性があるため、その場合はスクリプトの修正が必要となるかもしれない。

#!/bin/bash
################
# Scripts name : check_nginx_stream.sh
# Usage        : ./check_nginx_stream.sh
# Description  : NGINX負荷分散対象ポートチェックスクリプト
# Create       : 2022/04/30 tech-mmmm (https://tech-mmmm.blogspot.com/)
# Modify       :
################

rc=0      # Return code
array=()  # サーバ&ポート一覧保存用配列
config_file="/etc/nginx/stream.conf.d/servers.stream.conf" # 設定ファイルパス

# Configからサーバ&ポート情報抽出
while read line || [ -n "${line}" ]; do
  # upstream行の設定から負荷分散対象グループ名を取得
  if [ $(echo ${line} | grep -c -E "^upstream.*{") -ne 0 ]; then
    pool=$(echo ${line} | cut -d" " -f2)
  fi
  # server行の設定から、負荷分散対象サーバの情報を取得
  if [ $(echo ${line} | grep -c -E "^server.*;") -ne 0 ]; then
    member=$(echo ${line} | cut -d" " -f2 | tr -d ";")
    array+=("${pool}:${member}")
  fi
done < "${config_file}"

# ポートスキャン
for i in ${array[@]} ; do
  # ポート番号取得
  server=$(echo $i | cut -d":" -f1)
  port=$(cat /etc/nginx/stream.conf.d/servers.stream.conf | grep -E -B1 "proxy_pass.*${server}" | grep listen | awk '{print $3}' | tr -d ";")
  if [ "${port}" == "" ]; then
    port="tcp"
  fi

  # ポートスキャン
  if [ "${port}" == "tcp" ]; then
    # TCPの場合
    nc -nvz $(echo $i | cut -d":" -f2) $(echo $i | cut -d":" -f3) > /dev/null 2>&1
    if [ $(echo $?) -eq 0 ]; then
      result="up"
    else
      result="down"
      rc=$((${rc} + 1))
    fi
  else
    # UDPの場合
    nc -unvz $(echo $i | cut -d":" -f2) $(echo $i | cut -d":" -f3) > /dev/null 2>&1
    if [ $(echo $?) -eq 0 ]; then
      result="up"
    else
      result="down"
      rc=$((${rc} + 1))
    fi
  fi

  echo "$i:$port -> ${result}"
done

exit ${rc}

上記スクリプトを任意の場所に配置し、実行権限をつければ動作する。今回はgitをインストールしていないため、wgetで取得した。

# wget https://raw.githubusercontent.com/tech-mmmm/check_nginx_stream/main/check_nginx_stream.sh
--2022-04-30 08:41:22--  https://raw.githubusercontent.com/tech-mmmm/check_nginx_stream/main/check_nginx_stream.sh
192.168.33.23:8080 に接続しています... 接続しました。
Proxy による接続要求を送信しました、応答を待っています... 200 OK
長さ: 1853 (1.8K) [text/plain]
`check_nginx_stream.sh' に保存中

check_nginx_stream. 100%[===================>]   1.81K  --.-KB/s 時間 0s

2022-04-30 08:41:22 (62.6 MB/s) - `check_nginx_stream.sh' へ保存完了 [1853/1853]

# chmod +x check_nginx_stream.sh

3. 動作確認

実際に私の環境で実行した結果は以下の通り。

# ./check_nginx_stream.sh
proxy_server:192.168.33.27:8080:tcp -> up
proxy_server:192.168.33.28:8080:tcp -> up
dns_server:192.168.33.27:10053:udp -> up
dns_server:192.168.33.28:10053:udp -> up
mail_server:192.168.33.27:25:tcp -> up
mail_server:192.168.33.28:25:tcp -> up
ntp_server:192.168.33.27:123:udp -> up
ntp_server:192.168.33.28:123:udp -> up

以上 。

2022年6月4日土曜日

NGINXで負荷分散装置(ロードバランサ)を構築する

自宅では、プロキシやDNSなどを負荷分散装置(ロードバランサ)にてロードバランスして利用している。負荷分散装置としてはZEVENETを利用していたが、コミュニティ版は2020年5月から更新がないことや、冗長構成した際にうまく切り替わらないなどの問題が起きていたため、今回別製品に変更することにした。

調べていくと、Webサーバ用途のソフトウェアとして知られる「NGINX (エンジンエックス)」が負荷分散装置としても利用できることがわかった。ただし、OSS版のNGINXにおいては、以下機能が実装されていない点に注意しよう。以下機能は商用のNGINX Plusであれば利用可能となる。

  • セッションパーシステンスの機能なし
  • 負荷分散対象サーバに対するNGINXからの定期的なヘルチェック (アクティブヘルスチェック) の機能なし。通信発生時に都度ヘルスチェックを行うパッシブヘルスチェックのみ利用可能
  • NGINXの機能を利用した冗長化構成の機能なし

今回、「NGINX」を利用して負荷分散装置(ロードバランサ)を構築する手順を記載する。先に言っておくと、NGINXの設定は非常に簡単だった。

環境

環境としては以下の通りAlmaLinuxを利用したが、そのほかのRed Hat系のディストリビューションであれば、ほぼ同様の手順で構築できるはずだ。

  • AlmaLinux 8.5
  • NGINX 1.14.1

負荷分散装置の構成は以下の通りとする。クライアントからの通信と負荷分散対象サーバが同一のインタフェースとなる「ワンアーム」構成となる。なお、NGINXでは、通信は必ずSource NATされるため、ワンアーム構成としたとしても特別な設定は不要となる。

負荷分散対象は以下の通りとする。

用途 待ち受けポート 負荷分散対象サーバ ポート番号
Proxy 8080/tcp 192.168.33.27, 192.168.33.28 8080/tcp
DNS 53/udp 192.168.33.27, 192.168.33.28 10053/udp
MTA 25/tcp 192.168.33.27, 192.168.33.28 25/tcp
NTP 123/udp 192.168.33.27, 192.168.33.28 123/udp

NGINXにて負荷分散装置を構築する手順

1. dnfでNGINXをインストール

Red Hat系のディストリビューションの場合は、NGINXは標準のリポジトリに用意されている。NGINX本体に加え、負荷分散装置の設定に必要なstreamモジュールをインストールする。

# dnf install nginx nginx-mod-stream -y

2. NGINXの設定ファイルを作成

負荷分散装置の設定ファイル用のディレクトリを作成する。

# mkdir /etc/nginx/stream.conf.d

ディレクトリ作成後、以下2つのファイルを作成・追記を行う。

/etc/nginx/stream.conf.d/servers.stream.conf

以下内容で設定ファイルを新規作成する。

# Proxy
upstream proxy_server {
    least_conn;
    server 192.168.33.27:8080;
    server 192.168.33.28:8080;
}

server {
    listen       8080;
    proxy_pass   proxy_server;
}

# DNS
upstream dns_server {
    server 192.168.33.27:10053;
    server 192.168.33.28:10053;
}

server {
    listen       53 udp;
    proxy_pass   dns_server;
}

# MTA
upstream mail_server {
    least_conn;
    server 192.168.33.27:25;
    server 192.168.33.28:25;
}

server {
    listen       25;
    proxy_pass   mail_server;
}

# NTP
upstream ntp_server {
    server 192.168.33.27:123;
    server 192.168.33.28:123;
}

server {
    listen       123 udp;
    proxy_pass   ntp_server;
}

/etc/nginx/nginx.conf

以下を最下行に追記する。

stream {
    include /etc/nginx/stream.conf.d/*.conf;
}

3. サービス起動

これだけで必要な設定は完了となるため、NGINXのサービスを起動しよう。

# systemctl start nginx
# systemctl enable nginx

4. 動作確認

サービス起動後に待ち受けポートが開放されていることをssコマンドで確認する。以下の通り、負荷分散装置の設定を行ったポートがLISTEN (UDPに関してはUNCONN) になっていることがわかる。

# ss -nl | egrep ":(8080|53|25|123)" | sed -e 's/  */\t/g'
udp     UNCONN  0       0       0.0.0.0:123     0.0.0.0:*
udp     UNCONN  0       0       0.0.0.0:53      0.0.0.0:*
tcp     LISTEN  0       128     0.0.0.0:8080    0.0.0.0:*
tcp     LISTEN  0       128     0.0.0.0:25      0.0.0.0:*

負荷分散対象サーバに対しても問題なく通信できていることを確認しておこう。

# ss -n | egrep "192.168.33.27:(8080|53|25|123)" | sed -e 's/  */\t/g'
udp     ESTAB   0       0       192.168.33.41:57935     192.168.33.27:123
tcp     ESTAB   0       0       192.168.33.41:39962     192.168.33.27:8080
tcp     ESTAB   0       0       192.168.33.41:39592     192.168.33.27:8080

# ss -n | egrep "192.168.33.28:(8080|53|25|123)" | sed -e 's/  */\t/g'
udp     ESTAB   0       0       192.168.33.41:37953     192.168.33.28:123
tcp     ESTAB   0       0       192.168.33.41:35096     192.168.33.28:8080
tcp     ESTAB   0       0       192.168.33.41:33832     192.168.33.28:8080

以上を確認したうえで、実際にプロキシ経由でのインターネット閲覧やDNSの名前解決を確認し、問題なく動作することを確認した。

以上にて、「NGINX」を利用して負荷分散装置を構築する手順は完了となる。

参考

人気の投稿