1. 概要

このチュートリアルでは、 Spring Cloud Open Service Brokerプロジェクトを紹介し、Open Service BrokerAPIを実装する方法を学習します。

まず、Open ServiceBrokerAPIの仕様について詳しく説明します。 次に、Spring Cloud OpenServiceBrokerを使用してAPI仕様を実装するアプリケーションを構築する方法を学習します。

最後に、サービスブローカーエンドポイントを保護するために使用できるセキュリティメカニズムについて説明します。

2. Open Service Broker API

Open Service Broker APIプロジェクトを使用すると、CloudFoundryやKubernetesなどのクラウドネイティブプラットフォームで実行されているアプリケーションにバッキングサービスをすばやく提供できます。 本質的に、API仕様は、これらのサービスをプロビジョニングして接続できる一連のRESTエンドポイントを記述しています。

特に、クラウドネイティブプラットフォーム内でサービスブローカーを使用して、次のことができます。

  • バッキングサービスのカタログを宣伝する
  • サービスインスタンスをプロビジョニングする
  • バッキングサービスとクライアントアプリケーション間のバインディングを作成および削除します
  • プロビジョニング解除サービスインスタンス

Spring Cloud Open Service Broker は、必要なWebコントローラー、ドメインオブジェクト、および構成を提供することにより、Open ServiceBrokerAPI準拠の実装のベースを作成します。 さらに、適切なサービスブローカーインターフェイスを実装して、ビジネスロジックを考え出す必要があります。

3. 自動構成

アプリケーションでSpringCloudOpen Service Brokerを使用するには、関連するスターターアーティファクトを追加する必要があります。 Maven Centralを使用して、 open-service-brokerstarterの最新バージョンを検索できます。

自動構成をアクティブ化するには、クラウドスターターに加えて、Spring Boot Webスターター、およびSpringWebFluxまたはSpringMVCのいずれかを含める必要があります。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-open-service-broker</artifactId>
    <version>3.1.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

自動構成メカニズムは、サービスブローカーに必要なほとんどのコンポーネントのデフォルトの実装を構成します。 必要に応じて、 open-service-broker Spring関連のBeanの独自の実装を提供することにより、デフォルトの動作をオーバーライドできます。

3.1. ServiceBrokerエンドポイントのパス構成

デフォルトでは、サービスブローカーエンドポイントが登録されるコンテキストパスは「/」です。

それが理想的ではなく、変更したい場合、最も簡単な方法は、アプリケーションのプロパティまたはYAMLファイルでプロパティ spring.cloud.openservicebroker.base-pathを設定することです。

spring:
  cloud:
    openservicebroker:
      base-path: /broker

この場合、サービスブローカーのエンドポイントをクエリするには、最初にリクエストの前に / broker/ベースパスを付ける必要があります。

4. サービスブローカーの例

Spring Cloud Open Service Brokerライブラリを使用してServiceBrokerアプリケーションを作成し、APIがどのように機能するかを調べてみましょう。

この例では、サービスブローカーを使用して、バッキングメールシステムをプロビジョニングして接続します。 簡単にするために、コード例で提供されているダミーのメールAPIを使用します。

4.1. サービスカタログ

まず、サービスブローカーが提供するサービスを制御するには、サービスカタログを定義する必要があります。 サービスカタログをすばやく初期化するために、この例では、タイプCatalogのSpringbeanを提供します。

@Bean
public Catalog catalog() {
    Plan mailFreePlan = Plan.builder()
        .id("fd81196c-a414-43e5-bd81-1dbb082a3c55")
        .name("mail-free-plan")
        .description("Mail Service Free Plan")
        .free(true)
        .build();

    ServiceDefinition serviceDefinition = ServiceDefinition.builder()
        .id("b92c0ca7-c162-4029-b567-0d92978c0a97")
        .name("mail-service")
        .description("Mail Service")
        .bindable(true)
        .tags("mail", "service")
        .plans(mailFreePlan)
        .build();

    return Catalog.builder()
        .serviceDefinitions(serviceDefinition)
        .build();
}

上記のように、サービスカタログには、サービスブローカーが提供できるすべての利用可能なサービスを説明するメタデータが含まれています。 さらに、サービスの定義は、データベース、メッセージングキュー、またはこの場合はメールサービスを指す可能性があるため、意図的に広くされています。

もう1つの重要なポイントは、各サービスが計画から構築されていることです。これは別の一般的な用語です。 本質的に、各プランは異なる機能を提供し、異なる金額を支払うことができます

最終的に、サービスカタログは、サービスブローカー / v2 /catalogエンドポイントを介してクラウドネイティブプラットフォームで利用できるようになります。

curl http://localhost:8080/broker/v2/catalog

{
    "services": [
        {
            "bindable": true,
            "description": "Mail Service",
            "id": "b92c0ca7-c162-4029-b567-0d92978c0a97",
            "name": "mail-service",
            "plans": [
                {
                    "description": "Mail Service Free Plan",
                    "free": true,
                    "id": "fd81196c-a414-43e5-bd81-1dbb082a3c55",
                    "name": "mail-free-plan"
                }
            ],
            "tags": [
                "mail",
                "service"
            ]
        }
    ]
}

その結果、クラウドネイティブプラットフォームは、すべてのサービスブローカーからサービスブローカーカタログエンドポイントにクエリを実行して、サービスカタログの集約ビューを表示します。

4.2. サービスプロビジョニング

広告サービスを開始したら、クラウドプラットフォーム内でそれらのライフサイクルをプロビジョニングおよび管理するためのメカニズムをブローカーに提供する必要もあります。

さらに、プロビジョニングが表すものはブローカーごとに異なります。 場合によっては、プロビジョニングには、空のデータベースの起動、メッセージブローカーの作成、または単に外部APIにアクセスするためのアカウントの提供が含まれる場合があります。

用語では、サービスブローカーによって作成されたサービスはサービスインスタンスと呼ばれます。

Spring Cloud Open Service Brokerを使用すると、 ServiceInstanceService インターフェイスを実装することで、サービスのライフサイクルを管理できます。 たとえば、サービスブローカーでサービスプロビジョニングリクエストを管理するには、createServiceInstanceメソッドの実装を提供する必要があります。

@Override
public Mono<CreateServiceInstanceResponse> createServiceInstance(
    CreateServiceInstanceRequest request) {
    return Mono.just(request.getServiceInstanceId())
        .flatMap(instanceId -> Mono.just(CreateServiceInstanceResponse.builder())
            .flatMap(responseBuilder -> mailService.serviceInstanceExists(instanceId)
                .flatMap(exists -> {
                    if (exists) {
                        return mailService.getServiceInstance(instanceId)
                            .flatMap(mailServiceInstance -> Mono.just(responseBuilder
                                .instanceExisted(true)
                                .dashboardUrl(mailServiceInstance.getDashboardUrl())
                                .build()));
                    } else {
                        return mailService.createServiceInstance(
                            instanceId, request.getServiceDefinitionId(), request.getPlanId())
                            .flatMap(mailServiceInstance -> Mono.just(responseBuilder
                                .instanceExisted(false)
                                .dashboardUrl(mailServiceInstance.getDashboardUrl())
                                .build()));
                    }
                })));
}

ここでは、同じサービスインスタンスIDを持つメールサービスが存在しない場合は、内部マッピングに新しいメールサービスを割り当て、ダッシュボードURLを提供します。 ダッシュボードは、サービスインスタンスのWeb管理インターフェイスと見なすことができます。

サービスプロビジョニングは、 / v2 / service_instances /{instance_id}エンドポイントを介してクラウドネイティブプラットフォームで利用できるようになります。

curl -X PUT http://localhost:8080/broker/v2/service_instances/[email protected] 
  -H 'Content-Type: application/json' 
  -d '{
    "service_id": "b92c0ca7-c162-4029-b567-0d92978c0a97", 
    "plan_id": "fd81196c-a414-43e5-bd81-1dbb082a3c55"
  }' 

{"dashboard_url":"http://localhost:8080/mail-dashboard/[email protected]"}

つまり、新しいサービスをプロビジョニングするときは、サービスカタログでアドバタイズされたservice_idとplan_idを渡す必要があります。 さらに、一意の instance_id を提供する必要があります。これは、サービスブローカーが将来のバインドおよびプロビジョニング解除要求で使用します。

4.3. サービスバインディング

サービスをプロビジョニングした後、クライアントアプリケーションがサービスとの通信を開始するようにします。 サービスブローカーの観点からは、これはサービスバインディングと呼ばれます。

サービスインスタンスやプランと同様に、バインディングは、サービスブローカー内で使用できるもう1つの柔軟な抽象化と見なす必要があります。 一般に、サービスインスタンスへのアクセスに使用される資格情報を公開するためのサービスバインディングを提供します

この例では、アドバタイズされたサービスのbindableフィールドがtrueに設定されている場合、サービスブローカーはServiceInstanceBindingServiceインターフェイスの実装を提供する必要があります。 それ以外の場合、クラウドプラットフォームはサービスブローカーからサービスバインディングメソッドを呼び出しません。

createServiceInstanceBinding メソッドに実装を提供することにより、サービスバインディングの作成要求を処理しましょう。

@Override
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(
    CreateServiceInstanceBindingRequest request) {
    return Mono.just(CreateServiceInstanceAppBindingResponse.builder())
        .flatMap(responseBuilder -> mailService.serviceBindingExists(
            request.getServiceInstanceId(), request.getBindingId())
            .flatMap(exists -> {
                if (exists) {
                    return mailService.getServiceBinding(
                        request.getServiceInstanceId(), request.getBindingId())
                        .flatMap(serviceBinding -> Mono.just(responseBuilder
                            .bindingExisted(true)
                            .credentials(serviceBinding.getCredentials())
                            .build()));
                } else {
                    return mailService.createServiceBinding(
                        request.getServiceInstanceId(), request.getBindingId())
                        .switchIfEmpty(Mono.error(
                            new ServiceInstanceDoesNotExistException(
                                request.getServiceInstanceId())))
                        .flatMap(mailServiceBinding -> Mono.just(responseBuilder
                            .bindingExisted(false)
                            .credentials(mailServiceBinding.getCredentials())
                            .build()));
                }
            }));
}

上記のコードは、一意の資格情報のセット(ユーザー名、パスワード、およびURI)を生成します。これを介して、新しいメールサービスインスタンスに接続して認証できます。

Spring Cloud Open Service Brokerフレームワークは、 / v2 / service_instances / {instance_id} / service_bindings /{binding_id}エンドポイントを介してサービスバインディング操作を公開します。

curl -X PUT 
  http://localhost:8080/broker/v2/service_instances/[email protected]/service_bindings/admin 
  -H 'Content-Type: application/json' 
  -d '{ 
    "service_id": "b92c0ca7-c162-4029-b567-0d92978c0a97", 
    "plan_id": "fd81196c-a414-43e5-bd81-1dbb082a3c55" 
  }'

{
    "credentials": {
        "password": "bea65996-3871-4319-a6bb-a75df06c2a4d",
        "uri": "http://localhost:8080/mail-system/[email protected]",
        "username": "admin"
    }
}

サービスインスタンスのプロビジョニングと同様に、バインディングリクエスト内でサービスカタログにアドバタイズされたservice_idplan_idを使用しています。 さらに、一意の binding_id も渡します。これは、ブローカーが資格情報セットのユーザー名として使用します。

5. ServiceBrokerAPIのセキュリティ

通常、サービスブローカーとクラウドネイティブプラットフォームが相互に通信する場合、認証メカニズムが必要です。

残念ながら、Open Service Broker API仕様は、現在、ServiceBrokerエンドポイントの認証部分をカバーしていません。 このため、Spring Cloud OpenServiceBrokerライブラリもセキュリティ構成を実装していません。

幸い、サービスブローカーのエンドポイントを保護する必要がある場合は、SpringSecurityを使用して基本認証またはOAuth2.0メカニズムをすばやく導入できます。 この場合、選択した認証メカニズムを使用してすべてのサービスブローカー要求を認証し、認証が失敗したときに 401Unauthorized応答を返す必要があります。

6. 結論

この記事では、Spring Cloud OpenServiceBrokerプロジェクトについて説明しました。

最初に、Open Service Broker APIとは何か、そしてそれがどのようにバッキングサービスをプロビジョニングして接続できるようにするかを学びました。 続いて、Spring Cloud OpenServiceBrokerライブラリを使用してServiceBrokerAPI準拠のプロジェクトをすばやく構築する方法を確認しました。

最後に、SpringSecurityを使用してサービスブローカーエンドポイントを保護する方法について説明しました。

いつものように、このチュートリアルのソースコードは、GitHubからで入手できます。