The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.
このページを編集

Kubernetes で Stork を使用

このガイドでは、Kubernetes で Stork を使用してサービスの検出と負荷分散を行う方法について説明します。

Stork を初めて使用する場合は、Stork 入門ガイド をお読みください。

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

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

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

前提条件

このガイドを完成させるには、以下が必要です:

  • 約15分

  • IDE

  • JDK 17+がインストールされ、 JAVA_HOME が適切に設定されていること

  • Apache Maven 3.9.9

  • 動作するコンテナランタイム(Docker, Podman)

  • 使用したい場合は、 Quarkus CLI

  • ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること

  • Kubernetesクラスターへのアクセス(Minikubeは有効な選択肢です)

アーキテクチャ

このガイドでは、Kubernetes クラスターにデプロイされたいくつかのコンポーネントを使用します。

  • シンプルな Blue サービス。

  • シンプルな Red サービスです。

  • color-service は、Blue と Red のインスタンスへのエントリーポイントとなる Kubernetes サービスです。

  • REST クライアントを使用して、Blue または Red サービスを呼び出すクライアントサービス。サービスの検出と選択は Stork に委譲されます。

Architecture of the application

簡単にするために、すべてが Kubernetes クラスターの同じ名前空間にデプロイされます。

ソリューション

次のセクションの指示に従って、段階的にアプリケーションを作成することをお勧めします。しかし、完成した例をすぐに見ることもできます。

Clone the Git repository: git clone https://github.com/quarkusio/quarkus-quickstarts.git, or download an archive.

ソリューションは stork-kubernetes-quickstart ディレクトリ にあります。

ディスカバリーとセレクション

その前に、ディスカバリーとセレクションについて説明する必要があります。

  • サービスディスカバリーとは、サービスインスタンスを探すプロセスのことです。サービス・ディスカバリーでは、サービス・インスタンスのリストが作成されます。このリストは、(リクエストにマッチするサービスがない場合)空の可能性もあれば、複数のサービス・インスタンスを含む可能性もあります。

  • サービスセレクションはロードバランスとも呼ばれ、ディスカバリープロセスから返されたリストの中から最適なインスタンスを選択します。その結果、1つのサービスインスタンスになるか、適切なインスタンスが見つからない場合は例外となります。

Storkはディスカバリーとセレクションの両方を扱います。しかし、サービスとの通信は処理せず、サービスインスタンスを提供するだけです。Quarkusの様々な統合機能は、そのサービスインスタンスからサービスの場所を抽出します。

プロジェクトのブートストラップ

quarkus-rest-clientとquarkus-rest extensionsをインポートして、Quarkusプロジェクトを作成します:

コマンドラインインタフェース
quarkus create app org.acme:stork-kubernetes-quickstart \
    --extension='quarkus-rest-client,quarkus-rest' \
    --no-code
cd stork-kubernetes-quickstart

Gradleプロジェクトを作成するには、 --gradle または --gradle-kotlin-dsl オプションを追加します。

Quarkus CLIのインストールと使用方法の詳細については、 Quarkus CLI ガイドを参照してください。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.17.2:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=stork-kubernetes-quickstart \
    -Dextensions='quarkus-rest-client,quarkus-rest' \
    -DnoCode
cd stork-kubernetes-quickstart

Gradleプロジェクトを作成するには、 -DbuildTool=gradle または -DbuildTool=gradle-kotlin-dsl オプションを追加します。

Windowsユーザーの場合:

  • cmdを使用する場合、(バックスラッシュ \ を使用せず、すべてを同じ行に書かないでください)。

  • Powershellを使用する場合は、 -D パラメータを二重引用符で囲んでください。例: "-DprojectArtifactId=stork-kubernetes-quickstart"

生成されたプロジェクトに、以下の依存関係を追加します:

pom.xml
<dependency>
    <groupId>io.smallrye.stork</groupId>
    <artifactId>stork-service-discovery-kubernetes</artifactId>
</dependency>
<dependency>
      <groupId>io.smallrye.stork</groupId>
      <artifactId>stork-load-balancer-random</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-kubernetes</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-container-image-jib</artifactId>
</dependency>
build.gradle
implementation("io.smallrye.stork:stork-service-discovery-kubernetes")
implementation("io.smallrye.stork:stork-load-balancer-random")
implementation("io.quarkus:quarkus-kubernetes")
implementation("io.quarkus:quarkus-kubernetes-client")
implementation("io.quarkus:quarkus-container-image-jib")

stork-service-discovery-kubernetes provides an implementation of service discovery for Kubernetes. stork-load-balancer-random provides an implementation of random load balancer. quarkus-kubernetes enables the generation of Kubernetes manifests each time we perform a build. The quarkus-kubernetes-client extension enables the use of the Fabric8 Kubernetes Client in native mode. And quarkus-container-image-jib enables the build of a container image using Jib.

ブルーサービスとレッドサービス

一番最初から始めましょう:私たちが発見(ディスカバリー)し、選択(セレクション)し、呼び出すサービスです。

レッドとブルーは、それぞれ Hello from Red!Hello from Blue! に応答するエンドポイントを提供する2つの単純なRESTサービスです。両方のアプリケーションのコードは、 入門ガイド に従って開発されています。

このガイドの目的は Stork Kubernetes サービス検出の使用方法を示すことであるため、Red および Blue サービスに関する具体的な手順は説明しません。コンテナーイメージはすでにビルドされており、パブリックレジストリーで利用可能です。

Kubernetes での Blue および Red サービスのデプロイ

パブリックレジストリーでサービスコンテナーイメージを使用できるようになりました。次に、それらを Kubernetes クラスターにデプロイする必要があります。

以下のファイルには、Blue と Red のサービスをクラスターにデプロイし、アクセス可能にするために必要な Kubernetes リソースがすべて含まれています。

kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  namespace: development
  name: endpoints-reader
rules:
  - apiGroups: [""] # "" indicates the core API group
    resources: ["endpoints", "pods"]
    verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: stork-rb
  namespace: development
subjects:
  - kind: ServiceAccount
    # Reference to upper's `metadata.name`
    name: default
    # Reference to upper's `metadata.namespace`
    namespace: development
roleRef:
  kind: Role
  name: endpoints-reader
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: v1
kind: Service
metadata:
  annotations:
    app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
    app.quarkus.io/build-timestamp: 2022-03-31 - 10:36:56 +0000
  labels:
    app.kubernetes.io/name: color-service
    app.kubernetes.io/version: "1.0"
  name: color-service (1)
spec:
  ports:
    - name: http
      port: 80
      targetPort: 8080
  selector:
    app.kubernetes.io/version: "1.0"
    type: color-service
  type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
    app.quarkus.io/build-timestamp: 2022-03-31 - 10:36:56 +0000
  labels:
    color: blue
    type: color-service
    app.kubernetes.io/name: blue-service
    app.kubernetes.io/version: "1.0"
  name: blue-service (2)
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: blue-service
      app.kubernetes.io/version: "1.0"
  template:
    metadata:
      annotations:
        app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
        app.quarkus.io/build-timestamp: 2022-03-31 - 10:36:56 +0000
      labels:
        color: blue
        type: color-service
        app.kubernetes.io/name: blue-service
        app.kubernetes.io/version: "1.0"
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: quay.io/quarkus/blue-service:1.0
          imagePullPolicy: Always
          name: blue-service
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
---
apiVersion: apps/v1
kind: Deployment
metadata:
  annotations:
    app.quarkus.io/commit-id: 27be03414510f776ca70d70d859b33e134570443
    app.quarkus.io/build-timestamp: 2022-03-31 - 10:38:54 +0000
  labels:
    color: red
    type: color-service
    app.kubernetes.io/version: "1.0"
    app.kubernetes.io/name: red-service
  name: red-service (2)
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/version: "1.0"
      app.kubernetes.io/name: red-service
  template:
    metadata:
      annotations:
        app.quarkus.io/commit-id: 27be03414510f776ca70d70d859b33e134570443
        app.quarkus.io/build-timestamp: 2022-03-31 - 10:38:54 +0000
      labels:
        color: red
        type: color-service
        app.kubernetes.io/version: "1.0"
        app.kubernetes.io/name: red-service
    spec:
      containers:
        - env:
            - name: KUBERNETES_NAMESPACE
              valueFrom:
                fieldRef:
                  fieldPath: metadata.namespace
          image: quay.io/quarkus/red-service:1.0
          imagePullPolicy: Always
          name: red-service
          ports:
            - containerPort: 8080
              name: http
              protocol: TCP
---
apiVersion: networking.k8s.io/v1
kind: Ingress (3)
metadata:
  annotations:
    app.quarkus.io/commit-id: f747f359406bedfb1a39c57392a5b5a9eaefec56
    app.quarkus.io/build-timestamp: 2022-03-31 - 10:46:19 +0000
  labels:
    app.kubernetes.io/name: color-service
    app.kubernetes.io/version: "1.0"
    color: blue
    type: color-service
  name: color-service
spec:
  rules:
    - host: color-service.127.0.0.1.nip.io
      http:
        paths:
          - backend:
              service:
                name: color-service
                port:
                  name: http
            path: /
            pathType: Prefix

このリストには興味深い点がいくつかあります。

1 Stork が検出する Kubernetes Service リソースである color-service
2 Kubernetes サービスである color-service の背後にある Red と Blue のサービスインスタンス。
3 Kubernetes Ingressリソースで、クラスタの外部から color-service.127.0.0.1.nip.io urlで color-service をアクセス可能にします。IngressはStorkには必要ありませんが、アーキテクチャが整っているか確認するのに役立ちます。

プロジェクトのルートに上記の内容で kubernetes-setup.yml というファイルを作成し、以下のコマンドを実行して Kubernetes クラスターにすべてのリソースをデプロイしてください。専用の名前空間を作成することを忘れないでください。

kubectl create namespace development
kubectl apply -f kubernetes-setup.yml -n=development

すべてがうまくいった場合、http://color-service.127.0.0.1.nip.io で Color サービスにアクセスできます。Hello from Red!Hello from Blue! の応答がランダムに表示されるはずです。

Stork は Kubernetes に限定されず、他のサービス検出メカニズムと統合されます。

REST クライアントインターフェイスとフロントエンド API

ここまでのところ Storkは使用していません。これから検出、選択、呼び出しを行うサービスをデプロイしました。

REST Clientを使ってサービスを呼び出します。 以下の内容で src/main/java/org/acme/MyService.java ファイルを作成します:

package org.acme;

import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

/**
 * The REST Client interface.
 *
 * Notice the `baseUri`. It uses `stork://` as URL scheme indicating that the called service uses Stork to locate and
 * select the service instance. The `my-service` part is the service name. This is used to configure Stork discovery
 * and selection in the `application.properties` file.
 */
@RegisterRestClient(baseUri = "stork://my-service")
public interface MyService {

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    String get();
}

これは、単一のメソッドを含む単純なRESTクライアント・インターフェイスです。ただし、 baseUri 属性に注意してください: * stork:// という接尾辞は、サービスインスタンスのディスカバリとセレクションを Stork に委ねるよう REST クライアントに指示します。 * URI の my-service 部分は、アプリケーション設定で使用するサービス名です。

RESTクライアントの使用方法を変更するものではありません。以下の内容で src/main/java/org/acme/FrontendApi.java ファイルを作成します。

package org.acme;

import org.eclipse.microprofile.rest.client.inject.RestClient;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;

/**
 * A frontend API using our REST Client (which uses Stork to locate and select the service instance on each call).
 */
@Path("/api")
public class FrontendApi {

    @RestClient MyService service;

    @GET
    @Produces(MediaType.TEXT_PLAIN)
    public String invoke() {
        return service.get();
    }

}

通常通り、RESTクライアントを注入して使用します。

Stork の設定

次に、Kubernetes を使用してサービスの Blue と Red のインスタンスを検出するように Stork を設定する必要があります。

src/main/resources/application.properties に以下を追加します:

quarkus.stork.my-service.service-discovery.type=kubernetes
quarkus.stork.my-service.service-discovery.k8s-namespace=development
quarkus.stork.my-service.service-discovery.application=color-service
quarkus.stork.my-service.load-balancer.type=random

stork.my-service.service-discovery は、my-service サービスを見つけるために使用するサービス検出のタイプを示します。ここでは kubernetes です。Kubernetes クラスターへのアクセスが Kube 設定ファイルを介して設定されている場合、それへのアクセスを設定する必要はありません。それ以外の場合は、quarkus.stork.my-service.service-discovery.k8s-host プロパティーを使用して適切な Kubernetes URL を設定します。quarkus.stork.my-service.service-discovery.application には、Stork が要求する Kubernetes サービスの名前が含まれています。ここでは、Red および Blue インスタンスによってサポートされる kubernetes サービスに対応する color-service です。最後に、quarkus.stork.my-service.load-balancer.type でサービスの選択を設定します。ここでは、random ロードバランサーを使用します。

Kubernetes クラスター へのREST Client インターフェイスおよびフロントエンド API のデプロイ

システムはほぼ完成しています。あとは REST Client インターフェイスとクライアントサービスをクラスターにデプロイするだけです。src/main/resources/application.properties に以下を追加します:

quarkus.container-image.registry=<public registry>
quarkus.kubernetes-client.trust-certs=true
quarkus.kubernetes.ingress.expose=true
quarkus.kubernetes.ingress.host=my-service.127.0.0.1.nip.io

quarkus.container-image.registry には、使用するコンテナーレジストリーが含まれています。quarkus.kubernetes.ingress.expose は、サービスがクラスターの外部からアクセスできることを示します。quarkus.kubernetes.ingress.host には、サービスにアクセスするための URL が含まれています。IP アドレスのマッピングには nip.io ワイルドカードを使用しています。

よりカスタマイズされた設定については、 Kubernetesへのデプロイガイド を参照してください。

コンテナーイメージのビルドとプッシュ

ここで使用しているエクステンションにより、Jib を使用してコンテナーイメージのビルドを実行でき、アプリケーションのビルド中に Kubernetes マニフェストを生成することもできます。たとえば、次のコマンドは、target/kubernetes/ ディレクトリーに Kubernetes マニフェストを生成し、プロジェクトのコンテナーイメージをビルドしてプッシュします。

./mvnw package -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true

Kubernetes クラスターへのクライアントサービスのデプロイ

生成されたマニフェストは、kubectl を使用してプロジェクトのルートからクラスターに適用することができます。

kubectl apply -f target/kubernetes/kubernetes.yml -n=development

Stork で楕円曲線キーを使用すると java.lang.ClassNotFoundException: org.bouncycastle.jce.provider.BouncyCastleProvider のような例外が発生する場合は、BouncyCastle PKIX 依存関係 (org.bouncycastle:bcpkix-jdk18on) を追加する必要があります。

内部では、org.bouncycastle.jce.provider.BouncyCastleProvider プロバイダーがまだ登録されていない場合、それが登録されます。

BouncyCastle または BouncyCastle FIPS セクションの説明に従って、このプロバイダーを登録できます。

できました!では、実際に動くかどうか見てみましょう。

ブラウザーを開き、http://my-service.127.0.0.1.nip.io/api に移動します。

または、必要に応じて、別のターミナルで次を実行します:

> curl http://my-service.127.0.0.1.nip.io/api
...
> curl http://my-service.127.0.0.1.nip.io/api
...
> curl http://my-service.127.0.0.1.nip.io/api
...

応答は、Hello from Red!Hello from Blue! のいずれかがランダムに表示されます。

このアプリケーションをネイティブ実行可能ファイルにコンパイルして、起動することができます。

コマンドラインインタフェース
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

次に、ネイティブ実行可能ファイルに基づいてコンテナーイメージを構築する必要があります。これには、対応する Dockerfile を使用します:

> docker build -f src/main/docker/Dockerfile.native -t quarkus/stork-kubernetes-quickstart .

新しいイメージをコンテナーレジストリーに公開した後、Kubernetes マニフェストをクラスターに再デプロイできます。

さらに詳しく

このガイドでは、SmallRye Storkを使ってサービスを発見し、選択する方法を紹介しました。Storkについては、以下のページで詳しく紹介しています:

関連コンテンツ