Spring Cloud アプリケーションを Service Mesh (ASM) に接続することで、クラウドネイティブなサービスガバナンス機能を使用して、アプリケーションコードを変更することなく Spring Cloud サービスを管理できます。このトピックでは、ASM を使用して Spring Cloud サービスを管理する方法について説明します。
前提条件
Enterprise Edition または Ultimate Edition の ASM インスタンスが作成されていること。詳細については、「ASM インスタンスの作成」をご参照ください。
ACK マネージドクラスターが作成されていること。詳細については、「ACK マネージドクラスターの作成」をご参照ください。
クラスターが ASM インスタンスに追加されていること。詳細については、「ASM インスタンスへのクラスターの追加」をご参照ください。
イングレスゲートウェイがデプロイされていること。詳細については、「イングレスゲートウェイの作成」をご参照ください。
背景情報
Spring Cloud は、Spring Cloud Netflix、Spring Cloud Alibaba、Spring Cloud Consul など、さまざまな実装を持つ標準です。ASM では、Spring Cloud の実装における主な違いはサービスレジストリにあります。次の表は、これらの Spring Cloud 実装を使用して開発されたアプリケーションを ASM に移行できるかどうかを示しています。
Spring Cloud の実装 | サービスレジストリ | コード変更なしの移行がサポートされているかどうか |
Spring Cloud Alibaba | マイクロサービスエンジン (MSE) Nacos (Alibaba Cloud サービス) | はい |
Spring Cloud Alibaba | セルフマネージド Nacos | はい |
Spring Cloud Netflix | Eureka | サポートされています。ASM インスタンスのバージョンは 1.13.4.53 以降である必要があります。 |
Spring Cloud Consul | Consul | サポートされています。ASM インスタンスのバージョンは 1.13.4.53 以降である必要があります。 |
Spring Cloud Zookeeper | Zookeeper | サポートされています。ASM インスタンスのバージョンは 1.13.4.53 以降である必要があります。 |
デモの紹介
この例では、Nacos レジストリを使用した Spring Cloud を使用します。デモのサンプルコードは、GitHub の nacos-examples リポジトリからダウンロードできます。
Spring Cloud サービスには、コンシューマーサービスとプロバイダーサービスが含まれています。プロバイダーサービスには、V1 と V2 の 2 つのバージョンがあります。プロバイダーサービスの両方のバージョンが Nacos レジストリに登録されています。コンシューマーサービスは、Nacos レジストリから 2 つのバージョンのプロバイダーサービスのエンドポイントを取得し、負荷分散方式でエンドポイントにリクエストを送信します。コンシューマーサービスはポート 8080 を公開し、エコーインターフェイスを提供します。リクエストがプロバイダーサービスに転送されると、プロバイダーサービスは対応するレスポンスを返し、コンシューマーサービスはレスポンスを配信します。プロバイダーサービスの異なるバージョンは、異なるレスポンスを返します。
V1 のプロバイダーサービスは、エコーリクエストに対して次の情報で応答します。
Hello Nacos Discovery From v1xxx
V2 のプロバイダーサービスは、エコーリクエストに対して次の情報で応答します。
Hello Nacos Discovery From v2xxx
レスポンスの xxx
文字列は、対応するエコーリクエストの特定のパラメーターを示します。たとえば、/echo/world リクエストが V1 のプロバイダーサービスに送信されると、Hello Nacos Discovery From v1world
レスポンスが返されます。
コンシューマーサービスとプロバイダーサービスが ASM インスタンスにデプロイされていない場合、つまり、サービスポッドに対してサイドカープロキシインジェクションが有効になっていない場合は、サービスにアクセスできますが、Istio リソースを使用してサービスを管理することはできません。
手順 1:ASM コントロールプレーンで Spring Cloud のサポートを有効にする
方法 1:すべての Spring Cloud の実装とレジストリに適用可能
ASM インスタンスのバージョンは 1.13.4.32 以降である必要があります。
制限事項:
Kubernetes サービスは、デスティネーションサービスとして作成する必要があります。サービスポートとデスティネーションポートは、Server Load Balancer (SLB) インスタンスを介してアプリケーションがルーティングされるポートである必要があります。
1.23.6.32 以降の ASM インスタンスを使用する場合は、REGISTRY_ONLY を無効にする必要があります。
kubectl を使用して、コントロールプレーンのクラスターに接続します。詳細については、「コントロールプレーンで kubectl を使用して Istio リソースにアクセスする」をご参照ください。
ASM インスタンスに追加された ACK クラスタに Envoy フィルタを作成します。
次の内容で any-spring-cloud-support.yaml という名前のファイルを作成します。
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: labels: provider: "asm" asm-system: "true" name: any-spring-cloud-support namespace: istio-system spec: configPatches: - applyTo: HTTP_FILTER match: proxy: proxyVersion: "^1.*" context: SIDECAR_OUTBOUND listener: portNumber: 8070 filterChain: filter: name: "envoy.filters.network.http_connection_manager" subFilter: name: "envoy.filters.http.router" patch: operation: INSERT_BEFORE value: # reverse_dns フィルタの仕様 name: com.aliyun.reverse_dns typed_config: "@type": "type.googleapis.com/udpa.type.v1.TypedStruct" type_url: type.googleapis.com/envoy.config.filter.reverse_dns.v3alpha.CommonConfig value: pod_cidrs: - "10.0.128.0/18"
ビジネス要件に基づいて、ファイル内のパラメーター設定を変更します。いくつかのパラメーターは次のように説明されています。
portNumber
: Spring Cloud サービスのポート番号を指定します。複数のポートがある場合は、このパラメーターを削除できます。ポートを統合できる場合は、複数の Envoy フィルタを作成し、各 Envoy フィルタでポート番号を設定できます。pod_cidrs
: ACK または ACK Serverless クラスタのポッド CIDR ブロックを指定します。Container Service for Kubernetes (ACK) コンソール にログインし、[クラスター] ページに移動して、目的のクラスターをクリックします。表示されるクラスター詳細ページで、[クラスターリソース] タブをクリックします。次に、VPC セクションのリンクをクリックして、[VPC] の vSwitch の CIDR ブロックを表示します。
次のコマンドを実行して、サービスに対して
com.aliyun.reverse_dns
フィルタを有効にします。kubectl apply -f any-spring-cloud-support.yaml
方法 2:Nacos レジストリのみに適用可能
kubectl を使用して、コントロールプレーンのクラスターに接続します。詳細については、「コントロールプレーンで kubectl を使用して Istio リソースにアクセスする」をご参照ください。
サービスエントリを作成します。
次の内容を含む external-nacos-svc.yaml ファイルを作成します。
kind: ServiceEntry metadata: name: external-nacos-svc spec: hosts: - "NACOS_SERVER_HOST" ## この変数を Nacos サーバーホストのエンドポイントに置き換えます。例: mse-xxx-p.nacos-ans.mse.aliyuncs.com。 location: MESH_EXTERNAL ports: - number: 8848 name: http resolution: DNS
上記の YAML ファイルでは、ポート
8848
は、Nacos で使用されるデフォルト ポートです。セルフマネージド Nacos サーバーと別のポートを使用する場合は、number
パラメーターを使用するポート番号に設定します。次のコマンドを実行して、サービスエントリを作成します。
kubectl apply -f external-nacos-svc.yaml
Envoy フィルタを作成します。
次の内容を含む external-envoyfilter.yaml ファイルを作成します。
apiVersion: networking.istio.io/v1alpha3 kind: EnvoyFilter metadata: labels: provider: "asm" asm-system: "true" name: nacos-subscribe-lua namespace: istio-system spec: configPatches: # 最初のパッチは、リスナー/ HTTP 接続マネージャーに lua フィルタを追加します。 - applyTo: HTTP_FILTER match: proxy: proxyVersion: "^1.*" context: SIDECAR_OUTBOUND listener: portNumber: 8848 filterChain: filter: name: "envoy.filters.network.http_connection_manager" subFilter: name: "envoy.filters.http.router" patch: operation: INSERT_BEFORE value: # lua フィルタの仕様 name: envoy.lua typed_config: "@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua" inlineCode: | -- 著作権: ASM (Alibaba Cloud ServiceMesh) function envoy_on_request(request_handle) local request_headers = request_handle:headers() -- /nacos/v1/ns/instance/list?healthyOnly=false&namespaceId=public&clientIP=10.122.63.81&serviceName=DEFAULT_GROUP%40%40service-provider&udpPort=53174&encoding=UTF-8 local path = request_headers:get(":path") if string.match(path,"^/nacos/v1/ns/instance/list") then local servicename = string.gsub(path,".*&serviceName.*40([%w.\\_\\-]+)&.*","%1") request_handle:streamInfo():dynamicMetadata():set("context", "request.path", path) request_handle:streamInfo():dynamicMetadata():set("context", "request.servicename", servicename) request_handle:logInfo("serviceName のサブスクライブ: " .. servicename) else request_handle:streamInfo():dynamicMetadata():set("context", "request.path", "") end end function envoy_on_response(response_handle) local request_path = response_handle:streamInfo():dynamicMetadata():get("context")["request.path"] if request_path == "" then return end local servicename = response_handle:streamInfo():dynamicMetadata():get("context")["request.servicename"] response_handle:logInfo("レスポンス IP を serviceName に変更しました:" .. servicename) local bodyObject = response_handle:body(true) local body= bodyObject:getBytes(0,bodyObject:length()) body = string.gsub(body,"%s+","") body = string.gsub(body,"(ip\":\")(%d+.%d+.%d+.%d+)","%1"..servicename) response_handle:body():setBytes(body) end
次のコマンドを実行して、Envoy フィルタを作成します。
kubectl apply -f external-envoyfilter.yaml
手順 2:ACK クラスタに Spring Cloud サービスをデプロイする
登録プロセスをインターセプトするために、デプロイメントを作成する前に Envoy フィルタが作成されていることを確認してください。Envoy フィルタを作成する前に特定のデプロイメントが作成されている場合は、デプロイメントのローリングアップデートを有効にする必要があります。
Spring Cloud サービスの場合、Kubernetes サービスリソースを作成し、クラスタ IP アドレスを提供する必要があります。
kubectl を使用して、データプレーンのクラスターに接続します。詳細については、「クラスターの kubeconfig ファイルを取得し、kubectl を使用してクラスターに接続する」をご参照ください。
次のコマンドを実行して、Spring Cloud サービスをデプロイします。
export NACOS_ADDRESS=xxxx # xxxx を MSE Nacos レジストリまたはセルフマネージド Nacos レジストリのエンドポイントに置き換えます。仮想プライベートクラウド (VPC) のエンドポイントを使用することをお勧めします。 wget https://alibabacloudservicemesh.oss-cn-beijing.aliyuncs.com/asm-labs/springcloud/demo.yaml -O demo.yaml sed -e "s/NACOS_SERVER_CLUSTERIP/$NACOS_ADDRESS/g" demo.yaml |kubectl apply -f -
次のコマンドを実行して、Spring Cloud サービスを確認します。
kubectl get pods
予期される出力:
consumer-bdd464654-jn8q7 2/2 Running 0 25h provider-v1-66bc67fb6d-46pgl 2/2 Running 0 25h provider-v2-76568c45f6-85z87 2/2 Running 0 25h
手順 3:Istio ゲートウェイと仮想サービスを作成する
Istio ゲートウェイを作成します。
次の内容を含む test-gateway.yaml ファイルを作成します。
apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: test-gateway spec: selector: istio: ingressgateway # istio デフォルトコントローラーを使用 servers: - port: number: 80 name: http protocol: HTTP hosts: - "*"
kubeconfig ファイルの情報に基づいて kubectl を使用して ASM インスタンスに接続し、次のコマンドを実行して Istio ゲートウェイを作成します。
kubectl apply -f test-gateway.yaml
仮想サービスを作成します。
次の内容を含む consumer.yaml ファイルを作成します。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: consumer spec: hosts: - "*" gateways: - test-gateway http: - match: - uri: prefix: / route: - destination: host: consumer.default.svc.cluster.local port: number: 8080
次のコマンドを実行して、仮想サービスを作成します。
kubectl apply -f consumer.yaml
手順 4:ASM が Spring Cloud サービスを管理できるかどうかを確認する
イングレスゲートウェイの IP アドレスをクエリします。
ASM コンソール にログインします。左側のナビゲーションウィンドウで、 を選択します。
[メッシュ管理] ページで、ASM インスタンスの名前をクリックします。左側のナビゲーションウィンドウで、 を選択します。
[イングレスゲートウェイ] ページで、イングレスゲートウェイの [サービスアドレス] を表示します。
次のコマンドを実行して、イングレスゲートウェイから Spring Cloud コンシューマーサービスへのリクエストを開始します。
curl <イングレスゲートウェイの IP アドレス>/echo/world
予期される出力:
Hello Nacos Discovery From v1world Hello Nacos Discovery From v2world Hello Nacos Discovery From v1world Hello Nacos Discovery From v2world
出力は、トラフィックがデフォルトでポーリングモードでプロバイダーサービスの V1 と V2 にルーティングされていることを示しています。
デスティネーションルールと仮想サービスを作成します。
次の内容を含む service-provider.yaml ファイルを作成します。
--- apiVersion: networking.istio.io/v1alpha3 kind: DestinationRule metadata: name: service-provider spec: host: service-provider subsets: - name: v1 labels: label: v1 - name: v2 labels: label: v2
次のコマンドを実行して、デスティネーションルールを作成します。
kubectl apply -f service-provider.yaml
次の内容を含む service-provider1.yaml ファイルを作成します。
作成される仮想サービスは、/echo/hello リクエストが V1 のプロバイダーサービスにルーティングされ、他のリクエストが V2 のプロバイダーサービスにルーティングされることを定義しています。
apiVersion: networking.istio.io/v1alpha3 kind: VirtualService metadata: name: service-provider spec: hosts: - service-provider http: - name: "hello-v1" match: - uri: prefix: "/echo/hello" route: - destination: host: service-provider subset: v1 - name: "default" route: - destination: host: service-provider subset: v2
次のコマンドを実行して、仮想サービスを作成します。
kubectl apply -f service-provider1.yaml
次のコマンドを実行して、Spring Cloud コンシューマーサービスへのリクエストを開始します。
curl <イングレスゲートウェイの IP アドレス>/echo/hello
予期される出力:
Hello Nacos Discovery From v1hello Hello Nacos Discovery From v1hello
出力は、
/echo/hello
リクエストが V1 のプロバイダーサービスにルーティングされ、他のリクエストが V2 のプロバイダーサービスにルーティングされていることを示しています。これは、Spring Cloud トラフィックが Istio によって引き継がれ、Istio によって提供されるカスタムリソース定義 (CRD) を使用してルーティングルールを設定できることを示しています。この場合、ASM は Spring Cloud サービスを管理できます。
FAQ
デプロイした Spring Cloud サービスが有効にならない場合はどうすればよいですか?
Nacos のポートまたは IP アドレスに対してトラフィックブロックが有効になっているかどうかを確認します。
逆引き DNS ルックアップを使用する場合は、ポッドの IP アドレスをブロックする必要があります。
Lua スクリプトを使用する場合は、Nacos サーバーの IP アドレスとクラスタ IP アドレスをブロックする必要があります。
登録プロセスをインターセプトするために、デプロイメントを作成する前に Envoy フィルタが作成されていることを確認してください。Envoy フィルタを作成する前に特定のデプロイメントが作成されている場合は、デプロイメントのローリングアップデートを有効にする必要があります。
Kubernetes サービスリソースを作成し、Spring Cloud サービスにクラスタ IP アドレスを提供したかどうかを確認します。
ASM コントロールプレーンで Spring Cloud のサポートを有効にする方法を確認します。
サービスのサイドカーバージョンを確認します。サイドカーイメージのバージョンが 1.13.4.32 より前の場合、ASM インスタンスのコントロールプレーンのみを更新し、データプレーンを更新していない可能性があります。この場合、サービスのデプロイメントのローリングアップデートを有効にします。