0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Envoy GatewayにおけるMulti-cluster Service APIsの対応状況

Posted at

Envoy Gatewayは、Multi-cluster Service APIsのServiceImport に対応しています。本記事では、Envoy GatewayがServiceImportをどのように扱っているか解説します。

1. ServiceImportの役割

ServiceImportはMulti-cluster Service APIsで定義されたカスタムリソースで、Kubernetesのマルチクラスタ環境において、他のクラスタからエクスポートされたサービスを現在のクラスタ内でインポートし、利用可能にするためのリソースです。

ServiceImportの処理フロー

Envoy Gatewayのコントローラーは、以下の手順でServiceImportを処理します:

  1. リソースのウォッチと取得:

    • コントローラーはServiceImportリソースの作成、更新、削除イベントを監視します。
    • ServiceImportが作成または更新されると、その詳細を取得し、関連するエンドポイント情報を収集します。
  2. EndpointSliceからのIP取得:

    • ServiceImportに関連付けられたEndpointSliceリソースをリストし、各エンドポイントのIPアドレスとポート情報を取得します。
    • これにより、EndpointSliceに列挙されているIPがEnvoyの設定に反映されます。
  3. EnvoyへのIP登録:

    • 取得したIPアドレスを基に、Envoyの設定に反映させ、トラフィックルーティングを実現します。

3. Envoy GatewayにおけるServiceImportからのIP登録の流れ

Envoy Gatewayは、ServiceImportリソースを通じてインポートされたサービスのエンドポイントIPを管理し、これを利用してトラフィックを適切にルーティングします。具体的な流れは以下の通りです:

  1. ServiceImportおよび関連リソースの取得:

    • Envoy Gatewayコントローラーは、ServiceImportリソースを監視し、必要に応じて取得します。
    • 取得されたServiceImportに関連するEndpointSliceをリストし、各エンドポイントのIPアドレスを収集します。
  2. EndpointSliceからのエンドポイント情報の抽出:

    • EndpointSliceには、実際のエンドポイント(Podや外部サービス)のIPアドレスとポート情報が含まれています。
    • Envoy GatewayはこれらのIPアドレスを基に、Envoyの設定を更新します。

コードスニペットの例

以下は、Envoy GatewayのコントローラーがServiceImportおよびEndpointSliceからIPアドレスを取得し、Envoyに登録する際のコード部分です:

func (r *gatewayAPIReconciler) processBackendRefs(ctx context.Context, gwcResource *resource.Resources, resourceMappings *resourceMappings) {
    for backendRef := range resourceMappings.allAssociatedBackendRefs {
        backendRefKind := gatewayapi.KindDerefOr(backendRef.Kind, resource.KindService)
        r.log.Info("processing Backend", "kind", backendRefKind, "namespace", string(*backendRef.Namespace), "name", string(backendRef.Name))

        var endpointSliceLabelKey string
        switch backendRefKind {
        case resource.KindService:
            // Serviceの場合の処理
            service := new(corev1.Service)
            err := r.client.Get(ctx, types.NamespacedName{Namespace: string(*backendRef.Namespace), Name: string(backendRef.Name)}, service)
            if err != nil {
                r.log.Error(err, "failed to get Service", "namespace", string(*backendRef.Namespace), "name", string(backendRef.Name))
            } else {
                resourceMappings.allAssociatedNamespaces.Insert(service.Namespace)
                gwcResource.Services = append(gwcResource.Services, service)
                r.log.Info("added Service to resource tree", "namespace", string(*backendRef.Namespace), "name", string(backendRef.Name))
            }
            endpointSliceLabelKey = discoveryv1.LabelServiceName

        case resource.KindServiceImport:
            // ServiceImportの場合の処理
            serviceImport := new(mcsapiv1a1.ServiceImport)
            err := r.client.Get(ctx, types.NamespacedName{Namespace: string(*backendRef.Namespace), Name: string(backendRef.Name)}, serviceImport)
            if err != nil {
                r.log.Error(err, "failed to get ServiceImport", "namespace", string(*backendRef.Namespace), "name", string(backendRef.Name))
            } else {
                resourceMappings.allAssociatedNamespaces.Insert(serviceImport.Namespace)
                key := utils.NamespacedName(serviceImport).String()
                if !resourceMappings.allAssociatedServiceImports.Has(key) {
                    resourceMappings.allAssociatedServiceImports.Insert(key)
                    gwcResource.ServiceImports = append(gwcResource.ServiceImports, serviceImport)
                    r.log.Info("added ServiceImport to resource tree", "namespace", string(*backendRef.Namespace), "name", string(*backendRef.Name))
                }
            }
            endpointSliceLabelKey = mcsapiv1a1.LabelServiceName

        case egv1a1.KindBackend:
            // Backendの場合の処理
            // 省略
        }

        // EndpointSliceの取得
        if endpointSliceLabelKey != "" {
            endpointSliceList := new(discoveryv1.EndpointSliceList)
            opts := []client.ListOption{
                client.MatchingLabels(map[string]string{
                    endpointSliceLabelKey: string(backendRef.Name),
                }),
                client.InNamespace(*backendRef.Namespace),
            }
            if err := r.client.List(ctx, endpointSliceList, opts...); err != nil {
                r.log.Error(err, "failed to get EndpointSlices", "namespace", string(*backendRef.Namespace), backendRefKind, string(backendRef.Name))
            } else {
                for _, endpointSlice := range endpointSliceList.Items {
                    key := utils.NamespacedName(&endpointSlice).String()
                    if !resourceMappings.allAssociatedEndpointSlices.Has(key) {
                        resourceMappings.allAssociatedEndpointSlices.Insert(key)
                        r.log.Info("added EndpointSlice to resource tree", "namespace", endpointSlice.Namespace, "name", endpointSlice.Name)
                        gwcResource.EndpointSlices = append(gwcResource.EndpointSlices, &endpointSlice)
                    }
                }
            }
        }
    }
}

このコードでは、ServiceImportによって参照されるIPアドレスをEndpointSliceから取得し、Envoyの設定に反映させています。

4. Topology Aware Routingの課題

EnvoyがServiceを経由せずにEndpointSliceのIPをEnvoyが直接参照する設計には、以下のような課題が存在します:

1. kube-proxyによるTopology Aware Routingとの整合性

Kubernetesのkube-proxyは、クラスター内のトラフィックを効率的にルーティングするためにTopology Aware Routingを実装しています。これは、トラフィックをできるだけ地理的に近いエンドポイントに送ることで、レイテンシの低減や帯域幅の節約を図るものです。しかし、Envoy GatewayがEndpointSliceのIPを直接参照する場合、kube-proxyが提供するTopology Aware Routingの機能、又は類似する機能をEnvoyが独自に再実装してほしくなります。

2. 現在の対応状況

このTopology Aware Routingの類似課題に対する対応は、現在Envoy GatewayのGitHubリポジトリで進行中です。具体的には、以下のIssueで議論および実装が行われています:

6. まとめ

Envoy Gatewayは、Multi-cluster Service APIsのServiceImportおよびEndpointSliceを活用してトラフィックルーティングを実現できます。しかし、Serviceを経由せずにEndpointSliceのIPを直接利用する設計には、kube-proxyが既に提供するTopology Aware Routingの機能の利用に制限がかかる可能性があります。

現在、この課題に対する対応はGitHubのIssue #1909で進行中ですが、まだ未実装の段階です。今後のアップデートにより、Envoy Gatewayが地域やゾーンに基づいた効率的なトラフィックルーティングを実現するための機能が強化されることが期待されています。

参考リンク:

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?