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

Stork リファレンスガイド

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

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

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

For a full list of possible statuses, check our FAQ entry.

対応クライアント

現在の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に任せるのではなく、サービスを検査し、サービスを提供しているポッドのリストを取得します。そして、インスタンスを選択することができます。

For a full example of using Stork with Kubernetes, please read the Using Stork with Kubernetes guide.

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

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>

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

The custom provider is a factory that creates an io.smallrye.stork.ServiceDiscovery instance for each configured service using this service discovery provider. A type, for example, acme identifies each provider. This type is used in the configuration to reference the provider:

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<AcmeServiceDiscoveryProviderConfiguration> {

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

この実装は単純です。

1 @ServiceDiscoveryType annotation defines the type of the service discovery provider. For each ServiceDiscoveryProvider annotated with this annotation, a configuration class will be generated. The name of the configuration class is constructed by appending Configuration to the name of the provider.
2 Use @ServiceDiscoveryAttribute to define configuration properties for services configured with this service discovery provider. Configuration properties are gathered from all properties of a form: quarkus.stork.my-service.service-discovery.attr=value.
3 The provider needs to implement ServiceDiscoveryType typed by the configuration class.
4 createServiceDiscovery method is the factory method. It receives the configuration and access to the name of the service and available infrastructure.

次に、 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(AcmeServiceDiscoveryProviderConfiguration 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

Similarly to ServiceDiscoveryProvider, a `LoadBalancerProvider implementation needs to be annotated with @LoadBalancerType that defines the type. Any configuration properties that the provider expects should be defined with @LoadBalancerAttribute annotations placed on the provider.

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);
    }
}

Note, that similarly to the ServiceDiscoveryProvider, the LoadBalancerProvider interface takes a configuration class as a parameter. This configuration class is generated automatically by the Configuration Generator. Its name is created by appending Configuration to the name of the provider class.

次のステップは、 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 のサービスインスタンスを選択します。