拡張ポイントが与えるものと、その代償
一言でいうと
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を洗い出して、バージョンアップのリスクをコードで出力する点検スクリプトを作ります。