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 に委譲されます。
簡単にするために、すべてが 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プロジェクトを作成します:
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-DprojectArtifactId=stork-kubernetes-quickstart"
生成されたプロジェクトに、以下の依存関係を追加します:
<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>
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 で楕円曲線キーを使用すると 内部では、 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
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
次に、ネイティブ実行可能ファイルに基づいてコンテナーイメージを構築する必要があります。これには、対応する Dockerfile を使用します:
> docker build -f src/main/docker/Dockerfile.native -t quarkus/stork-kubernetes-quickstart .
新しいイメージをコンテナーレジストリーに公開した後、Kubernetes マニフェストをクラスターに再デプロイできます。