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

Istioサービスメッシュ

拡張ポイントが与えるものと、その代償

TT Labで続きを見る

一言でいうと

EnvoyFilterは、Istioの抽象ではなく、Envoyの内部構造を直接いじるエスケープハッチなので、バージョンアップに弱いです。WasmPluginは、同じ要求を、バージョンへの依存が少ない形で書けますが、すべてのケースを代わりに担えるわけではありません。

なぜエスケープハッチが必要だったのか

IstioのトラフィックAPIは、よく選ばれた抽象です。どこへ送るか、どれだけ待つか、何回やり直すか。大半の要求は、この言語で表現できます。ところが、メッシュを長く使っていると、この言語にない要求が必ずやってきます。「すべてのレスポンスに社内の追跡ヘッダーを付けてほしい」「このワークロードの前にだけレート制限をかけてほしい」「アクセスログに業務のフィールドをもう1つ入れてほしい」といったものです。

プロキシ自体(Envoy)は、こうしたことをすべてできます。足りないのは、Istioの言語です。EnvoyFilterは、そのギャップを埋めるために開けてある扉で、Istioが生成したEnvoy設定に対して、上塗りする場所と内容を直接書きます。

どう動くのか

EnvoyFilter1つはパッチのリストで、パッチごとに4つのことを決めます。

項目 何を決めるか 値の例
applyTo どの種類のEnvoy設定をいじるか HTTP_FILTER、NETWORK_FILTER、CLUSTER、LISTENER
match.context どの方向の設定か SIDECAR_INBOUND、SIDECAR_OUTBOUND、GATEWAY、ANY
patch.operation どう上塗りするか MERGE、ADD、REMOVE、INSERT_BEFORE、INSERT_FIRST
priority 複数のパッチの適用順序 整数。小さいほど先

4つの値はすべて列挙型なので、APIサーバーが強制します。間違った値を入れると、オブジェクトが作られず、許可される値の一覧がそのまま返ってきます。これは良い知らせです。悪い知らせは、値がすべて合っていても、設定が適用される保証はないということです。matchは、Envoy設定の中から対象を見つけ出す条件ですが、見つからなければ、何も起こりません。エラーもイベントもありません。バージョンアップでフィルター名やチェーンの構造が変わると、まさにこの状態になります。

ここにもう1段あります。INSERT_BEFOREのように、ほかのパッチを基準にする操作は、順序が決まって初めて意味がありますが、priorityを書かないと、順序が保証されません。istioctl analyzeが、この場合をIST0151として検出してくれます。同じツールは、typed_configなしでフィルター名だけを書いた場合も指摘します。名前だけを書く方式は古い書き方で、今後変わる部分です。

範囲も重要です。EnvoyFilterは、置かれたネームスペースにだけかかりますが、ルートネームスペース(デフォルトはistio-system)に置くと、メッシュ全体にかかります。そこにworkloadSelectorを付けると、ラベルが合うワークロードに絞られます。事故の大きさは、この選択1つで決まります。

WasmPluginは、同じ要求を別の形で書きます。Envoyの内部構造の代わりに、どの段階に何を差し込むかだけを述べます。phaseはAUTHN、AUTHZ、STATS、UNSPECIFIED_PHASEの4つだけで、コードはOCIイメージとして別にデプロイします。内部構造を参照しないので、バージョンアップにはずっと強いです。その代わり、できないこともあります。クラスターの設定やリスナー自体を変える作業は、やはりEnvoyFilterの出番です。

現場での姿

最もよくある事故は、「去年入れたEnvoyFilterが、いつからか効かなくなった」というものです。誰も削除していませんし、オブジェクトもそのまま残っています。バージョンアップのどこかの時点で、マッチ条件が外れ始めただけです。これを事前に捕まえる方法は2つしかありません。バージョンアップの前に、一覧を洗い出すチェックリストを置くか、バージョンアップのあとに、実際のプロキシ設定を取得して確認する手順を置くかです。どちらもなければ、次の障害のときに、原因候補の一覧の一番下で見つかります。

2つ目は、範囲を広く取ったために起きた事故です。あるチームが、自分のサービスにヘッダーを付けるために作ったEnvoyFilterが、ルートネームスペースに入って、メッシュ全体のプロキシにかかったことがあります。レビューで目につかない理由は、マニフェストが短く、まともに見えるからです。ネームスペースの1行が、そのまま影響範囲になります。

このラボ環境の限界

ラボのPodには、istiodも本物のサイドカーもありません。そのため、EnvoyFilterが実際のEnvoy設定に反映される様子は見られません。istioctl proxy-configでパッチの前後を比較する作業は、この環境ではできません。その代わり、本物のAPIサーバーがあるので、スキーマによる強制は実際に確認でき、istioctl analyzeも、クラスターのオブジェクトを読んで、同じ判定を下してくれます。「宣言が受け入れられるか」と「宣言が実際に効くか」は別の問いで、このラボでは、前者と、その前の段階のリスク点検までを扱います。

次のラボですること

列挙型を3つ同時に間違えて、APIサーバーが何を返すかを見て、直して実際に適用します。メッシュ全体にかかる場所と、ワークロード1つにかかる場所を並べて作り、範囲を比較し、優先度のない相対位置のパッチが、アナライザーにどう検出されるかを見ます。同じ要求をWasmPluginで書いてみて、最後に、クラスターのすべてのEnvoyFilterを洗い出して、バージョンアップのリスクをコードで出力する点検スクリプトを作ります。