壊れたアップストリームを入れてクラスタを観察する
目標
エンドポイントを知る方法と、健全かどうかを判断する方法を別々に立ててみて、健全なものが足りないときにEnvoyが選ぶ2つの道を、自分で作ります。
なぜ重要なのか
プロキシ運用で実際によく見る画面は、ルート表ではなくクラスターの一覧です。どこにサーバーが何台あり、そのうち何台が健全か。その数字を読めれば、503の報告の半分はその場で片付きます。特にパニックモードは、一度目で見ておかないと、本番で初めて遭遇したときに「全部死んでいるのに、なぜ送り続けるのか」で止まってしまいます。優先度の引き継ぎも同じで、設定を読むだけでは、いつ下の段階がトラフィックを受けるのか、見当がつきません。
ステップ
- アップストリームを4つ起動してください。
8084・8086はok、8085・8087はfailです。/root/envd-cluster/cluster.yamlにSTATICクラスターpool(エンドポイントは8084・8085・8086)と/poolルートを置いて起動してください(管理9941、リスナー127.0.0.1:10041)。/clustersからpool::で始まる行だけを選んで、/root/envd-cluster/01-pool.txtに保存してください。 STRICT_DNSクラスターbydnsを追加してください。アドレスはlocalhost、ポートは8084で、dns_lookup_familyはV4_ONLYです。/bydnsルートも一緒に置いてください。/config_dump?resource=static_clustersから、クラスターごとに이름 타입(プレースホルダーは名前とタイプです)を1行ずつ取り出して、/root/envd-cluster/02-types.txtに保存してください。poolにアクティブヘルスチェックを追加してください。intervalは1秒、timeoutは1秒、2つのしきい値はどちらも1で、http_health_checkのパスは/healthzです。少し待ってから、/clustersからpoolエンドポイントのhealth_flagsの行だけを選び、/root/envd-cluster/03-health.txtに保存してください。/poolに12回リクエストして、どのアップストリームが受けたかを数え、/root/envd-cluster/04-spread.txtにp8084=・p8085=・p8086=・total=の4行で書いてください(値は受けた回数)。- クラスター
panicを追加してください。エンドポイントは8085・8087で、どちらもfailであり、同じアクティブヘルスチェックを設定します。/panicルートも置いてください。6回リクエストした後で、/root/envd-cluster/05-panic.txtにcodes=(受け取ったHTTPコードを空白区切りで)、lb_healthy_panic=(同じ名前の統計の値)、membership_healthy=の3行を書いてください。 - クラスター
tieredを追加してください。priority: 0に8085(fail)、priority: 1に8086(ok)を置き、同じアクティブヘルスチェックを設定します。/tieredルートも置いて6回リクエストし、/root/envd-cluster/06-priority.txtにserved_by=(応答したポート)、count=(そのポートが受けた回数)の2行を書いてください。 /root/envd-cluster/07-inventory.txtに、クラスターごとに1行ずつ、이름 타입 엔드포인트수 성한수の4つの値を空白で区切って書いてください(プレースホルダーは名前、タイプ、エンドポイント数、健全数です)。名前順に並べてください。値は目で数えず、/config_dumpと/statsから取り出します。/root/envd-cluster/08-report.mdに、healthy=(poolの健全なエンドポイント数)、total=(poolの全エンドポイント数)、panic_requests_sent=(パニックモードでリクエストが送られたならyes)、failover_port=(ステップ6で実際に応答したポート)の4行を書き、その下に学んだことを4行以上書いてください。
参考
- アップストリームは
python3 /opt/lab/envoy/upstream.py <포트> ok|fail(プレースホルダーはポート番号です)で起動します。failはどのパスで尋ねても503を返すので、ヘルスチェックも一緒に失敗します。 - Envoyを起動するときは
setsid --fork nohup envoy -c <파일> --log-level warn --concurrency 1 > <로그> 2>&1 </dev/null(プレースホルダーは設定ファイルとログファイルです)を使い、再起動する前にはpkill -x envoyで片付けてください。 - ヘルスチェックの間隔が1秒なので、設定を反映した直後はまだ判定がありません。固定の
sleepの代わりに、目的の状態が/clustersや/statsに現れるまで回るループを使ってください。 /clustersは、エンドポイント1つにつき20行以上を出力します。grep 'health_flags'のように、必要な行だけを選んで保存してください。- よくある間違い: 外れ値検出とアクティブヘルスチェックを同じものと考えること。このラボはアクティブ側です。
1つの名前にアドレスを3つぶら下げる
アップストリームを4つ起動してください。8084・8086はok、8085・8087はfailです。/root/envd-cluster/cluster.yamlにSTATICクラスターpool(エンドポイントは8084・8085・8086)と/poolルートを置いて起動してください(管理9941、リスナー127.0.0.1:10041)。/clustersからpool::で始まる行だけを選んで、/root/envd-cluster/01-pool.txtに保存してください。
クラスターは「この名前で呼べるサーバー」の集まりです。STATICはアドレスを設定にそのまま書く最も単純な方式で、そのため設定を変えない限りリストも変わりません。アップストリームはpython3 /opt/lab/envoy/upstream.py <포트> ok|fail(プレースホルダーはポート番号です)で起動します。failはどのパスで尋ねても503を返します。/clustersはエンドポイントごとに何行も出力するので、grepで絞って保存してください。
アドレスを書く代わりに名前を書く
STRICT_DNSクラスターbydnsを追加してください。アドレスはlocalhost、ポートは8084で、dns_lookup_familyはV4_ONLYです。/bydnsルートも一緒に置いてください。/config_dump?resource=static_clustersから、クラスターごとに이름 타입(プレースホルダーは名前とタイプです)を1行ずつ取り出して、/root/envd-cluster/02-types.txtに保存してください。
エンドポイントを知る方法が、そのままクラスターのtypeです。STATICは設定に書いたアドレス、STRICT_DNSは名前を定期的に解決し直して応答に含まれるアドレスすべてをエンドポイントにし、LOGICAL_DNSはそのうちの1つだけを使い続けます。EDSはコントロールプレーンがリストを送り込む方式です。jq -r '.configs[]?.cluster | "\(.name) \(.type)"'で2つの値を取り出せます。
リクエストとは別に、定期的につついて確かめる
poolにアクティブヘルスチェックを追加してください。intervalは1秒、timeoutは1秒、2つのしきい値はどちらも1で、http_health_checkのパスは/healthzです。少し待ってから、/clustersからpoolエンドポイントのhealth_flagsの行だけを選び、/root/envd-cluster/03-health.txtに保存してください。
外れ値検出(outlier detection)は実際のリクエストが失敗するのを見て外しますが、アクティブヘルスチェックはリクエストとは関係なく別につついて確かめます。そのため、トラフィックがない時間帯でも状態がわかり、故障したサーバーへ最初のリクエストが行きません。その代わり、サーバーごとに定期的な負荷が1つ増えます。/clustersのhealth_flagsは、健全ならhealthy、アクティブ検査に失敗すると/failed_active_hcです。検査間隔が1秒なので、設定を反映した直後はまだ判定がないことがあります。フラグが出るまで待ってください。
健全でない所には送らない
/poolに12回リクエストして、どのアップストリームが受けたかを数え、/root/envd-cluster/04-spread.txtにp8084=・p8085=・p8086=・total=の4行で書いてください(値は受けた回数)。
負荷分散は健全なエンドポイントの間だけで回ります。そのため、アクティブ検査に失敗した1つは、リクエストを1回も受けないはずです。応答本文にポートが入っているので、それで数えます。--concurrency 1で起動していれば、健全な2つに正確に半分ずつ行きます。
健全な所が1つもなければどうするのか
クラスターpanicを追加してください。エンドポイントは8085・8087で、どちらもfailであり、同じアクティブヘルスチェックを設定します。/panicルートも置いてください。6回リクエストした後で、/root/envd-cluster/05-panic.txtにcodes=(受け取ったHTTPコードを空白区切りで)、lb_healthy_panic=(同じ名前の統計の値)、membership_healthy=の3行を書いてください。
健全な割合がしきい値(デフォルト50%)を下回ると、Envoyは健康情報を無視して、すべてに送ります。これをパニックモードといいます。奇妙に見えますが、判断は単純です。検査が間違っている可能性があるのに、どこにも送らなければ確実に障害になり、送れば一部だけでも生き残れます。起きたかどうかは、cluster.<이름>.lb_healthy_panic(プレースホルダーはクラスター名です)の統計で見ます。curl -s localhost:<admin>/stats | grep ...で、値だけを取り出してください。
上がすべて死んだら下へ移る
クラスターtieredを追加してください。priority: 0に8085(fail)、priority: 1に8086(ok)を置き、同じアクティブヘルスチェックを設定します。/tieredルートも置いて6回リクエストし、/root/envd-cluster/06-priority.txtにserved_by=(応答したポート)、count=(そのポートが受けた回数)の2行を書いてください。
エンドポイントのグループごとにpriorityを指定できます。普段は優先度0だけを使います。優先度0の健全な割合が下がると、足りない分を優先度1が受け、優先度0が全滅すると、すべてが優先度1へ行きます。別のリージョンの予備サーバーを普段は遊ばせておき、障害のときだけ使う構成が、こうして作られます。/clustersの出力には、エンドポイントごとにpriorityの行があり、どの段階かを確認できます。
4つのクラスターの一覧を作る
/root/envd-cluster/07-inventory.txtに、クラスターごとに1行ずつ、이름 타입 엔드포인트수 성한수の4つの値を空白で区切って書いてください(プレースホルダーは名前、タイプ、エンドポイント数、健全数です)。名前順に並べてください。値は目で数えず、/config_dumpと/statsから取り出します。
運用で最初に見る表が、これです。どのクラスターにサーバーが何台あり、そのうち何台が健全か。cluster.<이름>.membership_totalとmembership_healthyの2つの統計(プレースホルダーはクラスター名です)が、その2つの数字です。タイプは/config_dump?resource=static_clustersから出ます。2か所から取り出した値を、クラスター名でつなげば済みます。
クラスター運用のメモを残す
/root/envd-cluster/08-report.mdに、healthy=(poolの健全なエンドポイント数)、total=(poolの全エンドポイント数)、panic_requests_sent=(パニックモードでリクエストが送られたならyes)、failover_port=(ステップ6で実際に応答したポート)の4行を書き、その下に学んだことを4行以上書いてください。
値は前のステップで作ったファイルから取ってください。記憶で書くとずれます。説明の行には、「アクティブヘルスチェックと外れ値検出の違い」のように、次に設計するときに使える文を書いてください。