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

ICA — Istio認定アソシエイト

Gatewayは扉を開け、VirtualServiceは道を作る

TT Labで続きを見る

一言でいうと

Gatewayは、どのポート・ホスト・TLSでトラフィックを受けるかだけを決め、受けたあとのルーティングはすべてVirtualServiceが行います。両者をつなぐのは、VirtualServiceのgatewaysフィールドの1行です。

なぜ必要なのか

KubernetesのIngressは、1つのリソースに入口とルーティングが混在していて、表現力が不足していました。ヘッダーベースのルーティング、重みによる分配、TLSのパススルーモードのような要求は、すべてコントローラーごとのアノテーションに流れ込み、結果としてマニフェストが特定のIngressコントローラーに縛られてしまいました。

Istioは、この問題を責任の分離で解決しました。Gatewayはゲートウェイ用Podのリスナーを宣言し、ルーティングは、メッシュの内部で使っていたVirtualServiceをそのまま再利用します。おかげで、「内部のeast-westルーティング」と「外部から入ってくるnorth-southルーティング」を、同じ文法で書けるようになりました。

どう動くのか

Gatewayは、spec.selectorでどのゲートウェイ用Podにこの設定を付けるかを選びます。通常はistio: ingressgatewayです。Gatewayリソースはプロキシを作りません。すでに動いているゲートウェイのDeploymentに、リスナーの設定を載せるだけです。

TLSのモードは、3つを区別する必要があります。

モード ゲートウェイが行うこと 必要なもの
SIMPLE TLSを終端して、平文で後ろに渡します サーバー証明書(credentialName)
MUTUAL TLSの終端とクライアント証明書の検証 サーバー証明書とCA
PASSTHROUGH 終端せずに、SNIだけを見て渡します 証明書は不要です

PASSTHROUGHは、プロトコルをHTTPSではなくTLSと書く必要があります。ゲートウェイがHTTPをパースしないからで、そのため、この場合のルーティングもHTTPのルールではなく、tlsブロックのsniHostsで行います。credentialNameが指すkubernetes.io/tlsのSecretは、ゲートウェイ用Podが動いているネームスペースにある必要があります。アプリケーションのネームスペースに置いて、なぜ付かないのかと尋ねる事故がよくあります。

バインディングは、2つの条件がどちらも合って初めて成立します。VirtualServiceのgatewaysにGatewayの名前があり、hostsがGatewayのserver hostsと重なっている必要があります。メッシュ内部のトラフィックにも同じルールを適用するには、gatewaysに予約語のmeshを追加します。

ServiceEntryは反対方向、つまりメッシュの外のサービスを内側に連れてくるリソースです。登録すれば、外部APIにもタイムアウト・リトライ・ミラーリング・メトリクスを付けられます。resolutionは、STATIC(endpointsに書いたIPを使う)、DNS(名前を照会する)、NONE(元のリクエストのアドレスを使う)を区別しておけば十分です。メッシュ全体でoutboundTrafficPolicy: REGISTRY_ONLYを有効にすると、ServiceEntryにない外部ホストはブロックされます。

Sidecarリソースは性格が異なります。デフォルトでは、すべてのサイドカーが、メッシュのすべてのサービスの設定を受け取ります。サービスが数千個になると、この設定だけでEnvoyのメモリが数百MiBに膨れ上がります。Sidecarでegress.hostsを絞れば、そのワークロードが知る必要のある範囲だけが送られてきます。形式は네임스페이스/호스트で(プレースホルダーはネームスペースとホストです)、./*は自分のネームスペース、istio-system/*はコントロールプレーンのネームスペースです。

今後の方向性も知っておく必要があります。新規のIngressはKubernetes Gateway API(Gateway + HTTPRoute)で書くことが推奨され、アンビエントモードのwaypointプロキシ自体が、Gateway APIのGatewayリソースとして宣言されます。Istio独自のGateway/VirtualServiceは引き続きサポートされますが、新しい標準の機能は、Gateway APIのほうに先に載ります。

現場での姿

筆者のホームラボでは、CiliumのGateway API実装を立ち上げようとして、一度つまずきました。Gateway APIのCRDをv1.2でインストールしたところ、コントローラーが起動を拒否しましたが、原因は、tlsroutesとreferencegrantsがまだv1ではなかったからでした。CRDをv1.6.1に上げて、ようやくつながりました。

教訓は、Istioにもそのまま当てはまります。Gateway APIは、クラスターにCRDが先にある必要がある別のプロジェクトであり、実装(Istio、Cilium)とCRDのバージョンが合っている必要があります。「istioctl installしたのに、なぜHTTPRouteを作れないのか」という質問の答えがこれです。同じホームラボで、hubble-relayとhubble-uiがPendingのままだったのも、似た性質の問題でした。これらはDaemonSetではなくDeploymentなので、コントロールプレーンのtaintをトレレートせず、ワーカーがジョインするとすぐに解消しました。ゲートウェイのDeploymentも、同じ理由でスケジュールされないことがよくあります。

次のラボですること

バックエンドのワークロードとkubernetes.io/tlsのSecretを実際に作ったあと、SIMPLEとPASSTHROUGHのサーバーを1つのGatewayに入れ、VirtualServiceでバインドし、外部の決済APIをServiceEntryで登録してから、Sidecarで、そのワークロードの視野を3つの項目に絞ります。