どうも、cloudpack の 自称 HAProxy 王子の かっぱ(@inokara)です。
はじめに…
前回「HAProxy チートシート(acl や SSL サポート等)」の続きです。
前回の記事で URI パスによる振り分けを検証した際に…以下のようなプロキシが出来なくて残念な気分になっていたら…
reqirep を利用してバックエンド側でパスを書き換えるという方法があったので試してみましたとさ。
reqirep を使わない場合
制限
上記のようにクライアントから以下のようにアクセスがあり、acl
を利用してパス毎のサーバーを振り分けたい場合に…
http://example.com/hoge
バックエンド側のアプリケーションサーバー側で以下のように設定する必要がありました。
${Document_Root}/hoge
むむ…これはちょっと…
reqirep を使う
reqirep とは…
ドキュメントには以下のように書かれています。
Replace a regular expression with a string in an HTTP request line
HTTP のリクエストを正規表現で書き換える機能で以下のように記述します。
reqirep[{if | unless} ] (ignore case)
例
例えば、/user/
というアクセスがあった場合にbackend のホスト側で /
に書き換えたい場合には以下のように設定します。
reqirep ([^ ]*) /user/(.*) 1 /2
haproxy.cfg
クライアントからアクセスが /hoge/
であった場合には backend hoge_bk
の ${Document_Root}/
にルーティングさせる場合には以下のように設定します。
frontend ha-test bind 0.0.0.0:80 acl hoge path_beg /hoge acl fuga path_beg /fuga use_backend hoge_bk if hoge use_backend fuga_bk if fuga default_backend hoge_bk backend hoge_bk reqirep ([^ ]*) /hoge/(.*) 1 /2 server web01 ${backend_host01}:80 check backend fuga_bk reqirep ([^ ]*) /fuga/(.*) 1 /2 server web01 ${backend_host02}:80 check
同様に /fuga/
でアクセスがあった場合には backend fuga_bk
の ${Document_Root}/
にルーティングさせる場合にも同様です。
ということで…
reqirep を利用することで下図のような動作を HAProxy で行わせることが出来るようになります。
やったー。HAProxy サイコー。
demo
ということで…
デモってみます。
仕込み(HAProxy)
frontend balancer-test bind 0.0.0.0:80 stats enable stats uri /haproxy?stats acl hoge path_beg /hoge acl fuga path_beg /fuga use_backend hoge_bk if hoge use_backend fuga_bk if fuga default_backend hoge_bk backend hoge_bk reqirep ([^ ]*) /hoge/(.*) 1 /2 reqadd Use_HAProxy_backend: hoge_bk server web01 backend_host:8001 check backend fuga_bk reqirep ([^ ]*) /fuga/(.*) 1 /2 reqadd Use_HAProxy_backend: fuga_bk server web02 backend_host:8002 check
/hoge
で hoge_bk
に振り分けを行い、/fuga
で fuga_bk
に振り分けを行います。また、ちゃんとバックエンドが振り分けられているかを識別する為に以下のようにヘッダを追加しています。
reqadd Use_HAProxy_backend: [hoge_bk|fuga_bk]
バックエンド側の Nginx のログに記録させます。
仕込み(バックエンドの Nginx)
server { listen [8001|8002]; location / { root [html_8001|html_8002]; index index.html index.htm; } }
それぞれの DocumentRoot 以下に hoge
又は fuga
と書いた index.html を配置しました。
また、Nginx のログに HAProxy 側で付加した Use_HAProxy_backend
ヘッダを記録するように以下のように設定を追加しています。
underscores_in_headers on; log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '$ssl_protocol/$ssl_cipher' '"$http_user_agent" "$http_x_forwarded_for"' ' "$http_use_haproxy_backend"';
underscores_in_headers on;
で _
付きのリクエストヘッダを容認します。また、Use_HAProxy_backend
は変数の $http_use_haproxy_backend
に記録されます(オリジナルヘッダの場合には $http_
を付けるようです)。
アクセス
/hoge にアクセスしてみましょう
% curl ec2-xx-xx-xx-xxx.ap-northeast-1.compute.amazonaws.com/hoge/ hoge
Nginx のログには以下のように記録されました。
xxx.xxx.xxx.xxx - - [16/Nov/2014:08:46:27 +0000] "GET / HTTP/1.1" 200 5 "-" -/-"curl/7.30.0" "-" "hoge_bk"
ちゃんとhoge_bk
に振り分けられて ${DocumentRoot}/index.html
にアクセスされています。
/fuga にアクセスしてみましょう
% curl ec2-xx-xx-xx-xxx.ap-northeast-1.compute.amazonaws.com/fuga/ fuga
Nginx のログには以下のように記録されました。
xxx.xxx.xxx.xxx - - [16/Nov/2014:08:49:28 +0000] "GET / HTTP/1.1" 200 5 "-" -/-"curl/7.30.0" "-" "fuga_bk"
ちゃんと fuga_bk
に振り分けられて ${DocumentRoot}/index.html
にアクセスされています。
お疲れ様でした
HAProxy があればー、なんでも出来るー(アン◯ニオ猪木風)って感じです。
あと、Nginx でオリジナルヘッダを記録する方法を知ることが出来て良かったデス!
元記事はこちらです。
「HAProxy チートシート(ACL を使ったリクエストパスによる振り分けについて)」