移行できなかったサーバーをメッシュに入れる — WorkloadGroup と WorkloadEntry
目標
WorkloadGroupで、メッシュの外にあるサーバーのグループの型を作り、WorkloadEntryでサーバーを1台ずつ登録し、ServiceEntryでメッシュ内のサービス名に結び付けます。最後に、そのサーバーが受け取る設定一式を、istioctl x workload entry configureで実際に作ってみて、セレクターが何を選ぶのかを数えるレポートを残します。
なぜ重要なのか
メッシュを導入しても、Kubernetesに移せないサーバーは残ります。これらを外に置いておくと、メッシュが提供するものがそこで途切れます。身元、暗号化、アクセスポリシー、そして何より、1枚のサービスマップです。メッシュの拡張は、そのサーバーをお客様ではなく、構成員として迎え入れる作業です。核心は身元です。Kubernetesの中では、Podがサービスアカウントで身元を受け取りますが、VMにはそういうものがありません。そのため、WorkloadGroupにどのサービスアカウントを使うかを書いておき、そのサーバーには、クラスターが発行したトークンとルート証明書を、あらかじめ入れてあげます。この3つが合って初めて、VMのプロキシがコントロールプレーンにつながって、自分の身元を証明できます。3つのオブジェクトの関係も混同しやすいのですが、グループの型がWorkloadGroup、サーバー1台がWorkloadEntry、呼び出すための名前がServiceEntryと考えれば整理できます。
ステップ
/root/ist-expansionとネームスペースexpansionを作成して、その中にServiceAccountbilling-saを作成してください。そして、このサービスアカウントを使うワークロードがメッシュで受け取ることになる身元の文字列を、/root/ist-expansion/identity.txtに1行で書いてください。トラストドメインはデフォルト値のcluster.localです。/root/ist-expansion/wg.yamlにWorkloadGrouplegacy-billingを書いて、expansionに適用してください。spec.metadata.labelsはapp: billing、spec.templateはserviceAccount: billing-sa、network: onprem、ports.http: 8080で、spec.probeはperiodSeconds: 5で、httpGetでポート8080の/healthzを見ます。/root/ist-expansion/wg-bad-probe.yamlにWorkloadGroupbad-probeを書いて、spec.probeにhttpGetとtcpSocketを両方入れてください。/root/ist-expansion/wg-no-template.yamlにはno-templateを書いて、spec.templateをまるごと抜いてください。どちらもサーバー側の試験適用だけを行って、拒否文を/root/ist-expansion/wg-reject.txtに順番に集めてください。/root/ist-expansion/we.yamlにWorkloadEntrybilling-1を書いて適用してください。メタデータのラベルはapp: billing、addressは10.20.30.41、networkはonprem、serviceAccountはbilling-sa、localityはdc1/rack2、ports.httpは8080です。そのあと、/root/ist-expansion/we-typo.yamlにbilling-typoを書いて、アドレスを10.20.30 .41のように空白を入れて適用し、istioctl analyze -n expansion -o jsonの出力を/root/ist-expansion/analyze-address.jsonに保存してください。ラベルはapp: billing-brokenにします。/root/ist-expansion/se.yamlにServiceEntrybilling-svcを書いて適用してください。hostsはbilling.expansion.internalの1つ、locationはMESH_INTERNAL、resolutionはSTATIC、ポートは番号8080で名前はhttp、プロトコルはHTTPで、workloadSelector.labelsはapp: billingです。- 3つのServiceEntryファイルを作成して、サーバー側の試験適用でルールを確認してください。
/root/ist-expansion/se-none-endpoints.yaml(resolution: NONEなのにendpointsがある)、/root/ist-expansion/se-roundrobin-two.yaml(resolution: DNS_ROUND_ROBINでendpointsが2つ)、/root/ist-expansion/se-roundrobin-one.yaml(resolution: DNS_ROUND_ROBINでendpointsが1つ)です。結果を/root/ist-expansion/resolution-rules.tsvに、<파일이름>\t<accepted|rejected>の形式で(プレースホルダーはファイル名です)上の順に書いて、拒否文は/root/ist-expansion/resolution-reject.txtに集めてください。3つのファイルとも、実際には適用しないでください。 - まず
istio-systemネームスペースを作成して、istioctl manifest generate --set profile=minimalのレンダリングからConfigMapistioだけを取り出して/root/ist-expansion/istio-cm.yamlに保存してから適用してください。そのあと、expansionにConfigMapistio-ca-root-certを作成してください。キー名はroot-cert.pemで、値はopensslで作成した自己署名のルート証明書です(/root/ist-expansion/root-cert.pem)。最後に、istioctl x workload entry configure -f /root/ist-expansion/wg.yaml -o /root/ist-expansion/vmcfg --clusterID lab-clusterを実行して、設定一式を作成してください。 /root/ist-expansion/we2.yamlに2台目のサーバーbilling-2を書いて適用してください。ラベルはapp: billing、アドレスは10.20.30.42、network: onprem、serviceAccount: billing-sa、locality: dc1/rack3、ports.httpは8080です。そのあと、/root/ist-expansion/se-match.shを作成して、expansionのServiceEntryのうち、workloadSelectorがあるものごとに、<ServiceEntry 이름>\t<잡힌 WorkloadEntry 수>\t<이름들 쉼표>の形式で(プレースホルダーはServiceEntryの名前と選ばれたWorkloadEntryの数と名前のカンマ区切りです)、名前順に標準出力にだけ出力するようにして、その出力を/root/ist-expansion/match-result.txtに保存してください。
参考
- 身元の形式は、
spiffe://<신뢰도메인>/ns/<네임스페이스>/sa/<서비스어카운트>です(プレースホルダーはトラストドメインとネームスペースとサービスアカウントです)。 kubectl apply --dry-run=serverは、作成せずに、APIサーバーに問い合わせだけを行います。istioctl x workload entry configureは、クラスターのConfigMap 2つとサービスアカウントを読みます。- よくある間違い: WorkloadEntryだけを作って、ServiceEntryを忘れること。呼び出すための名前がなければ、誰も呼び出せません。
- よくある間違い: ラベルをWorkloadEntryの
specに書くこと。セレクターが見るのはmetadata.labelsです。 - 参考: https://istio.io/v1.24/docs/reference/config/networking/workload-group/
- 参考: https://istio.io/v1.24/docs/reference/config/networking/workload-entry/
- 参考: https://istio.io/v1.24/docs/ops/deployment/vm-architecture/
メッシュがそのサーバーを何と呼ぶかを先に決める
/root/ist-expansionとネームスペースexpansionを作成して、その中にServiceAccount billing-saを作成してください。そして、このサービスアカウントを使うワークロードがメッシュで受け取ることになる身元の文字列を、/root/ist-expansion/identity.txtに1行で書いてください。トラストドメインはデフォルト値のcluster.localです。
メッシュの身元は、IPやホスト名ではなく、サービスアカウントから得られます。形式はspiffe://<신뢰도메인>/ns/<네임스페이스>/sa/<서비스어카운트>です(プレースホルダーはトラストドメインとネームスペースとサービスアカウントです)。メッシュの外のサーバーも、結局はこの名札を受け取ってはじめて、内側に入れます。
VM1台ではなく、VMのグループの型を作る
/root/ist-expansion/wg.yamlにWorkloadGroup legacy-billingを書いて、expansionに適用してください。spec.metadata.labelsはapp: billing、spec.templateはserviceAccount: billing-sa、network: onprem、ports.http: 8080で、spec.probeはperiodSeconds: 5で、httpGetでポート8080の/healthzを見ます。
WorkloadGroupは、PodのDeploymentに相当する場所です。個々のサーバーではなく、そのグループが共通で持つラベル・身元・ネットワーク・ポート・ヘルスチェックの方法を書きます。network値は、そのサーバーがどのネットワークにあるのかを指し、あとでプロキシがその値で経路を選びます。
スキーマが拒否する2つのケースを、自分で受けてみる
/root/ist-expansion/wg-bad-probe.yamlにWorkloadGroup bad-probeを書いて、spec.probeにhttpGetとtcpSocketを両方入れてください。/root/ist-expansion/wg-no-template.yamlにはno-templateを書いて、spec.templateをまるごと抜いてください。どちらもサーバー側の試験適用だけを行って、拒否文を/root/ist-expansion/wg-reject.txtに順番に集めてください。
probeは、検査方法のうち1つだけを選ぶようになっています。スキーマのoneOf制約です。templateは、なければグループのデフォルト値がわからないので、必須です。拒否文がどのフィールドを指しているかを、読んでみてください。
サーバー1台を実際に登録して、打ち間違いがどこで検出されるかを見る
/root/ist-expansion/we.yamlにWorkloadEntry billing-1を書いて適用してください。メタデータのラベルはapp: billing、addressは10.20.30.41、networkはonprem、serviceAccountはbilling-sa、localityはdc1/rack2、ports.httpは8080です。そのあと、/root/ist-expansion/we-typo.yamlにbilling-typoを書いて、アドレスを10.20.30 .41のように空白を入れて適用し、istioctl analyze -n expansion -o jsonの出力を/root/ist-expansion/analyze-address.jsonに保存してください。ラベルはapp: billing-brokenにします。
WorkloadEntryは、グループの中のサーバー1台です。アドレスの形式はCRDスキーマが検査しないので、変な値も作成されます。そうしたものを検出してくれるのは、アナライザーです。どのコードで出力されるかを、確認してみてください。
登録したサーバーを、メッシュのサービス名に結び付ける
/root/ist-expansion/se.yamlにServiceEntry billing-svcを書いて適用してください。hostsはbilling.expansion.internalの1つ、locationはMESH_INTERNAL、resolutionはSTATIC、ポートは番号8080で名前はhttp、プロトコルはHTTPで、workloadSelector.labelsはapp: billingです。
WorkloadEntryだけを作っても、呼び出すための名前がありません。ServiceEntryがメッシュ内のサービス名を作り、workloadSelectorでその名前の背後に立つワークロードを選びます。locationがMESH_INTERNALなら、メッシュの構成員として扱われて、mTLSとポリシーが適用される対象になります。
resolutionごとに、endpointのルールが違う
3つのServiceEntryファイルを作成して、サーバー側の試験適用でルールを確認してください。/root/ist-expansion/se-none-endpoints.yaml(resolution: NONEなのにendpointsがある)、/root/ist-expansion/se-roundrobin-two.yaml(resolution: DNS_ROUND_ROBINでendpointsが2つ)、/root/ist-expansion/se-roundrobin-one.yaml(resolution: DNS_ROUND_ROBINでendpointsが1つ)です。結果を/root/ist-expansion/resolution-rules.tsvに、<파일이름>\t<accepted|rejected>の形式で(プレースホルダーはファイル名です)上の順に書いて、拒否文は/root/ist-expansion/resolution-reject.txtに集めてください。3つのファイルとも、実際には適用しないでください。
resolutionは、宛先をどう見つけるかを決めます。NONEは元の宛先IPをそのまま使い、STATICは書かれたendpointを、DNSは名前を解決して使います。そのため、方式ごとにendpointを何個書けるかが違います。このルールは、istioctlではなく、CRDの検証ルールが強制します。
そのサーバーが受け取る設定一式を、実際に作ってみる
まずistio-systemネームスペースを作成して、istioctl manifest generate --set profile=minimalのレンダリングからConfigMap istioだけを取り出して/root/ist-expansion/istio-cm.yamlに保存してから適用してください。そのあと、expansionにConfigMap istio-ca-root-certを作成してください。キー名はroot-cert.pemで、値はopensslで作成した自己署名のルート証明書です(/root/ist-expansion/root-cert.pem)。最後に、istioctl x workload entry configure -f /root/ist-expansion/wg.yaml -o /root/ist-expansion/vmcfg --clusterID lab-clusterを実行して、設定一式を作成してください。
VM側のプロキシが必要とするものは3つです。メッシュ設定(どこにつなぐか)、ルート証明書(誰を信頼するか)、トークン(自分が誰なのか)です。前の2つはクラスターのConfigMapから得られ、トークンは、このコマンドがサービスアカウントで直接発行します。発行されたトークンは寿命が短いものですが、画面に出力しないでください。
セレクターが実際に何を選ぶのかを数えて、レポートとして残す
/root/ist-expansion/we2.yamlに2台目のサーバーbilling-2を書いて適用してください。ラベルはapp: billing、アドレスは10.20.30.42、network: onprem、serviceAccount: billing-sa、locality: dc1/rack3、ports.httpは8080です。そのあと、/root/ist-expansion/se-match.shを作成して、expansionのServiceEntryのうち、workloadSelectorがあるものごとに、<ServiceEntry 이름>\t<잡힌 WorkloadEntry 수>\t<이름들 쉼표>の形式で(プレースホルダーはServiceEntryの名前と選ばれたWorkloadEntryの数と名前のカンマ区切りです)、名前順に標準出力にだけ出力するようにして、その出力を/root/ist-expansion/match-result.txtに保存してください。
ラベルセレクターは、kubectl get workloadentry -l app=billingのように、そのまま問い合わせられます。セレクターが複数のラベルなら、カンマでつなげます。選ばれたものがなければ、0とハイフンを出力するようにしておくと、あとでラベルがずれた日にすぐ見えます。