HAProxy
L4レベルと、L7レベルでの負荷分散(ロードバランシング)に対応するフロントエンド。
HAProxy単体でパーシステンス(srcIP,cookie,etc...)も可能だし、重み付け分散も出来る。
システムを本気で冗長化したいが、金を掛けたくない場合には有効な手段の一つ。
ただし、HAProxyは負荷分散のみの為、完全冗長化をする為にはHeartBeatも組み込む必要がある。
システムに金をかけれる場合、F5のBIG-IPとかA10のThunderとかを使う必要がある。
1. ビルド・インストール
事前にsquidをインストールしておく事。
HAProxyは単純にmakeしてあげれば、ビルドとインストールまで出来るのだが、
今回はHAProxyのバージョン管理も行いたい為、Makefileを直接編集する。
# tar zxvf haproxy-1.5.8.tar.gz # cd haproxy-1.5.8 # cp Makefile Makefile- # sed -e "s/PREFIX = \/usr\/local/PREFIX = \/usr\/local\/haproxy-1.5.8/g" Makefile- > Makefile # diff Makefile- Makefile 83c83 < PREFIX = /usr/local --- > PREFIX = /usr/local/haproxy-1.5.8
Makefileを編集したらビルド開始。下記で指定しているパラメータは以下参照。
TARGET=Linuxのkernel。2.6.xxか3.xx.xxを使っている場合はlinux2628を指定する。 CPU=サーバのCPU種類。面倒だったら"generic"と書けば大丈夫。SPARCを使っているなら"ultrasparc"と書く。 ARCH=今回は未指定。CPUのアーキテクチャを指定したい場合に書く。i386やx86_64等を指定可能。書かなくてもmakeは通る。 ===== # echo "TARGET=linux2628 CPU=x86_64 USE_OPENSSL=1 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1" > make.option # make `cat ./make.option` # make install
上記の手動書き換えを行わない場合、make install時にインストール先を指定するやり方もある
# make TARGET=linux2628 CPU=x86_64 USE_OPENSSL=1 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 # make PREFIX=/usr/local/haproxy-1.5.8 install
HAProxy v2.0.0以降はビルドオプションが変わり"linux2628"が削除された。
また、systemdへの最適化も行われているので次のオプションでビルドを行う。
# echo "TARGET=linux-glibc USE_PCRE=1 USE_PCRE_JIT=1 USE_OPENSSL=1 USE_ZLIB=1 USE_LIBCRYPT=1 USE_SYSTEMD=1 USE_THREAD=1 USE_TFO=1" > make.option # make `cat ./make.option` # make PREFIX=/usr/local/haproxy-2.0.1 install
2. 設定ファイル
設定ファイルの作成と、起動に必要な情報も決めていく。
コンフィグのひな形はexamplesの中にシナリオが用意されているので、それをコピーしても稼働する。
今回は必要最低限に削減したコンフィグを自作する。
# mkdir /var/run/haproxy # groupadd haproxy # useradd -g haproxy -d /var/run/haproxy -s /sbin/nologin haproxy # chown haproxy.haproxy /var/run/haproxy # chmod 755 /var/run/haproxy # cd /usr/local # ln -s /usr/local/haproxy-1.5.8 ./haproxy # cd /usr/sbin # ln -s /usr/local/haproxy/sbin/haproxy .
# cp ${HAProxy_SRC}/examples/haproxy.init /etc/init.d/haproxy # chown root.root /etc/init.d/haproxy # chmod 755 /etc/init.d/haproxy
# mkdir /etc/haproxy # vi /etc/haproxy/haproxy.cfg ===== ## グローバルセクション global # デーモンとして動かす daemon # 起動させるHAProxyデーモンの数 nbproc 2 # 最大コネクション数 maxconn 4096 # HAProxyの実行ユーザ。UID指定も可能 uid haproxy # HAProxyの実行グループ。GID指定も可能 gid haproxy # chroot機能を利用する時のDocumentRoot指定 #chroot /usr/share/haproxy # HAProxyの切り替わりログ。下記の場合、localhostのsyslogにfacility:local1でlevel:info以上を投げる #log 127.0.0.1 local1 info # HAProxyのPID pidfile /var/run/haproxy.pid # HAProxyの状態をWebベースで見れる様にする為のソケット。UIDとGIDは実行ユーザの物と合わせる stats socket /var/run/haproxy/stats.sock uid 5001 gid 5001 ## デフォルトで適用されるパラメータの指定 defaults # ロードバランシングのモード。TCPとHTTPが指定可能 mode http # ログの出力オプション。下記の場合、httplogとHealthCheckのログを出力する option httplog option dontlognull option log-health-checks # クライアントとのKeep-Aliveを維持しつつ、バックエンド接続はクローズする option http-server-close # "Connection: close"ヘッダが無ければ付与してバックエンドに転送する #option httpclose # HAProxyを通過したパケットに、X-Forwarded-ForのHTTPヘッダを追加する option forwardfor # HAProxyのリトライパラメータ。下記の場合、接続を3回トライした後に4回目(最後)の接続で別バックエンドに投げる option redispatch retries 3 # 最大コネクション数 maxconn 2048 # ログの出力方式はglobalセクションの物を使用する。 log global # HAProxyのコネクションタイムアウト。ms指定 timeout connect 3000 # HAProxyのクライアントとサーバのタイムアウト。デフォルトはms指定。clientとserverは同じ値にする timeout client 30s timeout server 30s ## HAProxyのstatsページ。下記の場合、8888ポートでstatsページの表示を受け付ける。 listen hastats 0.0.0.0:8888 # statsページの出力モード。httpのみ mode http # defaultsセクションの指定内容と同様 maxconn 128 timeout connect 3000 timeout server 10000 timeout client 10000 # stats表示を有効にする stats enable stats show-legends # statsページのURL-PATHを指定する stats uri /haproxy?hastats # statsページのログインユーザ[User]とパスワード[Password]を指定する stats auth User:Password # --- Balancing proxy server --- # ## HAProxyのフロントエンド指定。負荷分散先の振り分けルールを作成する。 frontend all 0.0.0.0:8080 # HTTPS接続時のポート番号を指定 acl ssl_port url_end 443 # 振り分けURLの指定。指定出来るパラメータは以下の通り # [url_beg -i "パラメータ"]の様に指定すると、複数指定が可能 # ---------- # url : URLの完全一致 # url_beg : URLの先頭一致 # url_dir : URLのディレクトリ一致 # url_dom : HTTPリクエストのドメイン完全一致 # url_end : URLの後方一致 # url_len : URLの長さ一致 # url_reg : 正規表現のマッチング # url_sub : URLを文字列として見た場合の一致 # ---------- # if "ACL_NAME1" "ACL_NAME2" "etc..." : ACL_NAMEが全てtrueの場合 # unless "ACL_NAME1" "ACL_NAME2" "etc..." : ACL_NAMEが全てfalseの場合(ifの逆) acl url_google url_dom www.google.co.jp use_backend google if url_google ssl_port # 個別の振り分け条件にマッチしなかった場合に使用するデフォルトバックエンド default_backend squid ## デフォルトのバックエンド指定 backend squid # ロードバランサーの分散処理方式 # ---------- # roundrobin : ラウンドロビン方式。weightパラメータ(分散先の重み付け[1~256])を使用可能。バックエンド復帰時のバランシングも可能 # static-rr : ラウンドロビン方式。weightパラメータ(分散先の重み付け[1~256])を使用可能。バックエンド復帰時のバランシング不可 # leastconn : 接続数が一番少ないサーバにコネクションを割り振る。負荷を均等にする場合に効果大 # source : srcIPを元に負荷分散。パーシステンスを効かせる場合には特に有効 # uri [len <length>] [depth <depth>] : URIの"?"より前を元に負荷分散。参照するURIの長さも指定可能。リバースプロキシを作る時に使う程度 balance roundrobin # HTTPヘッダ内のcookieにSERVERIDを付与する。これによってSERVERIDを元にしたcookieパーシステンスが出来る cookie SERVERID insert indirect nocache # 負荷分散先のバックエンドサーバを指定する # server "サーバ名" "IPアドレス:ポート番号" "オプション" # ---------- # cookie "NAME" : HTTPリクエストのcookieに埋め込むパラメータの指定。ここに書いた名前がcookieに埋め込まれる為、ローカル名の指定は注意 # check : バックエンドサーバHealthCheckを行う。デフォルトでは、2秒間隔にチェックを行う # inter "NUM" : 指定数毎にcheckを行う。単位はms # fall "NUM" : 指定数のチェックに失敗したら、最後に+1回のチェックを行った上で、他バックエンドサーバに処理を割り振る # rise "NUM" : 指定数のチェックに成功したら、他バックエンドサーバに割り振っていた処理を巻き取る # backup : バックエンドサーバをバックアップ用途で使用する。backup指定をすると、他バックエンドサーバが落ちない限り処理が割り振られない server proxy01.hogehoge.org 192.168.1.11:8008 cookie proxy01 check server proxy02.hogehoge.org 192.168.1.12:8008 cookie proxy02 check ## 個別バックエンド指定 backend google balance roundrobin cookie SERVERID insert indirect nocache server proxy01.hogehoge.org 192.168.1.11:8008 cookie proxy01 check inter 1000 fall 2 rise 4 server proxy02.hogehoge.org 192.168.1.12:8008 cookie proxy02 check backup
"stats socket"で指定した"/var/run/haproxy"はtmpfsの為、OSを再起動するとディレクトリの中身が空になりHAProxyが起動出来なくなる。
その為、initスクリプトに"/var/run/haproxy"のチェックとディレクトリ作成処理を追加しておく。
# vi /etc/init.d/haproxy ===== = [ -f /etc/$BASENAME/$BASENAME.cfg ] || exit 1 + if [ ! -e /var/run/${BASENAME} ] ; then + mkdir /var/run/${BASENAME} + chown root.root /var/run/${BASENAME} + chmod 750 /var/run/${BASENAME} + fi = RETVAL=0
OSがsystemdを採用している場合、ビルド時にsystemdフラグを有効化すると、
OSで"sd_notify()"関数をフックして起動制御する事が出来る。
# vi /etc/systemd/system/multi-user.target.wants/haproxy.service --- [Unit] Description=HAProxy Load Balancer After=network.target [Service] Type=notify # Make sure /var/run/haproxy exists ExecStartPre=/usr/bin/install -d /var/run/haproxy -o haproxy -g haproxy ExecStartPre=/usr/local/haproxy/sbin/haproxy -f ${CONFIG} -c -q # Set environment variable PIDFile=/var/run/haproxy.pid EnvironmentFile=-/etc/default/haproxy EnvironmentFile=-/etc/sysconfig/haproxy Environment="CONFIG=/etc/haproxy/haproxy.cfg" "PIDFILE=/var/run/haproxy.pid" ExecStart=/usr/local/haproxy/sbin/haproxy -Ws -f ${CONFIG} -p ${PIDFILE} ExecStop=/bin/kill -USR1 $MAINPID ExecReload=/usr/local/haproxy/sbin/haproxy -f ${CONFIG} -c -q ExecReload=/bin/kill -USR2 $MAINPID KillMode=mixed Restart=always SuccessExitStatus=143 LimitNOFILE=65535 LimitNPROC=65535 StartLimitBurst=0 [Install] WantedBy=multi-user.target
3. 起動方法
設定ファイルを作成したら、起動スクリプトを叩いてみる。
また、必要に応じてログローテートの設定も作成する。
#起動 # /etc/init.d/haproxy start #停止 # /etc/init.d/haproxy stop #コンフィグの再読込 # /etc/init.d/haproxy reload
4. HAProxyのstats表示
HAProxyの動作状況を確認するには、コンフィグで書いたstatsURLへ接続する必要がある。
上記の通りに設定している場合、"http://[HAProxyのサーバアドレス]:8888/haproxy?hastats"でアクセス出来る。
また、ユーザ名とパスワードを指定している場合、このタイミングでパスワード等を入力する必要がある。
正常に稼働している場合、下記のような画面が表示される(下のは実際にns-lab BBで動作しているHAProxyのステータス)
5. ロードバランシングパケットの転送
HAProxyとSquid(HAProxyの上位Proxy)を同じサーバで稼働させる時にはパケット転送(折り返し)が発生する為、
ip_forwardをenableにする必要がある。
・起動中のサーバでip_forwardをenableにする # echo 1 > /proc/sys/net/ipv4/ip_forward ===== ・永続的にip_forwardをenableにする # vi /etc/sysctl.conf < net.ipv4.ip_forward=0 --- > net.ipv4.ip_forward=1 ===== ・/etc/sysctl.confが無い場合は、/etc/rc.d/rc.localに下記を直書きする echo 1 > /proc/sys/net/ipv4/ip_forward
6. フロントエンドのSSL化
HAProxyではWebアクセスフロントエンドとしてSSL待ち受けが出来るようになった。
ただし、WordPressの様にアプリケーションでHTTP/HTTPSを判定する場合、
ブラウザのSSL混在コンテンツエラーに注意する。
## グローバルセクション global # X-Forwarded-ForのHTTPヘッダを追加する option forwardfor # 証明書の検証を無効化。自己証明書を利用する場合は必須 ssl-server-verify none # SSL POODLE脆弱性対応 ssl-default-bind-options no-sslv3 no-tls-tickets # SSL Cipher Suiteの限定化 ssl-default-bind-ciphers EECDH+HIGH:EDH+HIGH:HIGH:MEDIUM:+3DES:!ADH:!RC4:!MD5:!aNULL:!eNULL:!SSLv3:!SSLv2:!LOW:!EXP # 暗号化強度のデフォルト値 tune.ssl.default-dh-param 2048 ## HAProxyのHTTPSフロントエンド設定 frontend https # HTTPSの待ち受け設定。crtの指定にはssl-default-bind-optionsと同じオプションも個別追加出来る # "crt"はファイル指定とディレクトリ指定が可能。ディレクトリ指定時はディレクトリ配下を全てincludeする動作となる。 # "crt"で指定したディレクトリの中には、公開鍵・秘密鍵を下記の様に纏めたファイルを設置する # ---------- # -----BEGIN CERTIFICATE----- # MIIEGTCC..... # ............. # ............. # -----END CERTIFICATE----- # -----BEGIN RSA PRIVATE KEY----- # MIIEowIB..... # ............. # ............. # -----END RSA PRIVATE KEY----- # ---------- bind 0.0.0.0:443 ssl crt /etc/ssl/certs/haproxy.pem # X-Forwardedヘッダーに、SSL通信の値を追加する http-request set-header X-Forwarded-Proto https http-request set-header X-Forwarded-Port %[dst_port] http-request set-header X-Forwarded-Host %[req.hdr(Host)] # HTTPSバックエンドサーバの振り分けルール acl hoge-dst hdr_dom(host) -i www.hogehoge.org acl hoge-port dst_port 443 use_backend hoge-back if hoge-dst hoge-port backend hoge-back # SourceHashで負荷分散を行う balance source # ssl : バックエンドサーバにSSL(HTTPS)でアクセス # verify none : 証明書検証を明示的に無効化。自己証明書を利用する場合は必須 server www1.hogehoge.org 192.168.1.11:443 check ssl verify none server www2.hogehoge.org 192.168.1.12:443 check ssl verify none
バックエンドがWordPressの場合、SSL混在エラーの出る場合がある。
エラーが出た場合は、wp-config.phpに下記設定を追加する
if((empty($_SERVER['HTTP_X_FORWARDED_HOST']) == false)){ $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST']; } if((empty($_SERVER['HTTP_X_FORWARDED_FOR']) == false)){ $_SERVER['REMOTE_ADDR'] = $_SERVER['HTTP_X_FORWARDED_FOR']; } if((empty($_SERVER['HTTP_X_FORWARDED_PROTO']) == false) && ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')){ $_SERVER['HTTPS'] = 'on'; }