規則は正しいのにリクエストが見当違いの所へ行く理由
一言でいうと
VirtualServiceのhttp[]は、Envoyのルート表のroutes[]になります。順序までそのままです。表の名前はサービスポート、バーチャルホストの名前はFQDN:포트(プレースホルダーはポートです)、weightはweighted_clusters、retriesはretry_policyです。変換がこれほど素直なので、VirtualServiceのミスは、Envoyでそのまま再現されます。
なぜ必要なのか
VirtualServiceを直した後、「なぜこのリクエストがv1へ行くのか」を説明できないことが多いです。YAMLだけを見ると、ルールはすべて合っているように見えます。問題はたいてい、ルール同士の関係です。前の広いルールが後ろの狭いルールを覆い隠していたり、2つのルールが同じリクエストに一致するのに、意図と違うほうが先に書かれていたりします。そして、この種類のミスは、istioctl analyzeが捕まえられません。analyzeは、各ルールが指すサブセット・ゲートウェイが存在するかを見るだけで、ルール同士の覆い隠しは見ません。
そのため、変換規則を知る必要があります。規則を知っていれば、VirtualServiceを読みながら、頭の中でEnvoyのルート表を描け、本番では、istioctl proxy-config routesの出力とVirtualServiceを、行単位で突き合わせられます。
どう動くのか
出ていく側のサイドカーは、ポートごとにルート表を1つ置きます。同じ9080を使うサービスが複数あれば、1つの表の中に、サービスごとにバーチャルホストが1つずつ入り、リクエストのHostヘッダーで選びます。
| VirtualService | Envoy |
|---|---|
| サービスポート9080 | route_config.name: "9080" |
hosts: [reviews] |
バーチャルホストreviews.default.svc.cluster.local:9080、domainsにreviews・reviews.default・reviews.default.svc・FQDN |
http[i].match |
routes[i].match(prefix・headersなど) |
http[i].route[].destination.subset |
route.cluster: outbound|9080|v1|… |
weight |
route.weighted_clusters |
retries.attempts / retryOn |
retry_policy.num_retries / retry_on |
timeout |
route.timeout |
どのバーチャルホストのdomainsにもないHostで来ると、404です。表の中では、上から最初に一致するルート1つだけを使います。条件のないルール(catch-all)が前にあれば、後ろのルールは永遠に使われません。
重みは、リクエストごとにサイコロを振ります。75対25で40回送って、30対10がちょうど出ないのは正常です。リトライは、元のリクエスト1つに最大attempts回が追加され、アップストリームは1+attempts回叩かれます。IstioはVirtualServiceにretriesを書かなくても、デフォルトのリトライ(2回、接続失敗・拒否など)を入れ、同じホストを避けるprevious_hosts述語も一緒に付けます。
現場での姿
新しいルールをリストの最後に付けたのに、何の効果もない。最後にすでにcatch-allがあったからです。レビューのときに、「新しいルールがcatch-allより前か」を、1行の確認項目にしておきます。
障害のとき、アップストリームへのリクエストが4倍に跳ね上がる。呼び出しチェーンの複数の段が、それぞれリトライを設定すると、掛け算で増えます。リトライは、チェーンの1か所にだけ、短いperTryTimeoutと一緒に設定します。
Envoyを直接使ったことがある人が、15秒のタイムアウトを期待する。Envoyのルートのデフォルトのタイムアウトは15秒ですが、IstioはVirtualServiceにtimeoutがなければ、ルートに0s(オフ)を入れます。そのため、サイドカーの後ろの遅い呼び出しは、いつまでも待ちます。待ちの上限が必要なら、VirtualServiceに書く必要があり、書いた値がルートのtimeoutにそのまま見えます。
カナリア1%が見えない。リクエスト数十個で確認すると、v2が一度も出ないことがあります。比率は、統計で、十分な回数で見ます。
公式ドキュメント: VirtualService・Debugging Envoy and Istiod
次のラボですること
VS・DRを書いて解析を通し、ルート表・バーチャルホスト・ドメイン名を規則で導出してEnvoyを立てます。Hostヘッダーで表を選ぶこと、ヘッダーマッチとパスマッチが重なるときに先に書かれたものが勝つことを見て、catch-allを前に置いたミスをanalyzeは捕まえず、Envoyはそのまま従うことを確認します。最後に、重みとリトライを数えます。