haproxy
CentOS6.x

HAProxyを使い始めてみる

More than 3 years have passed since last update.

HAProxy1とは何か? から始まり、基本的な使い方までを調べました。


HAProxyとは

多機能なプロキシサーバです。ソフトウェアロードバランサの一種でもあります。古くから開発が続けられ、非常に高速かつ堅牢で信頼性が高いことを売りにしているようです。

HAProxyが何であって何でないかは、 ドキュメントに箇条書きで記載 されています。

ざっくりまとめると、こんな感じのことが書かれています。


  • TCP接続のプロキシとして動作させ、アクセス経路を設定することができる

  • HTTPリバースプロキシとしての機能を持ち、ルールに従ってリクエストを別のサーバに渡すことができる


    • このとき、URLやヘッダの書き換えも行える

    • SSLやHTTP圧縮を肩代わりできる



  • TCP/HTTPの正規化器(normalizer)となる


    • 不正なトラフィックからの防護を提供する



  • 負荷分散機能を提供する

  • ロギング機能を持つので、ネットワーク上の観測点(an observation point)として機能させることができる

  • トラフィックのコントロールができる


    • 例えば、同時接続数の制限

    • 例えば、IPベースのフィルタリング



一方で以下のような機能を持たない、とされています2


  • HTTPプロキシではない。つまりインターネットへのアクセスするブラウザがアクセスするような性質のものではない

  • キャッシュもしない

  • bodyの書き換えもしない

  • Webサーバではない

  • IPやUDPといったパケットレベルのレイヤは見ない


インストール

CentOSの場合、yumで入れられます。ただし、CentOS7であっても、執筆時点での最新安定版である1.6は入らないので、最新版が欲しければソースからビルドする必要があるかもしれません。

$ sudo yum install -y haproxy


設定の方法

設定はhaproxy.cfgに記述します。yumからインストールしたCentOSの場合は/etc/haproxyにあります。

例として設定ファイルは以下のような構造になっています。この例は設定ドキュメントから転載しました。


haproxy.cfg

    # Simple configuration for an HTTP proxy listening on port 80 on all

# interfaces and forwarding requests to a single backend "servers" with a
# single server "server1" listening on 127.0.0.1:8000
global
daemon
maxconn 256

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

frontend http-in
bind *:80
default_backend servers

backend servers
server server1 127.0.0.1:8000 maxconn 32

# The same configuration defined with a single listen block. Shorter but
# less expressive, especially in HTTP mode.
global
daemon
maxconn 256

defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms

listen http-in
bind *:80
server server1 127.0.0.1:8000 maxconn 32


設定ファイルはいくつかのセクションに分かれています。大きく分けて、HAProxyのプロセスとしての動作や、各種チューニングパラメータについての設定をするglobalセクションと、プロキシとしての動作の設定をするプロキシセクションがあります。

プロキシセクションはさらにdefaultsfrontendbackendlistenに細分化されていることが分かると思います。次のような役割の違いがあるので、それに従って書き分けます。



  • frontendには、プロキシとしてアクセスを受ける側についての設定をします


  • backendには、プロキシとしてアクセスを振り分ける先のサーバについての設定をします


  • listenには、フロントエンドとバックエンドを合わせて一つのプロキシ設定にしたものを、まとめ書きすることができます


  • defaultsに書いた設定は、それに続くセクション全てで有効になります。つまり共通する設定をdefaultsにまとめることができます



    • defaultsによって、そこまで有効だったデフォルトパラメータはリセットされます




とりあえずログを取れるようにする

yumでインストールした直後は、起動させることはできてもログが出ません。とりあえずログが見えるようにしました。

ロギングの方法は複数提供されていますが、一番シンプルなのはsyslogで渡す方法です。HAProxy側の設定項目としてlogパラメータを設定します。

http://cbonte.github.io/haproxy-dconv/configuration-1.6.html#3.1-log


haproxy.cfg

global

log 127.0.0.1 local2

これでローカルホストのUDPポート514を利用してログを送るようになります。2番目のパラメータであるファシリティは、ここではインストール時のテンプレートにならって、local2をそのまま利用します。

ログを受け付けられるように、rsyslogの設定も変更してUDPを有効化しておきます。


/etc/rsyslog.conf

# Provides UDP syslog reception

$ModLoad imudp
$UDPServerRun 514

ファシリティlocal2のログ出力を/var/log/haproxy.logに向けます3

$ sudo touch /etc/rsyslog.d/haproxy.conf


/etc/rsyslog.d/haproxy.conf

local2.info                       /var/log/haproxy.log

local2.* ~

設定を反映するために、rsyslogとhaproxyをrestartします。

$ sudo service rsyslog restart

$ sudo service haproxy restart

/var/log/haproxy.logが作成されログが出始めたら成功です。


基本的なロードバランス機能の確認

ロードバランス機能を設定することで動作確認をします。ここでは、Sinatraを用いた簡易サーバを用意しました。ロードバランスの状況を分かりやすくするために、プロセスIDを出力するようにしてあります。


serve.rb

require 'sinatra'

get '/' do
"Hello HAProxy!! pid=#{Process.pid}\n"
end


HAProxy側の設定としては、以下のようなものを用意しました。デフォルトのテンプレートを軽く修正したものです。


haproxy.cfg


global
log 127.0.0.1 local2
chroot /var/lib/haproxy
pidfile /var/run/haproxy.pid
maxconn 4000
user haproxy
group haproxy
daemon

defaults
mode http
log global
option httplog
timeout connect 10s
timeout client 1m
timeout server 1m

frontend main *:5000
default_backend app

backend app
balance roundrobin
server app1 127.0.0.1:5001 check
server app2 127.0.0.1:5002 check


この設定では、フロントエンドがポート5000での待ち受けをし、ラウンドロビンに基づいてローカルホストのポート5001と5002にアクセスを割り振ります。ちなみにtimeoutの3つを消してしまうとwarningが出てしまいました。理由はよく分かっていません……。

$ ruby serve.rb -p 5001 2>/dev/null &

[1] 15176
$ ruby serve.rb -p 5002 2>/dev/null &
[2] 15220
$ curl localhost:5000/
Hello HAProxy!! pid=15176
$ curl localhost:5000/
Hello HAProxy!! pid=15220
$ curl localhost:5000/
Hello HAProxy!! pid=15176
$ curl localhost:5000/
Hello HAProxy!! pid=15220

ラウンドロビンしていることが確認できます。片側を落としてさらにcurlで叩いてみます。

$ kill 15176

$ curl localhost:5000/
Hello HAProxy!! pid=15176
[1] - 15176 done ruby serve.rb -p 5001 2> /dev/null
$ curl localhost:5000/
Hello HAProxy!! pid=15220
$ curl localhost:5000/
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
$ curl localhost:5000/
Hello HAProxy!! pid=15220
$ curl localhost:5000/
Hello HAProxy!! pid=15220

何か見えてはいけないものが一瞬見えていますが、とはいえ、ちゃんと停止したサーバの切り離しができている様子です。この辺りの微妙な挙動は要検証でしょうか。パラメータもたくさんあるし……。


まとめ

HAProxyの概要・設定の書き方・基本的な設定と動作確認をしてみる所までを調べてまとめました。

HAProxyはものすごく多機能です。この記事でまとめた機能はほんの一部にすぎません。例えばACL、HTTPヘッダのrewrite、stick-tablesなどには折を見て触れてみたいところではあります。


参考資料

ドキュメント類は最新の1.6系のものを参照しました。記事で動作させてみたのは1.5系なのですが、基本機能ではそこまで違いはないだろうし……?





  1. HAってやっぱりHigh Availabilityなのかなあ。たぶんそうなんでしょう。 



  2. これらについては他に優れたソフトウェアがある、とのこと。例えば、SquidやVarnishが例示されています。 



  3. 単にlocal2.* /var/log/haproxy.logとだけ書いてしまうと、動作確認中、バックエンドが全台落ちているときに出るemergログが、rsyslogデフォルト設定の*.emerg *に引っかかってしまい、コンソールがややうるさくなるという問題が発生しました。この記事では動作確認のためと割り切り、info以上のログのみファイル出力し、他は捨てるようにしています。