The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
Back to Guides

Stork リファレンスガイド

このガイドは、 Stork 入門ガイドと対です。QuarkusでのSmallRye Stork統合の設定と使用方法について説明しています。

この技術は、previewと考えられています。

preview では、下位互換性やエコシステムでの存在は保証されていません。具体的な改善には設定や API の変更が必要になるかもしれませんが、 stable になるための計画は現在進行中です。フィードバックは メーリングリストGitHub の課題管理 で受け付けています。

とりうるステータスの完全なリストについては、 FAQの項目 を参照してください。

対応クライアント

現在のStork統合で対応しているのは次の通りです:

  • リアクティブRESTクライアント

  • gRPCクライアント

注意: gRPCクライアント統合は、統計ベースのロードバランサーをサポートしていません。

利用可能なサービスディスカバリーと選択

提供されるサービスディスカバリーと選択については、 SmallRye Storkのウェブサイトをご確認ください。

KubernetesでのStorkの使用

Storkは、Kubernetesがデフォルトで提供しているものを超える、Kubernetesのサービスディスカバリーサポートを提供します。これは、KubernetesのサービスをバックアップしているすべてのPodを探しますが、Kubernetesのようにラウンドロビンを適用するのではなく、Storkのロードバランサーを使用してポッドを選択するオプションを提供します。

この機能を使用するには、プロジェクトに以下の依存関係を追加します。

pom.xml
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-service-discovery-kubernetes</artifactId>
</dependency>
build.gradle
implementation("io.smallrye.stork:stork-service-discovery-kubernetes")

Kubernetes Serviceとして公開される予定の各サービスについて、ルックアップを設定します。

quarkus.stork.my-service.service-discovery.type=kubernetes
quarkus.stork.my-service.service-discovery.k8s-namespace=my-namespace

Storkは、指定された名前(前の例では my-service )のKubernetes Serviceを指定された名前空間で探します。StorkはKubernetes ServiceのIPを直接使用し、選択とバランシングをKubernetesに任せるのではなく、サービスを検査し、サービスを提供しているポッドのリストを取得します。そして、インスタンスを選択することができます。

KubernetesでStorkを使う詳しい例は、 Kubernetes で Stork を使用 をお読みください。

カスタムサービスディスカバリーの実装

Storkは拡張性があり、独自のサービスディスカバリーメカニズムを実装することができます。

依存関係

サービス ディスカバリー プロバイダーを実装するには、プロジェクトが Core と Configuration Generator に依存していることを確認してください。前者はカスタムディスカバリーの実装に必要なクラスを提供し、後者はStorkが必要とするクラスを生成するアノテーションプロセッサを含んでいます。

pom.xml
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-core</artifactId>
</dependency>
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-configuration-generator</artifactId>
    <!-- provided scope is sufficient for the annotation processor -->
    <scope>provided</scope>
</dependency>
build.gradle
implementation("io.smallrye.stork:stork-core")
compileOnly("io.smallrye.stork:stork-configuration-generator")

プロバイダがエクステンションに配置されている場合、設定ジェネレータは実行時モジュールの annotationProcessorPaths セクションでデフォルトのスコープを使用して宣言する必要があります。

<annotationProcessorPaths>
  ...
  <path>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-configuration-generator</artifactId>
  </path>
</annotationProcessorPaths>

サービスディスカバリープロバイダーの実装

カスタムプロバイダーは、このサービスディスカバリープロバイダーを使用して設定されたサービスごとに io.smallrye.stork.ServiceDiscovery インスタンスを作成するファクトリーです。例えば acme のようなタイプが各プロバイダを識別します。このタイプは、設定でプロバイダーを参照するために使用されます。

quarkus.stork.my-service.service-discovery.type=acme

最初のステップは、 io.smallrye.stork.spi.ServiceDiscoveryProvider インターフェースの実装です。

package examples;

import io.smallrye.stork.api.ServiceDiscovery;
import io.smallrye.stork.api.config.ServiceConfig;
import io.smallrye.stork.api.config.ServiceDiscoveryAttribute;
import io.smallrye.stork.api.config.ServiceDiscoveryType;
import io.smallrye.stork.spi.StorkInfrastructure;
import io.smallrye.stork.spi.ServiceDiscoveryProvider;

@ServiceDiscoveryType("acme") (1)
@ServiceDiscoveryAttribute(name = "host",
        description = "Host name of the service discovery server.", required = true) (2)
@ServiceDiscoveryAttribute(name = "port",
        description = "Port of the service discovery server.", required = false)
public class AcmeServiceDiscoveryProvider (3)
        implements ServiceDiscoveryProvider<AcmeConfiguration> {

    (4)
    @Override
    public ServiceDiscovery createServiceDiscovery(AcmeConfiguration config,
                                                   String serviceName,
                                                   ServiceConfig serviceConfig,
                                                   StorkInfrastructure storkInfrastructure) {
        return new AcmeServiceDiscovery(config);
    }
}

この実装は単純です。

1 @ServiceDiscoveryType アノテーションは、サービスディスカバリープロバイダーのタイプを定義します。このアノテーションでアノテーションされた各 ServiceDiscoveryProvider に対して、設定クラスが生成されます。構成クラスの名前は、プロバイダの名前に Configuration を付加して構成されます。
2 このサービスディスカバリープロバイダーで構成されたサービスの設定プロパティを定義するには、 @ServiceDiscoveryAttribute を使用します。設定プロパティは、フォームのすべてのプロパティから次の形で収集されます: stork.my-service.service-discovery.attr=value.
3 The provider needs to implement ServiceDiscoveryType typed by the configuration class. This configuration class is generated automatically by the Configuration Generator. Its name is created by appending Configuration to the service discovery type, such as AcmeConfiguration.
4 createServiceDiscovery メソッドは、ファクトリーメソッドです。このメソッドは、設定を受け取り、サービスの名前と利用可能なインフラへのアクセスを行います。

次に、 ServiceDiscovery インターフェースを実装する必要があります。

package examples;

import java.util.Collections;
import java.util.List;

import io.smallrye.mutiny.Uni;
import io.smallrye.stork.api.ServiceDiscovery;
import io.smallrye.stork.api.ServiceInstance;
import io.smallrye.stork.impl.DefaultServiceInstance;
import io.smallrye.stork.utils.ServiceInstanceIds;

public class AcmeServiceDiscovery implements ServiceDiscovery {

    private final String host;
    private final int port;

    public AcmeServiceDiscovery(AcmeConfiguration configuration) {
        this.host = configuration.getHost();
        this.port = Integer.parseInt(configuration.getPort());
    }

    @Override
    public Uni<List<ServiceInstance>> getServiceInstances() {
        // Proceed to the lookup...
        // Here, we just return a DefaultServiceInstance with the configured host and port
        // The last parameter specifies whether the communication with the instance should happen over a secure connection
        DefaultServiceInstance instance =
                new DefaultServiceInstance(ServiceInstanceIds.next(), host, port, false);
        return Uni.createFrom().item(() -> Collections.singletonList(instance));
    }
}

繰り返しになりますが、この実装は単純過ぎるものです。一般的には、設定から得た値でサービス・インスタンスを作成するのではなく、サービス・ディスカバリー・バックエンドに接続してサービスを探し、それに応じてサービス・インスタンスのリストを作成します。これが、このメソッドが Uni を返す理由です。ほとんどの場合、ルックアップはリモート操作で行われます。

サービスディスカバリーの利用

これを使用するプロジェクトでは、実装を提供するモジュールへの依存を忘れずに追加してください。そして、設定では、以下の追加だけが必要です:

quarkus.stork.my-service.service-discovery.type=acme
quarkus.stork.my-service.service-discovery.host=localhost
quarkus.stork.my-service.service-discovery.port=1234

そして、Storkはあなたの実装を使って、 my-service のサービスを探します。

カスタムサービス選択/ロードバランサーの実装

Storkは拡張性があり、独自のサービス選択(ロードバランサー)機構を実装することができます。

依存関係

ロードバランサープロバイダーを実装するには、プロジェクトが Core と Configuration Generator に依存していることを確認してください。前者はカスタムロードバランサーの実装に必要なクラスを提供し、後者はStorkが必要とするクラスを生成するアノテーションプロセッサを含んでいます。

pom.xml
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-core</artifactId>
</dependency>
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-configuration-generator</artifactId>
    <!-- provided scope is sufficient for the annotation processor -->
    <scope>provided</scope>
</dependency>
build.gradle
implementation("io.smallrye.stork:stork-core")
compileOnly("io.smallrye.stork:stork-configuration-generator")

カスタム ディスカバリー プロバイダと同様に、プロバイダがエクステンションに配置されている場合は、ランタイム モジュールの annotationProcessorPaths セクションでデフォルト スコープを使用して設定ジェネレータを宣言する必要があります。

ロードバランサー・プロバイダーの実装

ロードバランサーの実装は3つの要素で構成されています:

  • LoadBalancer Stork サービスのサービスインスタンスを選択する責任があります。

  • LoadBalancerProvider ロードバランサーの type に応じて LoadBalancer のインスタンスを作成します。

  • ロードバランサーの設定である LoadBalancerProviderConfiguration

type は、例えば acme のように、各プロバイダーを識別します。この type は、設定でプロバイダーを参照するために使用されます。

quarkus.stork.my-service.load-balancer.type=acme

ServiceDiscoveryProvider と同様に、LoadBalancerProvider の実装は type を定義する @LoadBalancerType のアノテーションが必要です。プロバイダーが期待する設定プロパティは、プロバイダーに置かれた @LoadBalancerAttribute のアノテーションで定義する必要があります。

package examples;

import io.smallrye.stork.api.LoadBalancer;
import io.smallrye.stork.api.ServiceDiscovery;
import io.smallrye.stork.api.config.LoadBalancerAttribute;
import io.smallrye.stork.api.config.LoadBalancerType;
import io.smallrye.stork.spi.LoadBalancerProvider;

@LoadBalancerType("acme")
@LoadBalancerAttribute(name = "my-attribute",
        description = "Attribute that alters the behavior of the LoadBalancer")
public class AcmeLoadBalancerProvider implements
        LoadBalancerProvider<AcmeLoadBalancerProviderConfiguration> {

    @Override
    public LoadBalancer createLoadBalancer(AcmeLoadBalancerProviderConfiguration config,
                                           ServiceDiscovery serviceDiscovery) {
        return new AcmeLoadBalancer(config);
    }
}

なお、 ServiceDiscoveryProvider と同様に、 LoadBalancerProvider インターフェースもパラメータとして設定クラスを受け取ります。この設定クラスは、 Configuration Generator によって自動的に生成されます。その名前は、プロバイダークラスの名前に Configuration を付加して作成されます。

次のステップは、 LoadBalancer インターフェースを実装することです。

package examples;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Random;

import io.smallrye.stork.api.LoadBalancer;
import io.smallrye.stork.api.NoServiceInstanceFoundException;
import io.smallrye.stork.api.ServiceInstance;

public class AcmeLoadBalancer implements LoadBalancer {

    private final Random random;

    public AcmeLoadBalancer(AcmeLoadBalancerProviderConfiguration config) {
        random = new Random();
    }

    @Override
    public ServiceInstance selectServiceInstance(Collection<ServiceInstance> serviceInstances) {
        if (serviceInstances.isEmpty()) {
            throw new NoServiceInstanceFoundException("No services found.");
        }
        int index = random.nextInt(serviceInstances.size());
        return new ArrayList<>(serviceInstances).get(index);
    }
}

繰り返しになりますが、この実装は単純過ぎるもので、受信したリストからランダムにインスタンスを選択するだけです。

examples.AcmeLoadBalancerProvider

ロードバランサーの使用

これを使用するプロジェクトでは、実装を提供するモジュールへの依存を忘れずに追加してください。そして、設定では、以下の追加だけが必要です:

quarkus.stork.my-service.service-discovery.type=...
quarkus.stork.my-service.load-balancer.type=acme

その後、Storkはあなたの実装を使って my-service のサービスインスタンスを選択します。