TT Lab
はじめる
学ぶ 学習パス コース

ICA — Istio認定アソシエイト

プロキシをPodから外すと何が変わるのか

TT Labで続きを見る

一言でいうと

アンビエントモードは、L4とL7を分離して、すべてのワークロードがフルのEnvoyのコストを強制的に負担しなくて済むようにした構造です。その代わり、障害ドメインがPodからノードへ大きくなります。

なぜ必要なのか

サイドカーモデルのコストは、数字で見ると明らかです。Pod 500個のクラスターで、サイドカー1つあたりのメモリが120MiBなら、それだけで約58GiB、CPU requestが100mずつなら50 vCPUが、スケジューリングの容量から消えます。しかも、プロキシがPodの中にあるので、バージョンを上げるには全ワークロードをローリング再起動する必要があり、注入ラベル・リビジョンタグ・Webhookの設定のうち1つでも食い違えば、「あるPodはメッシュの中、あるPodはメッシュの外」という状態になります。この状態でSTRICTを有効にすると、注入されていないPodがすべて切断されます。

ここに、決定的な観察がもう1つ加わります。実際にL7の機能が必要なサービスは、全体の一部です。残りの大多数は、mTLSと基本的なテレメトリーで十分なのに、サイドカーモデルは、これらにもフルのEnvoyを負担させていました。

どう動くのか

アンビエントは、2つの層に分かれます。

ノード間は、HBONEトンネルで流れます。ポート15008で、mTLSの上にHTTP/2 CONNECTで、元のTCPストリームを包む方式です。HTTP/2のストリーム多重化のおかげで、同じノードの組の複数の接続が1つのmTLS接続を共有してハンドシェイクのコストが減り、CONNECTヘッダーに元の宛先とアイデンティティが載るので、受信側のztunnelは、ペイロードを開けなくてもL4の認可を判定できます。

設計の原則を1つ、必ず覚えておく必要があります。waypointは宛先側の所有物です。サイドカーモデルでは、クライアント側のプロキシがルーティングとリトライを行いましたが、アンビエントでは、宛先のサービスを所有するチームが、自分のwaypointでL7のポリシーを執行します。ポリシーの所有権が明確になる代わりに、「呼び出し元ごとに異なるタイムアウト」のようなクライアント側のポリシーは、再設計が必要です。

正直にトレードオフも見る必要があります。waypointを経由する経路は、ホップが3つ(ztunnel → waypoint → ztunnel)なので、サイドカー(ホップ2)より長くなることがあります。そして、ztunnelが落ちると、そのノードのすべてのメッシュトラフィックが影響を受けます。サイドカーは、プロキシの障害がPod 1つに閉じ込められていましたが、アンビエントはノード単位の障害ドメインです。PodDisruptionBudget、優先度クラス、再起動のモニタリングを、運用設計に必ず反映する必要があります。

デバッグは、順序がすべてです。istioctl proxy-configを、トラフィックが流れる順序のとおりに読みます。

listener  이 프록시가 그 포트를 듣고 있는가
   ->
route     VirtualService 가 라우팅 테이블로 번역됐는가
   ->
cluster   DestinationRule(서킷브레이커, TLS)이 반영됐는가
   ->
endpoint  그 subset 에 실제 파드 IP 가 잡혀 있는가

どの段階で期待と食い違っているかを見つければ、直すべきリソースが自動的に決まります。503のレスポンスフラグの判読表も、同じ文脈です。

フラグ 意味 最初に疑うこと
UH no healthy upstream subsetのラベルとPodのラベルの不一致
UO upstream overflow connectionPoolの上限超過
UF upstream connection failure 片側だけSTRICTのmTLSの不一致、ポートのプロトコルの誤認
NR no route VirtualServiceのマッチの漏れ、catch-allの不在
URX max retries reached リトライの使い切り。根本原因はほかのフラグと一緒に追跡します

オブザーバビリティの側で、最後に1つ。Envoyはスパンを自動で作りますが、アプリケーションがインバウンドのリクエストのトレースヘッダーをアウトバウンドに伝播しないと、トレースが途切れます。メッシュを入れたのにトレースがばらばらに出る理由は、ほとんどがこれであり、メッシュが代わりに行えない唯一の部分でもあります。

現場での姿

筆者のホームラボで、hubble-relayとhubble-uiがPendingのままだったことがあります。イベントは0/1 nodes are available: 1 node(s) had untolerated taint(s)でした。原因は単純でした。コントロールプレーンのノードには、node-role.kubernetes.io/control-plane:NoScheduleのtaintがかかっていて、この2つの構成要素は、DaemonSetではなくDeploymentなので、tolerationがありませんでした。CoreDNSはデフォルトのtolerationを持っていて正常に起動したのと対照的で、ワーカーがジョインするとすぐに解消しました。

この事例が、アンビエントを理解するのにそのまま使えます。ztunnelはDaemonSet、waypointはDeploymentです。つまり、ztunnelはノードごとに自動で起動しますが、waypointは、スケジューラーが置き場所を見つけてやる必要があります。taintがかかったノードだけが残っていたり、リソースが不足していたりすると、waypointは静かにPendingのままになり、そのネームスペースのL7のポリシーは、まったく執行されません。「L4は動くのにL7のポリシーだけが効かない」という症状の最初の確認箇所が、waypointのPodの状態である理由です。

もう1つ。そのホームラボは、--skip-phases=addon/kube-proxyでkube-proxyを、インストールして削除したのではなく、最初から未インストールで構築しました。一度でも動くと、KUBE-SERVICES / KUBE-SVC-* / KUBE-SEP-*のチェーンがノードに残るからです。サイドカーからアンビエントへ移行するときにも、同じ原則が当てはまります。1つのネームスペースに、注入ラベルとambientラベルが共存してはならず、注入ラベルを消したあと、必ずロールアウトの再起動で既存のサイドカーを取り除いてから、ambientラベルを付ける必要があります。

次のクイズで確認すること

このモジュールは概念のモジュールです。ラボの代わりに、クイズでアンビエントの構造、HBONE、障害ドメイン、proxy-configを読む順序、レスポンスフラグの判読を点検します。この5つは、試験だけでなく、実際の障害対応で最初に取り出して使うツールです。