こんにちは、yebis0942です。体重計を購入してヘルスチェックを始めました。最近の体重計は計測結果をBluetoothやWi-Fiでクラウドに保存できて便利ですね。
このほどベースマキナでもGoogle Cloud上で運用するサービスのヘルスチェック設定を見直しましたので、それにまつわるTipsをご紹介します。
tl;dr
- Load Balancingではリダイレクトは失敗と判定される
- Cloud Runではリダイレクトは成功と判定される
ヘルスチェックとは
サービス運用におけるヘルスチェックとは、サーバーが正常に動作しているか検証する仕組みを指します。正常に動作していないと判定されたサーバーは、ロードバランサーから切り離されたり、再起動されたりすることになります。
Load Balancingのヘルスチェック
Load Balancingは、ユーザーから受け取ったリクエストを複数のインスタンスに振り分けて負荷分散をするコンポーネントです。ヘルスチェックに成功したインスタンスだけにトラフィックを振り分けます。HTTP系のプロトコルとしてはHTTP, HTTPS, HTTP/2をサポートしていますが、いずれの場合にも200 OK以外のHTTPステータスコードは失敗と判定します。
HTTP、HTTPS、HTTP/2 のヘルスチェックでは、ヘルスチェックのタイムアウト前に HTTP 200 (OK) レスポンス コードを受信する必要があります。301 や 302 など、リダイレクト レスポンス コードを含む他のすべての HTTP レスポンス コードは異常と見なされます。
Cloud Runのヘルスチェック
Cloud Runは、Dockerコンテナを動作させるマネージドサービスです。ヘルスチェックに失敗したコンテナは自動的に再起動されます。HTTP系のプロトコルとしてはHTTP/1のみサポートされていますが、成功条件は以下のようになっています。
200~400 のレスポンスはどれも成功であり、他のレスポンスは失敗を意味します。
コンテナのヘルスチェックを構成する(サービス) | Cloud Run Documentation | Google Cloud
より正確には、HTTPステータスコードが200以上、400未満であれば成功と判定されます。
Load Balancingと違い、301 Moved Permanentlyなどのリダイレクトは無条件に成功となります。リダイレクト先を見ることはありません。
意図せずリダイレクトが発生してしまうケース
あえてヘルスチェックの設定にリダイレクトが発生するURLを使うことはなさそうですが、意図せずそのような状況が発生してしまうことはあります。たとえば、Goのhttp.ServeMux
のTrailing-slash redirectionによって、URLの末尾の/
の有無によって自動的にリダイレクトが行われるようなケースです。*1
ややわざとらしい例ですが、以下のように、/health/
という末尾に/
のあるルーティングを設定したhttp.ServeMux
のHTTPサーバーを考えてみます。
package main import ( "net/http" ) func main() { mux := http.NewServeMux() // /health/ にルーティングを設定する mux.HandleFunc("/health/", func(w http.ResponseWriter, r *http.Request) { // 常にunhealthy w.WriteHeader(http.StatusInternalServerError) }) http.ListenAndServe(":8080", mux) }
このHTTPサーバーの/health/
にアクセスすると意図通り500 Internal Server Errorが返されますが、/health
にアクセスすると301 Moved Permanentlyが返され、/health/
にリダイレクトされます。
先に説明したヘルスチェックの動作と組み合わせると、正常に動いているはずなのにヘルスチェックに失敗しつづけたり、正常に動かなくなってもヘルスチェックに成功しつづけるといった問題が起こりうることが分かります。
Webブラウザではリダイレクトは自動的に解決されてしまうので、検証方法によっては気づきづらいのではないでしょうか。検証環境で実際にヘルスチェックを失敗させてみて挙動を確認しておくのが安全そうです。
まとめ
Google CloudのサービスごとのHTTPのヘルスチェックの挙動の違いと、それが問題になりうるケースをご紹介しました。みなさまの健やかなサービス開発の一助になれば幸いです。
*1:http.Handleおよびhttp.HandleFuncではtrailing slashによる自動リダイレクトは発生しません。