えんでぃの技術ブログ

えんでぃの技術ブログ

ネットワークエンジニアの視点で、IT系のお役立ち情報を提供する技術ブログです。

HAProxyによるL4負荷分散実装

お伝えしたいこと

Linuxにインストール可能なオープンソースソフトウェアのロードバランサーであるHAProxyについて、以下のトピックをご紹介します。

  • 概要
  • インストール手順
  • L4ロードバランスの実装手順

HAProxyとは

HAProxyにはざっくりOSS版と商用版があります。 本記事では、単にHAProxyと記載した場合はOSS版を指すものとします。

HAProxyはTCP, HTTP, HTTPSをサポートするロードバランサーです。 つまりHAProxyは対象の通信を一度受信し、配下のサーバ群に対して負荷が分散するよう通信を転送するネットワーク機器です。

HAProxyがサポートする機能を一部のみ抜粋します。 BIG-IP用語でいうとtcp/http/client-ssl/server-ssl profileとsnatに近い機能を持ちます。
(HAProxy 3.1 Starter Guide - #What HAProxy is and isn't)

  • TCP (L4) ロードバランシング (UDPのロードバランシング機能はない)
  • HTTP/HTTPS (L7) ロードバランシング
  • SSL/TLS オフロード/イニシエイト (HTTPS通信を受信・復号してHTTPで転送したり、再暗号化してHTTPSで転送したりできる)
  • ヘッダ情報に応じた通信制御 (例: URLによる負荷分散先の切り替え)
  • 透過型フォワードプロキシ
  • 負荷分散時の送信元NAT (デフォルト有効。無効化することも可能)

一方で、サポートしない機能は以下の通りです。

ここに記載した情報は全量ではないので、詳細が気になる方は上記リンク先の公式情報を参照してください。

(参考) HAProxyの有償版について

HAProxy Technologies, LLCは、OSS版のHAProxyをベースとした製品をいくつか販売しています。

製品の1つであるHAProxy EnterpriseはHAProxyの有償版とも言うべきソフトウェアロードバランサーで、OSS版よりも多くの機能をサポートしています。 追加機能にはUDPロードバランシングも含まれます。

詳細はFeature comparison tableの比較表をご覧ください。

(参考) えんでぃ目線のHAProxyの使い方

あくまで私の場合ですが、「KubernetesでControl-plane Nodesを冗長化したい」など、非クラウドのローカル検証環境にて簡易的なロードバランサーが欲しくなったときにHAProxyを使いました。 このユースケースであれば、本記事で紹介するHAProxyのL4負荷分散機能で十分にカバーできます。

HAProxyの構成

簡易構成図と用語説明

今回はHTTPクライアント 1台、HAProxyロードバランサー (LB) 1台、HTTPサーバ 2台の構成でTCPロードバランシングを実装してみます。

haproxy_topology

構成上のポイントは2つあります。 2のこだわりポイントを実現するために、今回はHAProxyに加えてKeepalivedという別ソフトも併せてインストールします。

  1. 全てのホストを同一ネットワークに構築した (設計・実装の難易度を下げるため)
  2. LB VIP (front_endの待ち受けIP) をfloating IPで構成した。つまりLinuxレイヤーでインターフェースに設定していないIPをLB VIPとして使える (こだわりポイント)

Keepalivedとの組み合わせ

多くのLinuxにおいて、デフォルトではOSレイヤーに設定済みのIPアドレスしかVIPとして使えません。

例えば、192.168.0.10/24というIPアドレスを持つLinuxにHAProxyをインストールしたとします。 このLinux192.168.0.11:80というTCPソケットをbind (利用登録) し、LB VIPとして使うことはデフォルトではできないことが多いです。 一方で192.168.0.10:80のように、OSレイヤーで持っているIPアドレスであればLB VIPとして使うことが可能です。

LBの設計によっては、NICに設定していないIPアドレスもLB VIPとして設定し、floating VIPを構成したいケースもあると思います。 そんなときに役立つのが以下2つの設定です。
(※) 私はまだ検証していませんが、VRRPでLBを冗長化することも可能です

  1. sysctlによりnet.ipv4.ip_nonlocal_bind=1というkernel parameterを設定することで、NICに設定していないIPを含むソケットのbindを許可する
  2. KeepalivedによりVRRPを構成することで、VRRP VIPを生成する。1の設定と合わせることで、このVRRP VIPをHAProxy側でLB VIPとして設定できる

なお、上記2つの設定なしでもNIC上に複数のIPアドレスを設定することでもHAProxyに複数IPのLB VIPを設定することが可能です。 LB冗長化に対応しない簡易的な設定方法ですが、既存のネットワークの制約でVRRPを使いたくないときなどに役立つかもしれません。

(参考) Keepalivedの概要

Keepalived User Guide

Keepalivedは大きく分けて2つの機能を持ちます。

  1. VRRPによるゲートウェイ冗長化
  2. L4ロードバランシング

1と2の機能はそれぞれ独立して実装できます。 例えば1に関連する情報だけを設定ファイルに記述した場合はVRRPのみ動作し、L4ロードバランシングは動作しません。

今回のケースでは、KeepalivedVRRP機能のみが必要です。 したがって、設定ファイルにもVRRPに関連する設定のみ記述します。

なお2のL4ロードバランシングについては、全体的にHAProxyと比較すると簡易的な機能です。 ヘルスチェックと負荷分散は可能なので、簡易的な負荷分散のみを実装するのであればKeepalivedだけで完結できます。 特に (無償版の) HAProxyはUDPの負荷分散に対応していないので、UDPの負荷分散がどうしても必要な場合はKeepalivedの利用を検討すると良さそうです。

HAProxyのセットアップ手順サンプル

では、実際のセットアップ手順のサンプルを示したいと思います。 今回実装する構成を再掲します。

haproxy_topology

全てのホストがCentOS Stream 9である前提で手順を紹介します。

Linuxの基本設定

本手順はLBとWEBサーバに対して実行します (lb1, web1, web2)。以下の流れで作業します。

  1. ホスト名の設定
  2. IPアドレスの設定
  3. firewalldのTCP 80 (http) 通信許可設定

私の環境は以下の構成になっています。 環境の前提が異なる方は必要に応じて読み替えてください。

  • ens3インターフェースを使う
  • 192.168.0.1デフォルトゲートウェイかつDNSサーバである
  • デフォルトゲートウェイからインターネットに出られる
  • シリアルコンソール接続して操作している (nmcli deleteでネットワーク疎通が切れる手順になっています。困る方はアレンジしてください)

以下はLBの手順です。 2台のWEBサーバについても、ホスト名とIPアドレスを読み替えつつ同様に設定します。

sudo hostnamectl set-hostname lb1.test

sudo nmcli connection delete ens3
sudo nmcli connection add autoconnect yes type ethernet ifname ens3 con-name ens3 ipv4.method manual ipv4.addresses 192.168.0.10/24 ipv4.gateway 192.168.0.1 ipv4.dns 192.168.0.1
sudo nmcli connection up ens3

sudo firewall-cmd --add-port 80/tcp --permanent
sudo firewall-cmd --reload

以降の手順は各LinuxサーバにSSHログインして実行できます。

Keepalivedのセットアップ

本手順はLBに対してのみ実行します (lb)。 以下の流れで作業します。

  1. Keepalivedのインストール
  2. Keepalived設定ファイルの更新 (VRRP VIP 192.168.0.100の作成)
  3. Keepalivedサービスの起動
# 1
# sudo firewall-cmd --add-protocol vrrp --permanent
# sudo firewall-cmd --reload

# 2
sudo dnf -y install keepalived

# 3-1
sudo mv -i /etc/keepalived/keepalived.conf{,.orig}
sudo mkdir /etc/keepalived/conf.d

cat << EOF | sudo tee /etc/keepalived/keepalived.conf > /dev/null
vrrp_track_process haproxy {
    process haproxy
    quorum 1
    weight 0
}

include /etc/keepalived/conf.d/*.conf
EOF

# 3-2
cat << EOF | sudo tee /etc/keepalived/conf.d/10_vrrp_web.conf > /dev/null
vrrp_instance web {
    virtual_router_id 2
    state MASTER
    interface ens3
    virtual_ipaddress {
        192.168.0.100
    }
    priority 255
    track_process {
        haproxy
    }
}
EOF

# keepalived -t ; echo $?

# 4
sudo systemctl enable keepalived.service --now

# 5
journalctl -eu keepalived.service -g state

コメント行に書かれた番号は、本セクションの冒頭に記載した「手順の流れ」の項番と対応しています。

以下、参考情報としていくつかの操作内容について補足します。

# 1

  • firewalldでVRRPの通信許可
  • 2台以上のHAProxyでVRRP冗長構成を組むときに必要
  • 今回の1台構成では不要のためコメントアウトした

# 3-1

  • デフォルトの/etc/keepalived/keepalived.confには不要な設定が多数あるので、一旦退避した
  • VRRP VIPが増えた場合も設定ファイルの見通しを良くするため、用途に応じてファイルを分割する構成とした (-> include)
  • Keepalived全体に影響を与えるようなグローバル設定のみ本ファイルに直接記述した

グローバル設定としては、以下の内容を実装した。

  • Keepalivedは同じLinux上で動作するhaproxyプロセスを監視し、haproxyが起動していなかった場合にVRRPステータスをFAULTに遷移する」設定を追加した
  • この設定がなくてもVRRPとしては最低限動作する

vrrp_track_processブロック配下の設定の意味は、それぞれ以下のとおりです。

オプション 意味
process <str> 指定した名前のプロセスが起動しているか否かを監視する
quorum <int> 指定した数のプロセス数が起動していたら監視成功
そうでなければ失敗
weight <int> 整数値を指定する。
正の数を指定すると、監視成功時にpriorityが加算される。
負の数を指定すると監視失敗時にpriorityを減算する。
0を指定すると監視失敗時にVRRPインスタンスが失敗する。0 reverseを指定すると監視成功時にVRRPインスタンスが失敗する。
デフォルトは1

# 3-2

  • VRRPインスタンス設定を投入する
  • VRRP ID、VRRP VIP、Priorityなど、一般的なVRRP設定を一通り指定する
  • # 2-1で設定したtrack設定を紐付けることで、trackの成否をVRRP状態と連動させる

vrrp_instanceブロック配下の設定の意味は、それぞれ以下のとおりです。

オプション 意味
virtual_router_id <int> VRRP ID (1〜255) の指定。
VRRP冗長化する2インスタンス間では値を揃える。
詳細はVRRPの標準仕様を調べること
state <str> VRRPのステータス初期値。
MASTER: priority255の場合に即時MASTERに昇格する。
BACKUP: BACKUPで起動し、3秒間のネゴシエーションの末MASTERに昇格。
今回はシングル構成なのでVIP起動を早めるためstate MASTERかつpriority 255とした。
冗長化する場合は起動時のIP重複を避けるためpriority 150など即昇格を避けるべきかも
interface <str> VRRPを動作させるインターフェース名を指定する
virtual_ipaddress {...} VRRP VIP (Virtual IP) を指定する。
CIDR形式で記述できるが、Prefix長を省略してホストIPとするのが一般的 (参考)
priority <int> VRRP Priority。
値が大きいほど優先的にMASTERに昇格しやすくなる。
nopreempt設定と密に関係する
track_process {...} # 2-2で設定したvrrp_track_process設定名を指定。
指定したtrack設定を有効化する。
有効化により、trackの成否がprioritystateが連動するようになる
nopreempt preemptを無効化する設定。
デフォルトはpreempt有効。
preemptが有効の場合、既存のMASTERよりも自身のpriorityが大きいときにMASTERを交代する。
preemptが無効の場合は既存のMASTERを維持する。
preemptを言い換えると自動フェイルバック設定

設定値の詳細はman keepalived.confを参照してください。

最後にコメントアウトされた以下のコマンドは、確認用です。 keepalived -tはconfig testを意味しており、keepalivedを起動せず設定ファイルの確認のみ行います。 Exit statusが0であれば正常で、それ以外の値であれば設定ファイルにエラーが存在します。 echo $?は、直前のkeepalived -tのExit statusを表示するコマンドです。

keepalived -t ; echo $?

HAProxyのセットアップ

本手順はLBに対してのみ実行します (lb1)。 以下の流れで作業します。

  1. HAProxyのインストール
  2. net.ipv4.ip_nonlocal_bind = 1のsysctl設定を追加し、VRRP VIPをLB VIPとして使えるようにする
  3. (必要に応じて) SELinuxの許可設定を有効化する
  4. HAProxyの設定ファイル更新
  5. HAProxyのサービス起動

LB VIPが待ち受けているTCP 80ポートは、すでに#Linuxの基本設定で通信許可されています。

# 1
sudo dnf -y install haproxy

# 2
cat << EOF | sudo tee /etc/sysctl.d/50_haproxy.conf
net.ipv4.ip_nonlocal_bind = 1
EOF

sudo sysctl --system

# sysctl net.ipv4.ip_nonlocal_bind

# 3
# sudo dnf -y install setools-console
# sesearch -A -ds -s haproxy_t -p name_bind
# seinfo --portcon | grep -P ':(commplex_main_port_t|http_cache_port_t|http_port_t):' | awk '{print $2, $3}'

# getsebool haproxy_connect_any
# seinfo -x -a port_type
# for PORT_T in $(seinfo -x -a port_type | grep -Po '\S+_t$') ; do seinfo --portcon | grep -P ":${PORT_T}:" | awk '{print $2, $3}'; done

sudo setsebool -P haproxy_connect_any=True

# getsebool haproxy_connect_any

# 4
sudo cp -pi /etc/haproxy/haproxy.cfg{,.orig}

cat << EOF | sudo tee /etc/haproxy/haproxy.cfg > /dev/null
global
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats
    stats timeout 2m

    # utilize system-wide crypto-policies
    ssl-default-bind-ciphers PROFILE=SYSTEM
    ssl-default-server-ciphers PROFILE=SYSTEM

defaults tcp
    mode    tcp
    log     global
    maxconn                 3000
    option  dontlognull
    retries 3
    timeout check           10s
    timeout client          1m
    timeout connect         10s
    timeout queue           1m
    timeout server          1m

defaults http from tcp
    mode    http
    option  httplog
    option  http-server-close
    option  forwardfor except 127.0.0.0/8
    option  redispatch
    timeout http-request    10s
    timeout http-keep-alive 10s
EOF

cat << EOF | sudo tee /etc/haproxy/conf.d/web.cfg > /dev/null
frontend web_http from tcp
  description Web Servers (HTTP)
  bind 192.168.0.100:80
  default_backend web_http

backend web_http from tcp
  description Web Servers (HTTP)
  server web1 192.168.0.11:80 check
  server web2 192.168.0.12:80 check
EOF

# haproxy -c -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d

# 5
systemctl enable haproxy.service --now

以下、詳細を補足します。

# 3

この手順では、SELinuxの許可設定を追加しています。 今回の構成では不要なのですが、LB VIPに割り当てるポート番号によっては必要となります。

また、そもそもSELinuxpermissiveモードに変更するなどしてSELinuxの防御を無効化している場合には、この設定は不要です。
(参考) SELinuxのステータス

前半のコメントアウト部分は、全て現状のSELinuxルールを確認するための確認コマンドです。

最初は以下の操作を実施しています。 最後のseinfoコマンドで出力されたポート番号は、HAProxyがデフォルトでLB VIPとして設定可能なポート番号です。 今回はtcp 80のLB VIPを作れれば良いので、デフォルト構成のままでも動作します。

  • SELinuxの確認コマンドを実行するため、必要なrpmパッケージをインストールする (setools-console)
  • haproxyプロセスがbind可能なポート番号を調査する (sesearch, seinfo)
sudo dnf -y install setools-console

sesearch -A -ds -s haproxy_t -p name_bind
# allow haproxy_t commplex_main_port_t:tcp_socket { name_bind name_connect };
# allow haproxy_t http_cache_port_t:tcp_socket { name_bind name_connect };
# allow haproxy_t http_port_t:tcp_socket { name_bind name_connect };
# allow haproxy_t port_type:tcp_socket name_bind; [ haproxy_connect_any ]:True

getsebool haproxy_connect_any
# haproxy_connect_any --> off

seinfo --portcon | grep -P ':(commplex_main_port_t|http_cache_port_t|http_port_t):' | awk '{print $2, $3}'
# tcp 10001-10010
# tcp 443
# tcp 488
# tcp 5000
# tcp 80
# tcp 8008
# tcp 8009
# tcp 8080
# tcp 81
# tcp 8118
# tcp 8123
# tcp 8443
# tcp 9000
# udp 3130
# udp 5000

上記以外のポート番号をbindする要件がある場合は、以下のコマンドを実行してください。 追加で許可できるポート番号がfor文で表示されます。

seinfo -x -a port_type
# 
# Type Attributes: 1
#    attribute port_type;
#   afs3_callback_port_t
#   afs_bos_port_t
# 以下略

for PORT_T in $(seinfo -x -a port_type | grep -Po '\S+_t$') ; do seinfo --portcon | grep -P ":${PORT_T}:" | awk '{print $2, $3}'; done
# tcp 7001
# udp 7001
# udp 7007
# 以下略

sudo setsebool -P haproxy_connect_any=True

getsebool haproxy_connect_any
# haproxy_connect_any --> on

一連のSELinux操作についてもっと詳しく理解したい方は、以下の記事をご覧ください。
SELinuxの実践

今回扱った操作に関連する部分だけ拾い読みするなら、Boolean有無の確認(参考) SELinuxの確認コマンドをご確認ください。

# 4

本手順では、まずオリジナルの/etc/haproxy/haproxy.cfgをベースにして以下のように書き換えています。

まずはglobalセクションです。 globalセクションにはHAProxy全体の基本設定が入っています。 globalセクションの設定はほぼ書き換えていません。

ただ唯一、stats timeout 2mという設定のみ書き換えました。 HAProxyの対話プロンプトを開いてステータス確認などを行う際のセッションタイムアウトをデフォルトの5秒から2分に延長するための便利設定です。 詳しくは#(参考) HAProxyのステータス確認で扱います。

globalセクション配下の各設定について、詳細はHAProxy 3.1 Configuration Manual - Global parametersを参照してください。

続いてdefaultsセクションです。 defaultsセクションには、後続のfrontendセクションやbackendセクションのデフォルト値を指定します。 frontend xxx from yyybackend xxx from yyyのようにfrom yyyの形式でdefaultsセクション名を指定することで、yyyセクションの設定をデフォルト値として参照するようになります。

HAProxyの負荷分散設定はざっくりL4ロードバランシング (mode tcp) とL7ロードバランシング (mode http) の2種類が存在することを想定し、今回もtcphttpという2種類のdefaultsセクションを定義しました。 インストール時に初期設定されていたdefaults設定はmode httpを想定した設定でしたが、今回はその設定をtcphttpの2つに分割しました。 そしてdefaults tcpセクションにはTCPの設定のみを指定し、defaults http from tcpセクションにはHTTPの設定のみを指定しました。 defaults http from tcpセクションはdefaults tcpセクションの設定を踏襲するので、結果としてオリジナルのdefaultsセクションと全く同じ設定値になります。 (BIG-IP用語でいうと、デフォルトのtcp profileとhttp profileの作成に相当します)

本件のハンズオンではdefaults tcpセクションしか使わないものの、将来的にはdefaults http from tcpセクションが役立つときが来るかもしれません。 TLSオフロード/TLSイニシエイトを実装したくなった場合は、新たにdefaults https from httpセクションを作成して設定を拡張できる想定です。

続いて/etc/haproxy/conf.d/web.cfgという設定ファイルですが、ここには今回のハンズオンで使用する負荷分散設定を実装しました。

frontendセクションにはLB VIPの設定を指定します。 (BIG-IP用語ではVirtual Serverに相当します)

frontendセクションで使ったオプションは以下の通りです。 HAProxy 3.1 Configuration Manual - Proxy keywords matrix

オプション 意味
description 説明文。
任意の文字列を指定可能
bind LB VIPの設定 (待ち受けIPアドレスとポート番号)
default_backend frontendと紐付けるbackend名を指定。
結果として負荷分散先のサーバが決まる

backendセクションには負荷分散先のサーバへの転送設定を指定します。 (BIG-IP用語ではpoolに相当します)

backendセクションで使ったオプションは以下の通りです。
HAProxy 3.1 Configuration Manual - Proxy keywords matrix
HAProxy 3.1 Configuration Manual - Server and default-server options

オプション 意味
description 説明文。
任意の文字列を指定可能
server 負荷分散先サーバの転送先IPアドレスとポート番号。
checkを指定するとヘルスチェックが有効になる (デフォルト無効)。
デフォルトではtcptlsによるヘルスチェックとなる
source backendに転送する際の送信元IP指定。
デフォルトではLBのIPアドレスに送信元NATされる。
デフォルトの送信元ポート番号はEphemeral Portとなる。
ヘルスチェックもデフォルトで同様の挙動。
送信元IP/ポート番号変換を無効化することも可能

Webサーバのセットアップ

本手順はWEBサーバ (web1, web2) に対してのみ実行します。 以下の流れで作業します。

  1. Apache httpdのインストール
  2. httpdサービスの起動
  3. HTMLファイルの配置

http通信のためのTCP 80ポートは、すでに#Linuxの基本設定で通信許可されています。

# 1
sudo dnf -y install httpd

# 2
sudo systemctl enable httpd.service --now

# 3
echo "${HOSTNAME}" | sudo tee /var/www/html/index.html > /dev/null

# curl localhost

最後のcurl localhostを実行すると、index.htmlに記述されたホスト名が返ってくる想定です。

疎通確認

では、最後にクライアントPCから疎通確認してみましょう。 今回はcurlを使っていますが、環境によってはブラウザアクセスでご確認いただいても結構です。

複数回アクセスすると、負荷分散によりweb1web2に対して交互に転送されていることがわかります。

curl 192.168.0.100
# web1.test

curl 192.168.0.100
# web2.test

(参考) Keepalivedのステータス確認

以下のようにstateキーワードでログを検索することで、VRRPのステータス遷移を確認できます。

journalctl -eu keepalived.service -g state

# Apr 03 00:24:16 lb1.test Keepalived_vrrp[1546]: (web) Entering FAULT STATE
# Apr 03 00:24:16 lb1.test Keepalived_vrrp[1546]: (web) Entering BACKUP STATE
# Apr 03 00:24:19 lb1.test Keepalived_vrrp[1546]: (web) Entering MASTER STATE
# Apr 03 00:24:36 lb1.test Keepalived_vrrp[1567]: (web) Entering MASTER STATE

ちなみに4行のログは、それぞれ以下のコマンドにより発生しました。

  • sudo systemctl restart haproxy.serviceを実行したことで、Keepalivedhaproxyプロセスの障害を検知してFAULT > BACKUP > MASTERと遷移 (FAULTに遷移した場合は、state MASTERかつpriority 255に設定していても一度BACKUPになるようです)
  • sudo systemctl restart keepalived.serviceを実行したことで、MASTER > (停止) > MASTERと遷移。サービス起動直後にMASTERに遷移するのはstate MASTERかつpriority 255に設定したため

sedコマンドでより簡潔な形に整形することもできます。

journalctl -eu keepalived.service -g state | sed -Ee 's/(.{15}).* \((\S+)\) entering (\S+) state(.*)/\1 | \2 -> \3\4/i'

# Apr 03 00:24:16 | web -> FAULT
# Apr 03 00:24:16 | web -> BACKUP
# Apr 03 00:24:19 | web -> MASTER
# Apr 03 00:24:36 | web -> MASTER

また、ipコマンドでもVRRPのステータスをうかがい知ることができます。 VRRP MASTERのときしかVRRP VIPが表示されないことから、VRRPの状態を察知できます。

以下のように、haproxyサービスを停止することで意図的にVRRPインスタンスFAULT状態に遷移させると、VRRP VIP (192.168.0.100/24) が見えなくなることがわかります。

sudo systemctl stop haproxy.service

ip -br address show
# lo               UNKNOWN        127.0.0.1/8 ::1/128 
# ens3             UP             192.168.0.10/24 fe80::b4e3:96cd:51f2:6fb7/64 
# ens4             DOWN           
# ens5             DOWN 

sudo systemctl start haproxy.service

ip -br address show
# lo               UNKNOWN        127.0.0.1/8 ::1/128 
# ens3             UP             192.168.0.10/24 192.168.0.100/24 fe80::b4e3:96cd:51f2:6fb7/64 
# ens4             DOWN           
# ens5             DOWN        

(参考) HAProxyのステータス確認

CLIによるステータス確認

HAProxy 3.1 Configuration Manual - stats socket

/etc/haproxy/haproxy.cfgstats socket /var/lib/haproxy/statsという設定行があります。

この設定により、HAProxyはUNIXソケットファイルを生成します。 UNIXソケットファイルに接続することで、ネットワーク機器に対して専用コマンドを実行するかのように設定変更やステータス確認コマンドを実行できます。

HAProxy 3.1 Management Guide - Unix Socket commands

UNIXソケットファイルに接続してステータスを確認してみましょう。 手順は以下のとおりです。

sudo dnf -y install socat

socat /var/lib/haproxy/stats readline
prompt

show backend
# web_http

show servers state web_http
# 3 web_http 1 web1 192.168.0.11 2 0 1 1 277 6 3 4 6 0 0 0 - 80 - 0 0 - - 0
# 3 web_http 2 web2 192.168.0.12 2 0 1 1 277 6 3 4 6 0 0 0 - 80 - 0 0 - - 0

使ったコマンドは以下のとおりです。

コマンド 意味
prompt 対話モード・非対話モードを切り替える。
とりあえず最初に実行する
show backend backend名を一覧表示する
show servers state backendのステータス表示。
6列目がステータスで、2が起動状態を表す。
0は停止状態、1は起動中、3は停止中

このままだと少々見づらいので、Linuxコマンドで整形しましょう。

まず基礎知識として、以下のようにsocatstdioと接続することで、非対話形式でコマンドを実行できます。

echo 'show servers state web_http' | socat /var/lib/haproxy/stats stdio
# 3 web_http 1 web1 192.168.0.11 2 0 1 1 769 6 3 4 6 0 0 0 - 80 - 0 0 - - 0
# 3 web_http 2 web2 192.168.0.12 2 0 1 1 769 6 3 4 6 0 0 0 - 80 - 0 0 - - 0

この形式であれば整形できますね。cutコマンドで1〜6列目のみを取り出しつつ、column -tで列の間隔を揃えて表示します。

echo 'show servers state web_http' | socat /var/lib/haproxy/stats stdio | sed 's/^# /#/' | cut -d' ' -f 1-6 | column -t
# #be_id  be_name   srv_id  srv_name  srv_addr      srv_op_state
# 4       web_http  1       web1      192.168.0.11  2
# 4       web_http  2       web2      192.168.0.12  2

だいぶ見やすくなりましたね。 srv_op_state2なので、負荷分散先のサーバへのヘルスチェックは成功しており、通信可能であることがわかります。

GUIによるステータス確認

(参考元: Exploring the HAProxy Stats Page (What You Should Know))

先ほどのCLI手順でも登場したHAProxyのStatsを、今度はWEB画面で確認する手順を紹介します。 ポート番号は80にしていますが、別の番号にしたい場合は80808008などでも良いかもしれません。 これらのポート番号であればデフォルトのSELinuxポリシーで許可されますが、80以外を使う場合はfirewalldの穴あけが必要です。

今回の設定ではstats admin if TRUEによってGUIアクセス時にHAProxyの操作権限が付与されます。 つまりGUI上で負荷分散先Serverの無効化 (BIG-IP風に言えばPool member無効化) などの操作が行なえます。 stats admin if TRUEstats admin if LOCALHOSTに置き換えることで、リモートログイン時には特権なしにできますので、お好みでアレンジしてください。

cat << EOF | sudo tee /etc/haproxy/conf.d/stat.cfg > /dev/null
frontend stats
    mode http
    bind *:80
    stats enable
    stats uri /
    stats admin if TRUE
    # stats refresh 10s
EOF

# sudo firewall-cmd --add-port 80/tcp --permanent
# sudo firewall-cmd --reload

systemctl restart haproxy.service

上記設定を入れた上で、HAProxyのIPアドレス (LB VIPではありません。今回の場合はhttp://192.168.0.10) にクライアントPCのブラウザからHTTPアクセスすると、GUIダッシュボードを確認できます。

ピンク色の枠で囲んだように、緑色のセルから直感的にサーバがUpしていることがわかりますし、Status列からも同様な情報を確認できます。 検証においては便利だと思います。

haproxy_gui_dashboard

以上でHAProxy + Keepalived構成のデモは終わりです。 お疲れ様でした。

参考URL