次の方法で共有


Ocelot を使用して API ゲートウェイを実装する

ヒント

このコンテンツは、.NET Docs で入手できる、またはオフラインで読み取ることができる無料のダウンロード可能な PDF として入手できる、コンテナー化された .NET アプリケーションの電子ブックである .NET マイクロサービス アーキテクチャからの抜粋です。

コンテナー化された .NET アプリケーションの .NET マイクロサービス アーキテクチャの電子ブックの表紙サムネイル。

重要

参照マイクロサービス アプリケーション eShopOnContainers は現在、 Envoy によって提供された機能を使用して、以前に参照された Ocelot ではなく API ゲートウェイを実装しています。 eShopOnContainers に実装された新しい gRPC サービス間通信で必要とされる、Envoy の WebSocket プロトコルの組み込みサポートにより、この設計を選択しました。 ただし、Ocelot は、運用グレードのシナリオに適したシンプルで、能力があり、軽量の API Gateway と見なすことができるように、ガイドのこのセクションを保持しています。 また、最新の Ocelot バージョンには、その json スキーマに重大な変更が含まれています。 Ocelot < v16.0.0 を使用するか、ReRoute ではなくキー ルートを使用することを検討してください。

API ゲートウェイの設計と設計

次のアーキテクチャ図は、eShopOnContainers の Ocelot で API ゲートウェイがどのように実装されたかを示しています。

eShopOnContainers アーキテクチャを示す図。

図 6-28 API ゲートウェイを使用した eShopOnContainers アーキテクチャ

この図は、"Docker for Windows" または "Docker for Mac" を使用して、アプリケーション全体を単一の Docker ホストまたは開発用 PC にデプロイする方法を示しています。 ただし、オーケストレーターへのデプロイも同様ですが、図内のコンテナーはオーケストレーターでスケールアウトできます。

さらに、データベース、キャッシュ、メッセージ ブローカーなどのインフラストラクチャ資産をオーケストレーターからオフロードし、Azure SQL Database、Azure Cosmos DB、Azure Redis、Azure Service Bus、オンプレミスの任意の HA クラスタリング ソリューションなどのインフラストラクチャの高可用性システムにデプロイする必要があります。

図でもわかるように、複数の API ゲートウェイを使用すると、マイクロサービスと独自の関連 API ゲートウェイを開発およびデプロイするときに、複数の開発チームを自律的にすることができます (この場合、マーケティング機能とショッピング機能)。

複数の開発チームによって単一のポイントが更新されることを意味する単一のモノリシック API ゲートウェイがある場合は、すべてのマイクロサービスとアプリケーションの 1 つの部分が結合される可能性があります。

設計をさらに進める中で、選択したアーキテクチャに応じて、きめ細かい API ゲートウェイを 1 つのビジネス マイクロサービスに制限することもできます。 ビジネスまたはドメインによって決まる API ゲートウェイの境界を持つことは、より良い設計を得るのに役立ちます。

たとえば、細かい API Gateway の概念は UI コンポジション サービスに似ているため、マイクロサービスに基づくより高度な複合 UI アプリケーションでは、API Gateway レベルの細かい粒度が特に役立ちます。

マイクロ サービスに基づく複合 UI の作成に関する前のセクションで詳しく説明しました。

重要なポイントとして、多くの中規模および大規模なアプリケーションでは、通常、カスタムビルドの API Gateway 製品を使用することをお勧めしますが、その API Gateway が自律マイクロサービスを作成する複数の開発チームに対して複数の独立した構成領域を許可しない限り、単一のモノリシック アグリゲーターや一意の中央カスタム API ゲートウェイとして使用することはできません。

API ゲートウェイ経由で再ルーティングするマイクロサービス/コンテナーのサンプル

たとえば、eShopOnContainers には、次の図に示すように、API ゲートウェイを介して発行する必要がある内部マイクロサービスの種類が約 6 種類あります。

サブフォルダーを示す Services フォルダーのスクリーンショット。

図 6-29 Visual Studio の eShopOnContainers ソリューションのマイクロサービス フォルダー

ID サービスについては、設計上、システム内の唯一の横断的な懸念事項であるため、API ゲートウェイ ルーティングから除外されますが、Ocelot では再ルーティング リストの一部として含めることもできます。

コードからわかるように、これらのサービスはすべて現在、コア Web API サービス ASP.NET として実装されています。 Catalog マイクロサービス コードのようなマイクロサービスの 1 つに焦点を当ててみましょう。

Catalog.API プロジェクトの内容を示すソリューション エクスプローラーのスクリーンショット。

図 6-30 サンプル Web API マイクロサービス (カタログ マイクロサービス)

Catalog マイクロサービスは、次のコードのように、いくつかのコントローラーとメソッドを備えた一般的な ASP.NET Core Web API プロジェクトであることがわかります。

[HttpGet]
[Route("items/{id:int}")]
[ProducesResponseType((int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)]
[ProducesResponseType(typeof(CatalogItem),(int)HttpStatusCode.OK)]
public async Task<IActionResult> GetItemById(int id)
{
    if (id <= 0)
    {
        return BadRequest();
    }
    var item = await _catalogContext.CatalogItems.
                                          SingleOrDefaultAsync(ci => ci.Id == id);
    //…

    if (item != null)
    {
        return Ok(item);
    }
    return NotFound();
}

HTTP 要求は、マイクロサービス データベースと追加の必要なアクションにアクセスする、その種の C# コードを実行することになります。

マイクロサービス URL に関して、コンテナーがローカル開発 PC (ローカル Docker ホスト) にデプロイされている場合、各マイクロサービスのコンテナーには、次の dockerfile のように、常に内部ポート (通常はポート 80) が dockerfile に指定されています。

FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80

コードに示されているポート 80 は Docker ホスト内の内部であるため、クライアント アプリでは到達できません。

クライアント アプリは、 docker-composeを使用して展開するときに発行された外部ポート (存在する場合) にのみアクセスできます。

運用環境にデプロイするときに、これらの外部ポートを発行しないでください。 この特定の理由から、クライアント アプリとマイクロサービス間の直接通信を回避するために、API ゲートウェイを使用する理由です。

ただし、開発中は、マイクロサービス/コンテナーに直接アクセスし、Swagger 経由で実行する必要があります。 そのため、eShopOnContainers では、外部ポートが API ゲートウェイまたはクライアント アプリで使用されない場合でも、外部ポートは引き続き指定されます。

Catalog マイクロサービスの docker-compose.override.yml ファイルの例を次に示します。

catalog-api:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - ASPNETCORE_URLS=http://0.0.0.0:80
    - ConnectionString=YOUR_VALUE
    - ... Other Environment Variables
  ports:
    - "5101:80"   # Important: In a production environment you should remove the external port (5101) kept here for microservice debugging purposes.
                  # The API Gateway redirects and access through the internal port (80).

docker-compose.override.yml構成では、カタログ コンテナーの内部ポートがポート 80 ですが、外部アクセス用のポートが 5101 である方法を確認できます。 ただし、このポートは、API ゲートウェイを使用する場合はアプリケーションで使用しないでください。これは、Catalog マイクロサービスのみをデバッグ、実行、およびテストする場合のみです。

通常、Docker-compose を使用して運用環境にデプロイすることはありません。マイクロサービスに適した運用環境は、Kubernetes や Service Fabric などのオーケストレーターであるためです。 これらの環境にデプロイする場合は、マイクロサービスの外部ポートを直接発行しない別の構成ファイルを使用しますが、API ゲートウェイのリバース プロキシは常に使用します。

ローカル Docker ホストでカタログ マイクロサービスを実行します。 Visual Studio から完全な eShopOnContainers ソリューションを実行するか (docker-compose ファイル内のすべてのサービスを実行します)、CMD または PowerShell で次の docker-compose コマンドを使用してカタログ マイクロサービスを開始するか、 docker-compose.ymldocker-compose.override.yml が配置されているフォルダーに配置します。

docker-compose run --service-ports catalog-api

このコマンドは、catalog-api サービス コンテナーと、docker-compose.ymlで指定されている依存関係のみを実行します。 この場合は、SQL Server コンテナーと RabbitMQ コンテナーです。

次に、Catalog マイクロサービスに直接アクセスし、Swagger UI を介してその "外部" ポートを介して直接アクセスする方法を確認できます。この場合は、次の http://host.docker.internal:5101/swagger

Catalog.API REST API を示す Swagger UI のスクリーンショット。

図 6-31 Swagger UI を使用したカタログ マイクロサービスのテスト

この時点で、Visual Studio の C# コードにブレークポイントを設定し、Swagger UI で公開されているメソッドを使用してマイクロサービスをテストし、最後に docker-compose down コマンドを使用してすべてをクリーンアップすることができます。

ただし、マイクロサービスへの直接アクセス通信 (この場合は外部ポート 5101 を使用) は、アプリケーションで避けたいものです。 また、API ゲートウェイの間接参照の追加レベル (この場合は Ocelot) を設定することで、これを回避できます。 そうすれば、クライアント アプリはマイクロサービスに直接アクセスしません。

Ocelot を使用した API ゲートウェイの実装

Ocelot は基本的に、特定の順序で適用できるミドルウェアのセットです。

Ocelot は、ASP.NET Core のみを使用するように設計されています。 パッケージの最新バージョンは .NET 6 を対象とする 18.0 であるため、.NET Framework アプリケーションには適していません。

Ocelot とその依存関係は、Visual Studio から Ocelot の NuGet パッケージを使用して、ASP.NET Core プロジェクトにインストールします。

Install-Package Ocelot

eShopOnContainers では、API Gateway の実装は単純な ASP.NET Core WebHost プロジェクトであり、Ocelot のミドルウェアは、次の図に示すように、すべての API Gateway 機能を処理します。

Ocelot API ゲートウェイ プロジェクトを示すソリューション エクスプローラーのスクリーンショット。

図 6-32 eShopOnContainers の OcelotApiGw 基本プロジェクト

この ASP.NET Core WebHost プロジェクトは、 Program.csStartup.csの 2 つの単純なファイルで構築されています。

Program.csは、一般的な ASP.NET Core BuildWebHost を作成して構成するだけで済むだけです。

namespace OcelotApiGw
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args)
        {
            var builder = WebHost.CreateDefaultBuilder(args);

            builder.ConfigureServices(s => s.AddSingleton(builder))
                    .ConfigureAppConfiguration(
                          ic => ic.AddJsonFile(Path.Combine("configuration",
                                                            "configuration.json")))
                    .UseStartup<Startup>();
            var host = builder.Build();
            return host;
        }
    }
}

Ocelot の重要なポイントは、configuration.json メソッドを使用してビルダーに提供する必要があるAddJsonFile() ファイルです。 この configuration.json では、すべての API Gateway ReRoute を指定します。つまり、特定のポートを持つ外部エンドポイントと、関連付けられた内部エンドポイント (通常は異なるポートを使用) です。

{
    "ReRoutes": [],
    "GlobalConfiguration": {}
}

構成には 2 つのセクションがあります。 ReRoute と GlobalConfiguration の配列。 ReRoute は、アップストリーム要求の処理方法を Ocelot に指示するオブジェクトです。 グローバル構成では、ReRoute 固有の設定をオーバーライドできます。 多くの ReRoute 固有の設定を管理したくない場合に便利です。

eShopOnContainers の API ゲートウェイのいずれかからの ReRoute 構成ファイル の簡略化された例を次に示します。

{
  "ReRoutes": [
    {
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "catalog-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/c/{everything}",
      "UpstreamHttpMethod": [ "POST", "PUT", "GET" ]
    },
    {
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "basket-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/b/{everything}",
      "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "IdentityApiKey",
        "AllowedScopes": []
      }
    }

  ],
    "GlobalConfiguration": {
      "RequestIdKey": "OcRequestId",
      "AdministrationPath": "/administration"
    }
  }

Ocelot API Gateway の主な機能は、受信 HTTP 要求を受け取り、現在は別の HTTP 要求としてダウンストリーム サービスに転送することです。 Ocelot は、ある要求を別の要求に ReRoute としてルーティングすることを表します。

たとえば、上記の configuration.json の ReRoute の 1 つである Basket マイクロサービスの構成に注目してみましょう。

{
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "basket-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/b/{everything}",
      "UpstreamHttpMethod": [ "POST", "PUT", "GET" ],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "IdentityApiKey",
        "AllowedScopes": []
      }
}

DownstreamPathTemplate、Scheme、および DownstreamHostAndPorts は、この要求の転送先となる内部マイクロサービス URL を作成します。

ポートは、サービスによって使用される内部ポートです。 コンテナーを使用する場合、その dockerfile で指定されたポート。

Hostは、使用しているサービス名解決に依存するサービス名です。 docker-compose を使用する場合、サービス名は Docker ホストによって提供されます。Docker ホストは、docker-compose ファイルで提供されるサービス名を使用します。 Kubernetes や Service Fabric などのオーケストレーターを使用している場合、その名前は各オーケストレーターによって提供される DNS または名前解決によって解決される必要があります。

DownstreamHostAndPorts は、要求の転送先となるダウンストリーム サービスのホストとポートを含む配列です。 通常、この構成には 1 つのエントリだけが含まれますが、ダウンストリーム サービスへの要求の負荷分散が必要な場合があり、Ocelot では複数のエントリを追加してからロード バランサーを選択できます。 ただし、Azure と任意のオーケストレーターを使用する場合は、クラウドとオーケストレーターのインフラストラクチャとの負荷分散を行う方が良い考えかもしれません。

UpstreamPathTemplate は、Ocelot がクライアントからの特定の要求に使用する DownstreamPathTemplate を識別するために使用する URL です。 最後に、UpstreamHttpMethod が使用されるため、Ocelot は同じ URL に対する異なる要求 (GET、POST、PUT) を区別できます。

この時点で、1 つまたは 複数のマージされた configuration.json ファイル を使用して 1 つの Ocelot API Gateway (ASP.NET Core WebHost) を作成することも、 構成を Consul KV ストアに格納することもできます。

ただし、アーキテクチャと設計のセクションで紹介したように、自律マイクロサービスを本当に使用する場合は、その単一のモノリシック API ゲートウェイを複数の API ゲートウェイや BFF (フロントエンド用バックエンド) に分割することをお勧めします。 そのために、Docker コンテナーでそのアプローチを実装する方法を見てみましょう。

1 つの Docker コンテナー イメージを使用して複数の異なる API ゲートウェイ/BFF コンテナーの種類を実行する

eShopOnContainers では、Ocelot API Gateway で 1 つの Docker コンテナー イメージを使用していますが、その後、実行時に、異なる configuration.json ファイルを提供することで、API-Gateway/BFF の種類ごとに異なるサービス/コンテナーを作成し、Docker ボリュームを使用してサービスごとに異なる PC フォルダーにアクセスします。

すべての API ゲートウェイの単一の Ocelot ゲートウェイ Docker イメージの図。

図 6-33 複数の API ゲートウェイの種類で 1 つの Ocelot Docker イメージを再利用する

eShopOnContainers では、"Generic Ocelot API Gateway Docker Image" は、"OcelotApiGw" という名前のプロジェクトと、docker-compose.yml ファイルで指定されたイメージ名 "eshop/ocelotapigw" を使用して作成されます。 次に、Docker にデプロイするときに、同じ Docker イメージから作成された 4 つの API-Gateway コンテナーが存在します。次に示すように、docker-compose.yml ファイルから抽出します。

  mobileshoppingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

  mobilemarketingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

  webshoppingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

  webmarketingapigw:
    image: eshop/ocelotapigw:${TAG:-latest}
    build:
      context: .
      dockerfile: src/ApiGateways/ApiGw-Base/Dockerfile

さらに、次のdocker-compose.override.yml ファイルでわかるように、これらの API Gateway コンテナーの唯一の違いは Ocelot 構成ファイルです。これはサービス コンテナーごとに異なり、実行時に Docker ボリュームを介して指定されます。

mobileshoppingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5200:80"
  volumes:
    - ./src/ApiGateways/Mobile.Bff.Shopping/apigw:/app/configuration

mobilemarketingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5201:80"
  volumes:
    - ./src/ApiGateways/Mobile.Bff.Marketing/apigw:/app/configuration

webshoppingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5202:80"
  volumes:
    - ./src/ApiGateways/Web.Bff.Shopping/apigw:/app/configuration

webmarketingapigw:
  environment:
    - ASPNETCORE_ENVIRONMENT=Development
    - IdentityUrl=http://identity-api
  ports:
    - "5203:80"
  volumes:
    - ./src/ApiGateways/Web.Bff.Marketing/apigw:/app/configuration

前のコードと以下の Visual Studio Explorer に示すように、4 つの API ゲートウェイは同じ Docker イメージに基づいているため、各特定のビジネス/BFF API ゲートウェイを定義するために必要な唯一のファイルは configuration.json ファイルにすぎません。

configuration.json ファイルを含むすべての API ゲートウェイを示すスクリーンショット。

図 6-34 Ocelot で各 API ゲートウェイ/BFF を定義するために必要な唯一のファイルは、構成ファイルです

API ゲートウェイを複数の API ゲートウェイに分割することで、マイクロサービスのさまざまなサブセットに焦点を当てたさまざまな開発チームが、独立した Ocelot 構成ファイルを使用して独自の API ゲートウェイを管理できます。 さらに、同時に、同じ Ocelot Docker イメージを再利用できます。

ここで、API ゲートウェイを使用して eShopOnContainers を実行する場合 (eShopOnContainers-ServicesAndWebApps.sln ソリューションを開くときに VS に既定で含まれるか、"docker-compose up" を実行している場合は、次のサンプル ルートが実行されます。

たとえば、webshoppingapigw API Gateway によって提供 http://host.docker.internal:5202/api/v1/c/catalog/items/2/ アップストリーム URL にアクセスすると、次のブラウザーのように、Docker ホスト内の内部ダウンストリーム URL http://catalog-api/api/v1/2 から同じ結果が得られます。

API ゲートウェイを通過する応答を示すブラウザーのスクリーンショット。

図 6-35 API ゲートウェイによって提供される URL を介してマイクロサービスにアクセスする

テストまたはデバッグの理由から、API ゲートウェイを通過せずに (開発環境でのみ) カタログ Docker コンテナーに直接アクセスする場合、'catalog-api' は Docker ホスト内部の DNS 解決 (docker-compose サービス名によって処理されるサービス検出) であるため、コンテナーに直接アクセスする唯一の方法は、docker-compose.override.ymlで発行された外部ポートを介することです。 これは、次のブラウザーで http://host.docker.internal:5101/api/v1/Catalog/items/1 など、開発テストにのみ提供されます。

Catalog.api への直接応答を示すブラウザーのスクリーンショット。

図 6-36 テスト目的でマイクロサービスに直接アクセスする

ただし、アプリケーションは、直接ポートの "ショートカット" ではなく、API ゲートウェイを介してすべてのマイクロサービスにアクセスするように構成されています。

eShopOnContainers のゲートウェイ集計パターン

前に紹介したように、要求の集計を柔軟に実装する方法は、コードによるカスタム サービスを使用することです。 eShopOnContainers で集計を実装する方法として、各アグリゲーターに対して明示的な ASP.NET Core Web API サービスを使用することが選択されています。

このアプローチによると、API Gateway の構成図は、前述の簡略化されたグローバル アーキテクチャ図に示されていないアグリゲーター サービスを考慮すると、実際にはもう少し拡張されます。

次の図では、アグリゲーター サービスが関連する API ゲートウェイとどのように連携するかを確認することもできます。

アグリゲーター サービスを示す eShopOnContainers アーキテクチャの図。

図 6-37 アグリゲーター サービスを使用した eShopOnContainers アーキテクチャ

さらに拡大すると、次の図の "ショッピング" ビジネス領域で、API ゲートウェイでアグリゲーター サービスを使用すると、クライアント アプリとマイクロサービスの間のチャット性が低下することがわかります。

eShopOnContainers アーキテクチャのズームインを示す図。

図 6-38 アグリゲーター サービスのビジョンを拡大する

図に、API ゲートウェイから送信される可能性のある要求が複雑になる可能性があるタイミングを確認できます。 一方、アグリゲーター パターンを使用すると、青色の矢印がクライアント アプリの観点からどのように通信を簡略化するかを確認できます。 このパターンは、通信のチャットと待ち時間を短縮するのに役立つだけでなく、リモート アプリ (モバイルアプリと SPA アプリ) のユーザー エクスペリエンスを大幅に向上させます。

"マーケティング" ビジネス領域とマイクロサービスの場合は単純なユース ケースであるため、アグリゲーターを使用する必要はありませんでしたが、必要に応じて可能な場合もあります。

Ocelot API ゲートウェイでの認証と承認

Ocelot API Gateway では、認証サービス ( IdentityServer を使用して認証トークンを提供する ASP.NET Core Web API サービスなど) を API ゲートウェイの内外に配置できます。

eShopOnContainers は BFF とビジネス領域に基づく境界を持つ複数の API ゲートウェイを使用しているため、次の図で黄色で強調表示されているように、ID/Auth サービスは API ゲートウェイから除外されます。

API ゲートウェイの下の ID マイクロサービスを示す図。

図 6-39 eShopOnContainers での ID サービスの位置

ただし、Ocelot では、この他の図のように、API ゲートウェイの境界内に ID/認証マイクロサービスを配置することもサポートされています。

Ocelot API ゲートウェイでの認証を示す図。

図 6-40 Ocelot での認証

前の図に示すように、ID マイクロサービスが API ゲートウェイ (AG) の下にある場合:1) AG が ID マイクロサービスに認証トークンを要求する、2) ID マイクロサービスが AG にトークンを返す、3 - 4) 認証トークンを使用してマイクロサービスからの AG 要求。 eShopOnContainers アプリケーションは API ゲートウェイを複数の BFF (フロントエンド用バックエンド) とビジネス領域の API ゲートウェイに分割しているため、もう 1 つのオプションは、横断的な懸念に対して追加の API ゲートウェイを作成することでした。 この選択は、複数の横断的な懸念がある、より複雑なマイクロサービス ベースのアーキテクチャでは公平です。 eShopOnContainers には横断的な懸念事項が 1 つしかないため、わかりやすくするために、セキュリティ サービスを API ゲートウェイ領域から処理することにしました。

いずれの場合も、アプリが API ゲートウェイ レベルでセキュリティ保護されている場合、セキュリティで保護されたマイクロサービスを使用しようとしたときに、Ocelot API Gateway の認証モジュールが最初にアクセスされます。 これは、ID または認証マイクロサービスにアクセスしてアクセス トークンを取得する HTTP 要求をリダイレクトし、access_tokenで保護されたサービスにアクセスできるようにします。

API ゲートウェイ レベルでサービスを認証してセキュリティで保護する方法は、configuration.jsonの関連設定で AuthenticationProviderKey を設定することです。

    {
      "DownstreamPathTemplate": "/api/{version}/{everything}",
      "DownstreamScheme": "http",
      "DownstreamHostAndPorts": [
        {
          "Host": "basket-api",
          "Port": 80
        }
      ],
      "UpstreamPathTemplate": "/api/{version}/b/{everything}",
      "UpstreamHttpMethod": [],
      "AuthenticationOptions": {
        "AuthenticationProviderKey": "IdentityApiKey",
        "AllowedScopes": []
      }
    }

Ocelot を実行すると、ReRoutes AuthenticationOptions.AuthenticationProviderKey が確認され、指定されたキーに登録されている認証プロバイダーがあることを確認します。 存在しない場合、Ocelot は起動しません。 存在する場合、ReRoute は実行時にそのプロバイダーを使用します。

Ocelot WebHost は authenticationProviderKey = "IdentityApiKey"で構成されているため、そのサービスに認証トークンのない要求がある場合は常に認証が必要です。

namespace OcelotApiGw
{
    public class Startup
    {
        private readonly IConfiguration _cfg;

        public Startup(IConfiguration configuration) => _cfg = configuration;

        public void ConfigureServices(IServiceCollection services)
        {
            var identityUrl = _cfg.GetValue<string>("IdentityUrl");
            var authenticationProviderKey = "IdentityApiKey";
                         //…
            services.AddAuthentication()
                .AddJwtBearer(authenticationProviderKey, x =>
                {
                    x.Authority = identityUrl;
                    x.RequireHttpsMetadata = false;
                    x.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                    {
                        ValidAudiences = new[] { "orders", "basket", "locations", "marketing", "mobileshoppingagg", "webshoppingagg" }
                    };
                });
            //...
        }
    }
}

次に、次の Basket マイクロサービス コントローラーのように、マイクロサービスのようにアクセスするリソースに対して [Authorize] 属性を使用して承認を設定する必要もあります。

namespace Microsoft.eShopOnContainers.Services.Basket.API.Controllers
{
    [Route("api/v1/[controller]")]
    [Authorize]
    public class BasketController : Controller
    {
      //...
    }
}

"basket" などの ValidAudience は、次のコードのように、Startup クラスの ConfigureServices() で AddJwtBearer() を使用して、各マイクロサービスで定義されている対象ユーザーと関連付けられます。

// prevent from mapping "sub" claim to nameidentifier.
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();

var identityUrl = Configuration.GetValue<string>("IdentityUrl");

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

}).AddJwtBearer(options =>
{
    options.Authority = identityUrl;
    options.RequireHttpsMetadata = false;
    options.Audience = "basket";
});

http://host.docker.internal:5202/api/v1/b/basket/1などの API ゲートウェイに基づく ReRoute URL を持つ Basket マイクロサービスなど、セキュリティで保護されたマイクロサービスにアクセスしようとすると、有効なトークンを指定しない限り、401 Unauthorized が表示されます。 一方、ReRoute URL が認証されると、Ocelot はそれに関連付けられているダウンストリーム スキーム (内部マイクロサービス URL) を呼び出します。

Ocelot の ReRoute 層での承認。 Ocelot では、認証後に評価されるクレーム ベースの承認がサポートされます。 承認をルート レベルで設定するには、次の行を ReRoute 構成に追加します。

"RouteClaimsRequirement": {
    "UserType": "employee"
}

この例では、承認ミドルウェアが呼び出されると、Ocelot は、ユーザーがトークンに要求の種類 'UserType' を持っているかどうか、およびその要求の値が 'employee' であるかどうかを確認します。 そうでない場合、ユーザーは承認されず、応答は 403 禁止になります。

Kubernetes イングレスと Ocelot API ゲートウェイの使用

Kubernetes (Azure Kubernetes Service クラスターなど) を使用する場合は、通常、Nginx に基づいて Kubernetes イングレス層を介してすべての HTTP 要求を統合します。

Kubernetes では、イングレス アプローチを使用しない場合、サービスとポッドには、クラスター ネットワークによってルーティング可能な IP のみが含まれます。

ただし、イングレス アプローチを使用する場合は、インターネットとサービス (API ゲートウェイを含む) の間に中間層があり、リバース プロキシとして機能します。

定義として、イングレスは、受信接続がクラスター サービスに到達できるようにする規則のコレクションです。 イングレスは、サービスに外部から到達可能な URL、負荷分散トラフィック、SSL 終了などを提供するように構成されます。 ユーザーは、イングレス リソースを API サーバーに POS 送信してイングレスを要求します。

eShopOnContainers では、ローカルで開発し、開発マシンのみを Docker ホストとして使用する場合、イングレスは使用せず、複数の API ゲートウェイのみを使用します。

ただし、Kubernetes に基づく "運用環境" 環境をターゲットとする場合、eShopOnContainers は API ゲートウェイの前でイングレスを使用します。 これにより、クライアントは引き続き同じベース URL を呼び出しますが、要求は複数の API ゲートウェイまたは BFF にルーティングされます。

API ゲートウェイは、サービスのみを表示するフロントエンドまたはファサードですが、通常はスコープ外の Web アプリケーションではありません。 さらに、API ゲートウェイでは、特定の内部マイクロサービスが非表示になる場合があります。

ただし、イングレスは HTTP 要求をリダイレクトするだけですが、マイクロサービスや Web アプリを非表示にしようとはしていません。

次の図に示すように、Web アプリケーションの前に Kubernetes のイングレス Nginx 層と複数の Ocelot API ゲートウェイ/BFF を含めるのが理想的なアーキテクチャです。

イングレス層が AKS 環境にどのように適合するかを示す図。

図 6-41 Kubernetes にデプロイされたときの eShopOnContainers のイングレス層

Kubernetes イングレスは、Api ゲートウェイ スコープ外の Web アプリケーションを含め、アプリへのすべてのトラフィックのリバース プロキシとして機能します。 Kubernetes に eShopOnContainers をデプロイすると、 イングレスを介して少数のサービスまたはエンドポイントだけが公開されます。基本的には、URL の後置の一覧を次に示します。

  • / クライアント SPA Web アプリケーション用
  • /webmvc クライアント MVC Web アプリケーション用
  • /webstatus 状態/正常性チェックが表示されているクライアント Web アプリの場合
  • /webshoppingapigw Web BFF およびショッピング ビジネス プロセス用
  • /webmarketingapigw Web BFF およびマーケティング ビジネス プロセス用
  • /mobileshoppingapigw モバイル BFF およびショッピング ビジネス プロセス用
  • /mobilemarketingapigw モバイル BFF およびマーケティング ビジネス プロセス用

Kubernetes にデプロイする場合、各 Ocelot API Gateway は、API ゲートウェイを実行している ポッド ごとに異なる "configuration.json" ファイルを使用します。 これらの "configuration.json" ファイルは、"ocelot" という名前の Kubernetes 構成マップ に基づいて作成されたボリュームをマウントすることによって提供されます (最初は deploy.ps1 スクリプトを使用)。 各コンテナーは、関連する構成ファイルを /app/configuration という名前のコンテナーのフォルダーにマウントします。

eShopOnContainers のソース コード ファイルでは、元の "configuration.json" ファイルが k8s/ocelot/ フォルダー内にあります。 BFF/APIGateway ごとに 1 つのファイルがあります。

Ocelot API ゲートウェイの追加のクロスカット機能

Ocelot API Gateway を使用する場合は、次のリンクで説明する、調査と使用に必要なその他の重要な機能があります。