다음을 통해 공유


Ocelot을 사용하여 API 게이트웨이 구현

팁 (조언)

이 콘텐츠는 .NET Docs 또는 오프라인으로 읽을 수 있는 다운로드 가능한 무료 PDF로 제공되는 컨테이너화된 .NET 애플리케이션용 .NET 마이크로 서비스 아키텍처인 eBook에서 발췌한 내용입니다.

컨테이너화된 .NET 애플리케이션을 위한 .NET 마이크로서비스 아키텍처 eBook의 표지 썸네일.

중요합니다

참조 마이크로 서비스 애플리케이션 eShopOnContainers는 현재 이전에 참조한 Ocelot 대신 Envoy에서 제공하는 기능을 사용하여 API 게이트웨이를 구현합니다. eShopOnContainers에서 구현된 새로운 gRPC 서비스 간 통신에 필요한 Envoy의 WebSocket 프로토콜에 대한 기본 제공 지원으로 인해 이 디자인을 선택했습니다. 그러나 Ocelot을 프로덕션 등급 시나리오에 적합한 간단하고 유능하며 간단한 API 게이트웨이로 간주할 수 있도록 가이드에서 이 섹션을 유지했습니다. 또한 최신 Ocelot 버전에는 json 스키마의 호환성이 손상되는 변경이 포함되어 있습니다. Ocelot < v16.0.0을 사용하거나 다시 라우팅 대신 키 경로를 사용하는 것이 좋습니다.

API 게이트웨이 설계 및 디자인

다음 아키텍처 다이어그램에서는 eShopOnContainers에서 Ocelot을 사용하여 API 게이트웨이를 구현하는 방법을 보여 줍니다.

eShopOnContainers 아키텍처를 보여 주는 다이어그램

그림 6-28. API 게이트웨이를 사용하는 eShopOnContainers 아키텍처

이 다이어그램은 "Windows용 Docker" 또는 "Mac용 Docker"를 사용하여 전체 애플리케이션을 단일 Docker 호스트 또는 개발 PC에 배포하는 방법을 보여 줍니다. 그러나 오케스트레이터에 배포하는 것은 유사하지만 다이어그램의 컨테이너는 오케스트레이터에서 확장될 수 있습니다.

또한 데이터베이스, 캐시 및 메시지 브로커와 같은 인프라 자산은 오케스트레이터에서 오프로드되고 Azure SQL Database, Azure Cosmos DB, Azure Redis, Azure Service Bus 또는 온-프레미스의 HA 클러스터링 솔루션과 같은 인프라에 대해 고가용성 시스템에 배포되어야 합니다.

다이어그램에서도 알 수 있듯이 여러 API 게이트웨이를 사용하면 마이크로 서비스와 자체 관련 API 게이트웨이를 개발하고 배포할 때 여러 개발 팀이 자율(이 경우 마케팅 기능과 쇼핑 기능)할 수 있습니다.

단일 모놀리식 API 게이트웨이가 있는 경우 여러 개발 팀에서 단일 지점을 업데이트해야 하며, 이는 모든 마이크로 서비스를 애플리케이션의 단일 부분과 결합할 수 있습니다.

디자인에서 훨씬 더 나아가, 경우에 따라 세분화된 API 게이트웨이는 선택한 아키텍처에 따라 단일 비즈니스 마이크로 서비스로 제한될 수 있습니다. 비즈니스 또는 도메인에서 지정한 API 게이트웨이의 경계를 사용하면 더 나은 디자인을 얻을 수 있습니다.

예를 들어 세분화된 API 게이트웨이의 개념은 UI 컴퍼지션 서비스와 유사하기 때문에 API 게이트웨이 계층의 세분성은 마이크로 서비스를 기반으로 하는 고급 복합 UI 애플리케이션에 특히 유용할 수 있습니다.

이전 섹션에서는 마이크로 서비스를 기반으로 복합 UI를 만드는 방법에 대해 자세히 설명합니다.

많은 중대형 애플리케이션에서 사용자 지정 빌드 API 게이트웨이 제품을 사용하는 것은 일반적으로 좋은 방법이지만, API 게이트웨이가 자율 마이크로 서비스를 만드는 여러 개발 팀에 여러 개의 독립적인 구성 영역을 허용하지 않는 한 단일 모놀리식 집계 또는 고유한 중앙 사용자 지정 API 게이트웨이는 아닙니다.

API 게이트웨이를 통해 경로를 다시 지정하는 샘플 마이크로 서비스/컨테이너

예를 들어 eShopOnContainers에는 다음 이미지와 같이 API 게이트웨이를 통해 게시해야 하는 약 6개의 내부 마이크로 서비스 유형이 있습니다.

하위 폴더를 보여 주는 Services 폴더의 스크린샷

그림 6-29. Visual Studio의 eShopOnContainers 솔루션에 있는 마이크로 서비스 폴더

ID 서비스에 대해 Ocelot을 사용하면 경로 변경 목록의 일부로 포함할 수도 있지만 시스템에서 유일한 교차 절단 문제이기 때문에 디자인에서 API 게이트웨이 라우팅에서 제외됩니다.

이러한 모든 서비스는 현재 코드에서 알 수 있듯이 ASP.NET Core Web API 서비스로 구현됩니다. 카탈로그 마이크로 서비스 코드와 같은 마이크로 서비스 중 하나에 집중해 보겠습니다.

Catalog.API 프로젝트 콘텐츠를 보여 주는 솔루션 탐색기의 스크린샷

그림 6-30. 샘플 Web API 마이크로 서비스(카탈로그 마이크로 서비스)

카탈로그 마이크로 서비스는 다음 코드와 같이 여러 컨트롤러와 메서드가 있는 일반적인 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과 같이 dockerfile에 지정된 내부 포트(일반적으로 포트 80)가 있습니다.

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

코드에 표시된 포트 80은 Docker 호스트 내에서 내부이므로 클라이언트 앱에서 연결할 수 없습니다.

클라이언트 앱은 로 배포할 때 게시된 외부 포트(있는 경우)에만 액세스할 수 있습니다 docker-compose.

이러한 외부 포트는 프로덕션 환경에 배포할 때 게시해서는 안 됩니다. 이러한 특정 이유 때문에 클라이언트 앱과 마이크로 서비스 간의 직접 통신을 방지하기 위해 API 게이트웨이를 사용하려고 합니다.

그러나 개발할 때 마이크로 서비스/컨테이너에 직접 액세스하고 Swagger를 통해 실행하려고 합니다. 따라서 eShopOnContainers에서 외부 포트는 API 게이트웨이 또는 클라이언트 앱에서 사용되지 않는 경우에도 계속 지정됩니다.

카탈로그 마이크로 서비스에 대한 파일의 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 게이트웨이를 사용하는 경우 애플리케이션에서 사용해서는 안 되며 카탈로그 마이크로 서비스만 디버그, 실행 및 테스트하는 데만 사용됩니다.

일반적으로 마이크로 서비스에 적합한 프로덕션 배포 환경은 Kubernetes 또는 Service Fabric과 같은 오케스트레이터이므로 docker-compose를 사용하여 프로덕션 환경에 배포하지 않습니다. 이러한 환경에 배포할 때는 마이크로 서비스에 대한 외부 포트를 직접 게시하지 않지만 항상 API 게이트웨이에서 역방향 프록시를 사용하는 다른 구성 파일을 사용합니다.

로컬 Docker 호스트에서 카탈로그 마이크로 서비스를 실행합니다. Visual Studio에서 전체 eShopOnContainers 솔루션을 실행하거나(docker-compose 파일에서 모든 서비스를 실행) CMD에서 다음 docker-compose 명령을 사용하여 카탈로그 마이크로 서비스를 시작하거나 배치되는 폴더 docker-compose.ymldocker-compose.override.yml 에 배치된 PowerShell을 사용합니다.

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

이 명령은 catalog-api 서비스 컨테이너와 docker-compose.yml 지정된 종속성만 실행합니다. 이 경우 SQL Server 컨테이너 및 RabbitMQ 컨테이너입니다.

그런 다음 카탈로그 마이크로 서비스에 직접 액세스하고 해당 "외부" 포트를 통해 직접 액세스하는 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 애플리케이션에 적합하지 않습니다.

Visual Studio에서 Ocelot의 NuGet 패키지를 사용하여 ASP.NET Core 프로젝트에 Ocelot 및 해당 종속성을 설치합니다.

Install-Package Ocelot

eShopOnContainers에서 API 게이트웨이 구현은 간단한 ASP.NET Core WebHost 프로젝트이며 Ocelot의 미들웨어는 다음 이미지와 같이 모든 API 게이트웨이 기능을 처리합니다.

Ocelot API 게이트웨이 프로젝트를 보여 주는 솔루션 탐색기의 스크린샷

그림 6-32. eShopOnContainers의 OcelotApiGw 기본 프로젝트

이 ASP.NET Core WebHost 프로젝트는 다음과 같은 두 개의 간단한 파일 Program.cs 로 빌드됩니다 Startup.cs.

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 게이트웨이 다시 라우팅을 지정합니다. 즉, 일반적으로 서로 다른 포트를 사용하는 특정 포트와 상관 관계가 있는 내부 엔드포인트가 있는 외부 엔드포인트를 의미합니다.

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

구성에는 두 개의 섹션이 있습니다. ReRoutes 및 GlobalConfiguration의 배열입니다. ReRoutes는 업스트림 요청을 처리하는 방법을 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 게이트웨이의 주요 기능은 들어오는 HTTP 요청을 가져와 현재 다른 HTTP 요청으로 다운스트림 서비스로 전달하는 것입니다. Ocelot은 한 요청을 다른 요청으로 라우팅하는 것을 ReRoute로 설명합니다.

예를 들어 위에서 configuration.json 있는 ReRoutes 중 하나인 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-compose 파일에 제공된 서비스 이름을 사용하는 Docker 호스트에서 제공됩니다. Kubernetes 또는 Service Fabric과 같은 오케스트레이터를 사용하는 경우 해당 이름은 각 오케스트레이터에서 제공하는 DNS 또는 이름 확인에 의해 확인되어야 합니다.

DownstreamHostAndPorts는 요청을 전달하려는 다운스트림 서비스의 호스트 및 포트를 포함하는 배열입니다. 일반적으로 이 구성은 하나의 항목만 포함하지만 경우에 따라 다운스트림 서비스에 대한 요청 부하를 분산하고 Ocelot을 사용하면 둘 이상의 항목을 추가한 다음 부하 분산 장치를 선택할 수 있습니다. 그러나 Azure 및 오케스트레이터를 사용하는 경우 클라우드 및 오케스트레이터 인프라와 부하를 분산하는 것이 좋습니다.

UpstreamPathTemplate은 Ocelot이 클라이언트에서 지정된 요청에 사용할 DownstreamPathTemplate을 식별하는 데 사용하는 URL입니다. 마지막으로, Ocelot이 동일한 URL에 대한 다양한 요청(GET, POST, PUT)을 구분할 수 있도록 UpstreamHttpMethod가 사용됩니다.

이 시점에서 하나 이상의 병합된 configuration.json 파일을 사용하여 단일 Ocelot API 게이트웨이(ASP.NET Core WebHost)를 만들거나 Consul KV 저장소에 구성을 저장할 수도 있습니다.

그러나 아키텍처 및 디자인 섹션에서 소개한 것처럼, 실제로 자율 마이크로 서비스를 사용하려는 경우 단일 모놀리식 API 게이트웨이를 여러 API 게이트웨이 및/또는 BFF(프런트 엔드용 백 엔드)로 분할하는 것이 더 나을 수 있습니다. 이를 위해 Docker 컨테이너를 사용하여 해당 접근 방식을 구현하는 방법을 살펴보겠습니다.

단일 Docker 컨테이너 이미지를 사용하여 여러 다른 API 게이트웨이/BFF 컨테이너 유형 실행

eShopOnContainers에서는 Ocelot API 게이트웨이와 함께 단일 Docker 컨테이너 이미지를 사용하지만 런타임에 각 서비스에 대해 다른 pc 폴더에 액세스하기 위해 docker 볼륨을 사용하여 다른 configuration.json 파일을 제공하여 각 유형의 API-Gateway/BFF에 대해 서로 다른 서비스/컨테이너를 만듭니다.

모든 API 게이트웨이에 대한 단일 Ocelot 게이트웨이 Docker 이미지의 다이어그램

그림 6-33. 여러 API 게이트웨이 유형에서 단일 Ocelot Docker 이미지 다시 사용

eShopOnContainers에서 "일반 Ocelot API 게이트웨이 Docker 이미지"는 'OcelotApiGw'라는 프로젝트와 docker-compose.yml 파일에 지정된 이미지 이름 "eshop/ocelotapigw"로 만들어집니다. 그런 다음 Docker에 배포할 때 docker-compose.yml 파일의 다음 추출과 같이 동일한 Docker 이미지에서 만든 4개의 API-Gateway 컨테이너가 있습니다.

  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 게이트웨이 컨테이너 간의 유일한 차이점은 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 탐색기에 표시된 것처럼 각 특정 비즈니스/BFF API 게이트웨이를 정의하는 데 필요한 유일한 파일은 4개의 API 게이트웨이가 동일한 Docker 이미지를 기반으로 하기 때문에 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 게이트웨이에서 제공하는 업스트림 URL http://host.docker.internal:5202/api/v1/c/catalog/items/2/ 을 방문하면 다음 브라우저와 같이 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 게이트웨이 컴퍼지션 다이어그램은 이전에 표시된 간소화된 전역 아키텍처 다이어그램에 표시되지 않는 집계 서비스를 고려할 때 실제로 조금 더 확장됩니다.

다음 다이어그램에서는 집계 서비스가 관련 API 게이트웨이에서 작동하는 방법을 확인할 수도 있습니다.

집계 서비스를 보여 주는 eShopOnContainers 아키텍처의 다이어그램

그림 6-37. 집계 서비스를 사용하는 eShopOnContainers 아키텍처

다음 이미지의 "쇼핑" 비즈니스 영역에서 추가로 확대하면 API 게이트웨이에서 집계 서비스를 사용할 때 클라이언트 앱과 마이크로 서비스 간의 대화가 감소하는 것을 볼 수 있습니다.

eShopOnContainers 아키텍처 확대를 보여 주는 다이어그램

그림 6-38. Aggregator 서비스의 시각 확대

다이어그램에 API 게이트웨이에서 들어오는 가능한 요청이 어떻게 표시되면 복잡해질 수 있는지 알 수 있습니다. 반면, 집계 패턴을 사용하는 경우 파란색 화살표가 클라이언트 앱 관점에서 통신을 간소화하는 방법을 확인할 수 있습니다. 이 패턴은 통신의 대화 및 대기 시간을 줄이는 데 도움이 될 뿐만 아니라 원격 앱(모바일 및 SPA 앱)에 대한 사용자 환경을 크게 향상시킵니다.

"마케팅" 비즈니스 영역 및 마이크로 서비스의 경우 간단한 사용 사례이므로 집계를 사용할 필요가 없었지만 필요한 경우 가능할 수도 있습니다.

Ocelot API 게이트웨이의 인증 및 권한 부여

Ocelot API 게이트웨이에서 API 게이트웨이 외부 또는 내부에서 인증 토큰을 제공하는 IdentityServer 를 사용하여 ASP.NET Core Web API 서비스와 같은 인증 서비스를 사용할 수 있습니다.

eShopOnContainers는 BFF 및 비즈니스 영역을 기반으로 경계가 있는 여러 API 게이트웨이를 사용하므로 ID/인증 서비스는 다음 다이어그램에서 노란색으로 강조 표시된 대로 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로 반환합니다. eShopOnContainers 애플리케이션이 API 게이트웨이를 여러 BFF(프런트 엔드용 백 엔드) 및 비즈니스 영역 API 게이트웨이로 분할했으므로 다른 옵션은 교차 절단 문제를 위한 추가 API 게이트웨이를 만드는 것이었습니다. 이러한 선택은 여러 교차 절단 문제가 있는 보다 복잡한 마이크로 서비스 기반 아키텍처에서 공정할 것입니다. eShopOnContainers에는 교차 커팅 문제가 하나뿐이므로 간단히 하기 위해 API 게이트웨이 영역에서 보안 서비스를 처리하기로 결정했습니다.

어쨌든 앱이 API 게이트웨이 수준에서 보호되는 경우 보안 마이크로 서비스를 사용하려고 할 때 Ocelot API 게이트웨이의 인증 모듈이 처음에 방문됩니다. 그러면 HTTP 요청을 리디렉션하여 ID 또는 인증 마이크로 서비스를 방문하여 액세스 토큰을 가져오므로 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"과 같은 ValidAudiences는 아래 코드와 같이 시작 클래스의 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";
});

API http://host.docker.internal:5202/api/v1/b/basket/1게이트웨이를 기반으로 하는 ReRoute URL이 있는 Basket 마이크로 서비스와 같은 보안 마이크로 서비스에 액세스하려고 하면 유효한 토큰을 제공하지 않는 한 401 권한 없음이 표시됩니다. 반면에 ReRoute URL이 인증되면 Ocelot은 연결된 다운스트림 스키마(내부 마이크로 서비스 URL)를 호출합니다.

Ocelot의 ReRoutes 계층에서 권한 부여. Ocelot은 인증 후에 평가되는 클레임 기반 권한 부여를 지원합니다. 다음 줄을 ReRoute 구성에 추가하여 경로 수준에서 권한 부여를 설정합니다.

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

이 예제에서 권한 부여 미들웨어가 호출되면 Ocelot은 사용자가 토큰에 클레임 형식 'UserType'을 가지고 있는지, 해당 클레임의 값이 'employee'인지를 찾습니다. 그렇지 않으면 사용자에게 권한이 부여되지 않으며 응답은 403이 금지됩니다.

Kubernetes 수신 및 Ocelot API 게이트웨이 사용

Kubernetes(예: Azure Kubernetes Service 클러스터)를 사용하는 경우 일반적으로 Nginx를 기반으로 Kubernetes 수신 계층을 통해 모든 HTTP 요청을 통합합니다.

Kubernetes에서 수신 방법을 사용하지 않는 경우 서비스와 Pod에는 클러스터 네트워크에서만 라우팅할 수 있는 IP가 있습니다.

그러나 수신 방법을 사용하는 경우 역방향 프록시 역할을 하는 인터넷과 서비스(API 게이트웨이 포함) 사이에 중간 계층이 있습니다.

정의로서 수신은 인바운드 연결이 클러스터 서비스에 연결할 수 있도록 허용하는 규칙의 컬렉션입니다. 수신은 외부에 연결할 수 있는 URL, 부하 분산 트래픽, SSL 종료 등의 서비스를 제공하도록 구성됩니다. 사용자는 수신 리소스를 API 서버에 POSTing하여 수신을 요청합니다.

eShopOnContainers에서 로컬로 개발하고 개발 머신만 Docker 호스트로 사용하는 경우 수신이 아니라 여러 API 게이트웨이만 사용합니다.

그러나 Kubernetes를 기반으로 하는 "프로덕션" 환경을 대상으로 하는 경우 eShopOnContainers는 API 게이트웨이 앞에서 수신을 사용합니다. 이렇게 하면 클라이언트는 여전히 동일한 기본 URL을 호출하지만 요청은 여러 API 게이트웨이 또는 BFF로 라우팅됩니다.

API 게이트웨이는 서비스만 표시하는 프런트 엔드 또는 외관이지만 일반적으로 범위를 벗어난 웹 애플리케이션은 표시하지 않습니다. 또한 API 게이트웨이는 특정 내부 마이크로 서비스를 숨길 수 있습니다.

그러나 수신은 HTTP 요청을 리디렉션하지만 마이크로 서비스 또는 웹앱을 숨기려고 하지 않습니다.

다음 다이어그램과 같이 웹 애플리케이션 앞에 Kubernetes에 수신 Nginx 계층과 여러 Ocelot API 게이트웨이/BFF가 있는 것이 이상적인 아키텍처입니다.

수신 계층이 AKS 환경에 맞는 방법을 보여 주는 다이어그램입니다.

그림 6-41. Kubernetes에 배포된 경우 eShopOnContainers의 수신 계층

Kubernetes 수신은 Api 게이트웨이 범위를 벗어난 웹 애플리케이션을 포함하여 앱에 대한 모든 트래픽에 대한 역방향 프록시 역할을 합니다. eShopOnContainers를 Kubernetes에 배포할 때 수신을 통해 몇 가지 서비스 또는 엔드포인트만 노출합니다. 기본적으로 URL의 다음 접미사 목록은 다음과 같습니다.

  • / 클라이언트 SPA 웹 애플리케이션용
  • /webmvc 클라이언트 MVC 웹 애플리케이션용
  • /webstatus 상태/상태 검사를 표시하는 클라이언트 웹앱의 경우
  • /webshoppingapigw 웹 BFF 및 쇼핑 비즈니스 프로세스용
  • /webmarketingapigw 웹 BFF 및 마케팅 비즈니스 프로세스용
  • /mobileshoppingapigw 모바일 BFF 및 쇼핑 비즈니스 프로세스용
  • /mobilemarketingapigw 모바일 BFF 및 마케팅 비즈니스 프로세스용

Kubernetes에 배포할 때 각 Ocelot API 게이트웨이는 API 게이트웨이를 실행하는 각 Pod 에 대해 다른 "configuration.json" 파일을 사용합니다. 이러한 "configuration.json" 파일은 'ocelot'이라는 Kubernetes 구성 맵 을 기반으로 만든 볼륨을 탑재(원래 deploy.ps1 스크립트와 함께)하여 제공됩니다. 각 컨테이너는 컨테이너의 폴더 /app/configuration에 관련 구성 파일을 탑재합니다.

eShopOnContainers의 소스 코드 파일에서 원래 "configuration.json" 파일은 폴더 내에서 k8s/ocelot/ 찾을 수 있습니다. 각 BFF/APIGateway에 대해 하나의 파일이 있습니다.

Ocelot API 게이트웨이의 추가 교차 절삭 기능

다음 링크에 설명된 Ocelot API 게이트웨이를 사용할 때 연구하고 사용하는 다른 중요한 기능이 있습니다.