ゲートウェイと外部サービスを繋ぐ
目標
Gatewayで入口を宣言し、VirtualServiceでルーティングを付けるという分業を身につけ、ServiceEntryとSidecarで、メッシュの境界を広げたり狭めたりしてみます。
なぜ重要なのか
Ingressは、メッシュで最も事故が多い箇所です。原因はたいてい次の3つのうちのどれかです。GatewayのhostsとVirtualServiceのhostsが重なっていない、gatewaysフィールドが抜けていてルールがメッシュ内部にだけ適用される、credentialNameが指すSecretが、ゲートウェイ用Podと別のネームスペースにある、という場合です。3つともapplyは成功してトラフィックだけが静かに失敗するので、マニフェストを読む目だけが、唯一の防衛線です。
ServiceEntryとSidecarは、正反対の方向のツールです。一方は、メッシュの外のサービスを内側に連れてきて、ポリシーと観測を付け、もう一方は、サイドカーが知る必要のある範囲を減らして、メモリを節約します。大規模なメッシュでのEnvoyのメモリ問題の標準的な処方がSidecarリソースだという事実は、試験にも実務にも出てきます。
Kubernetesの基本リソースは実際にapplyし、Istio CRDは/root/ica-gateway/の下にファイルとして作成します。
ステップ
- ネームスペース
ica-gatewayを作成し、ラベルistio-injection=enabledを付けてください。 - ネームスペース
ica-gatewayに、Deploymentshop-apiをレプリカ2つ(イメージnginx:1.27-alpine、Podのラベルapp=shop-api)でデプロイし、同じ名前のServiceshop-apiをポート8080、ポート名httpで作成してください。 - ネームスペース
ica-gatewayに、Secretshop-tlsをタイプkubernetes.io/tlsで作成してください。キーはtls.crtとtls.keyの2つで、値はプレースホルダーの文字列でも構いません。 /root/ica-gateway/gw-shop.yamlにGatewayshop-gatewayを作成してください。spec.selectorはistio: ingressgatewayで、serversは2つです。1つ目は、ポート443/プロトコルHTTPS/hostsshop.example.com/tls.mode: SIMPLE/tls.credentialName: shop-tls。2つ目は、ポート15443/プロトコルTLS/hostslegacy.example.com/tls.mode: PASSTHROUGHで、credentialNameは置きません。/root/ica-gateway/vs-shop.yamlにVirtualServiceを作成してください。hostsはshop.example.com、gatewaysはshop-gateway、httpのルーティング先はshop-api.ica-gateway.svc.cluster.localのポート8080です。/root/ica-gateway/se-payment.yamlにServiceEntryexternal-pgを作成してください。hostsはapi.pgprovider.example、locationはMESH_EXTERNAL、resolutionはDNS、portsは番号443/名前https/プロトコルTLSです。/root/ica-gateway/sidecar-default.yamlにSidecarを作成してください。metadata.nameはdefault、metadata.namespaceはica-gatewayで、spec.egress[0].hostsには、正確に3つの項目だけを置きます。自分のネームスペース(./*)、コントロールプレーン(istio-system/*)、そしてステップ6で登録した外部ホスト(*/api.pgprovider.example)です。
参考
- SecretをYAMLで作るときに
stringDataを使うと、base64エンコードを自分で行わなくて済みます。 kubectl create secret tlsは、実際の証明書ファイルを求めるので、この環境ではマニフェストを直接書くほうが早いです。- よくある間違い1: PASSTHROUGHのサーバーのプロトコルを
HTTPSと書くことです。終端しないのに、HTTPをパースすることはできません。 - よくある間違い2: VirtualServiceに
gatewaysを入れ忘れることです。そうすると、そのルールはメッシュ内部のトラフィックにだけ適用され、外部からの入口には何の影響もありません。 - Sidecarのegress hostsの形式は
네임스페이스/호스트です(プレースホルダーはネームスペースとホストです)。ネームスペースが分からない外部ホストには、*/を使います。
ゲートウェイのラボ用のネームスペースを作成する
ネームスペースica-gatewayを作成し、ラベルistio-injection=enabledを付けてください。
自動注入のラベルまで付けて初めて、次のステップのワークロードがメッシュに入ります。
ゲートウェイが送るバックエンドを用意する
ネームスペースica-gatewayに、Deployment shop-apiをレプリカ2つ(イメージnginx:1.27-alpine、Podのラベルapp=shop-api)でデプロイし、同じ名前のService shop-apiをポート8080、ポート名httpで作成してください。
ゲートウェイはトラフィックを受けるだけです。実際に応答するワークロードと、それをまとめるServiceが先にあって初めて、ルーティングの対象ができます。
TLSのSecretを作成する
ネームスペースica-gatewayに、Secret shop-tlsをタイプkubernetes.io/tlsで作成してください。キーはtls.crtとtls.keyの2つで、値はプレースホルダーの文字列でも構いません。
タイプが重要です。credentialNameはkubernetes.io/tlsタイプのSecretだけを認識し、その中にはtls.crtとtls.keyの2つのキーが必要です。このラボ環境にはCAがないので、プレースホルダーの文字列で埋めても構いません。
2種類のTLSモードを1つのGatewayに入れる
/root/ica-gateway/gw-shop.yamlにGateway shop-gatewayを作成してください。spec.selectorはistio: ingressgatewayで、serversは2つです。1つ目は、ポート443/プロトコルHTTPS/hosts shop.example.com/tls.mode: SIMPLE/tls.credentialName: shop-tls。2つ目は、ポート15443/プロトコルTLS/hosts legacy.example.com/tls.mode: PASSTHROUGHで、credentialNameは置きません。
TLSを終端するサーバーと通過させるサーバーでは、プロトコルの表記が違います。終端しない側はHTTPをパースしないのでHTTPSではなく、証明書を持つ必要もありません。
VirtualServiceをゲートウェイにバインドする
/root/ica-gateway/vs-shop.yamlにVirtualServiceを作成してください。hostsはshop.example.com、gatewaysはshop-gateway、httpのルーティング先はshop-api.ica-gateway.svc.cluster.localのポート8080です。
バインディングは、2つの条件が一緒に合う必要があります。gatewaysフィールドに名前があり、hostsがGatewayのserver hostsと重なっている必要があります。destinationにはポート番号も書いてください。
外部の決済APIをメッシュに登録する
/root/ica-gateway/se-payment.yamlにServiceEntry external-pgを作成してください。hostsはapi.pgprovider.example、locationはMESH_EXTERNAL、resolutionはDNS、portsは番号443/名前https/プロトコルTLSです。
メッシュの外のサービスなので、locationの値は決まっていて、endpointsを書かない場合は、名前をどう解決するかを教える必要があります。443ポートのプロトコルはTLSです。
Sidecarで視野を絞る
/root/ica-gateway/sidecar-default.yamlにSidecarを作成してください。metadata.nameはdefault、metadata.namespaceはica-gatewayで、spec.egress[0].hostsには、正確に3つの項目だけを置いてください。自分のネームスペース(./*)、コントロールプレーン(istio-system/*)、そしてステップ6で登録した外部ホスト(*/api.pgprovider.example)です。
ネームスペースのデフォルトになるには、名前が決まっています。egress hostsは、自分のネームスペース、コントロールプレーン、そしてステップ6で登録した外部ホストの、ちょうど3つだけを残してください。外部ホストは、ネームスペースの位置にワイルドカードを書きます。