share facebook facebook2 twitter menu hatena pocket slack

2015.01.15 THU

HAProxy のバックエンド Web サーバーヘルスチェックでコンテンツの中身をチェックする

川原 洋平

WRITTEN BY川原 洋平

取り急ぎのメモの cloudpackかっぱ (@inokara) です。

はじめに

HAProxy でバックエンドのヘルスチェックは option httpchk で定義しますが、option httpchk を設定して行われるヘルスチェックはステータスコードのみのチェックとなります…ということで。

option httpchk

HAProxy においてバックエンドの Web サーバーをヘルスチェックする際には以下のように設定することでチェックすることが可能です。

option httpchk

但し、上記の設定の場合には…

By default, “option httpchk” considers that response statuses 2xx and 3xx
are valid, and that others are invalid.

上記のようにバックエンドの Web サーバーをチェックしてステータスコードが 2xx か 3xx が返ってくることで正常と判断しています。これでも十分と言えば十分なのですが、Web サーバーは生きているけど DB 障害等でアプリケーションは死んでいるという場合にはこのチェックでは正常に死活をチェック出来ない可能性があります。これを解決する為に任意の URL にアクセスしたらアプリケーションの稼働状態を任意の文字列で表現(例えば ok 等を表示する)することで Web サーバーは生きていてもアプリケーションが稼働しないことを外部から監視することが可能になります。

この任意の URL に出力される文字列を HAProxy のヘルスチェックとして利用する為に http-check expect を利用します。

http-check expect

設定

http-check expect は以下のように定義することが出来ます。下記のようにステータスコードとレスポンスボディの文字列に合わせて、ステータスコードとレスポンスボディを正規表現でマッチさせたり ! を付加することで、ステータスコードが 5xx で無ければというヘルスチェックを行うことが可能です。

ステータスコード

http-check expect status 200

レスポンスボディの文字列

http-check expect string ok

ステータスコードを正規表現でマッチ

以下、ドキュメントからの抜粋です。

http-check expect ! rstatus ^5

レスポンスボディを正規表現でマッチ

以下、ドキュメントからの抜粋です。

http-check expect rstring <!--tag:[0-9a-f]*</html>

簡単に動作確認

以下のようなアプリケーションを用意します。

require 'sinatra'
require 'sinatra/reloader'
require "sinatra/multi_route"

get '/check' do
  "ok"
end

HAProxy は以下のように設定します。

backend app_bk
  mode http
  option forwardfor
  option httpchk GET /check
  http-check expect string ok
  server app01 127.0.0.1:8081 inter 3000 check
  server app02 127.0.0.1:80 backup

この状態で HAProxy にアクセスすると…

$ http localhost:8000/check
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: text/html;charset=utf-8
Server: thin 1.5.0 codename Knife
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

ok

上記のようにアプリケーションにアクセスすることが出来ましたが、アプリケーションを以下のように修正すると…

require 'sinatra'
require 'sinatra/reloader'
require "sinatra/multi_route"

get '/check' do
  "ng"
end

以下のようにヘルスチェックでは失敗となり backup で定義された Web サーバーに転送されます。(但し、直ぐに切り替わるのではなくヘルスチェックの回数が fall で定義されている回数失敗した後に転送されます。)

$ http localhost:8000/check
HTTP/1.1 404 Not Found
Content-Length: 280
Content-Type: text/html; charset=iso-8859-1
Date: Tue, 13 Jan 2015 05:52:30 GMT
Server: Apache

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /check was not found on this server.</p>
<hr>
<address>Apache Server at localhost Port 8000</address>
</body></html>

となります。

また、アプリケーション側で以下のような出力をさせた場合には…

require 'sinatra'
require 'sinatra/reloader'
require "sinatra/multi_route"

get '/check' do
  "oknxxx.xxx.xxx.xxx"
end

以下のようにヘルスチェックは成功してアプリケーション・サーバーに転送されます。

$ http localhost:8000/check
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: text/html;charset=utf-8
Server: thin 1.5.0 codename Knife
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

ok
xxx.xxx.xxx.xxx

ということは http-check expect string ok による文字列のチェックは該当の文字列が含まれていたらという条件のようです。

ということで…

HAProxy で出来ないことは無さそうです…。恐ろしや。

元記事はこちらです。
HAProxy のバックエンド Web サーバーヘルスチェックでコンテンツの中身をチェックする