Kubernetesクライアント
Quarkusには、 Fabric8 Kubernetesクライアント をネイティブモードで使用できるようにする kubernetes-client エクステンションが含まれています。
Kubernetes Operatorのパワーを引き出すためには、QuarkusにKubernetesクライアントエクステンションがあると非常に便利です。Kubernetes Operatorは、クラウドネイティブアプリケーションの新しい種類として急速に台頭してきています。これらのアプリケーションは、基本的にKubernetes APIを監視し、様々なリソースの変更に反応し、データベースやメッセージングシステムなど、あらゆる種類の複雑なシステムのライフサイクルを管理するために使用することができます。ネイティブイメージが提供する非常に低いフットプリントで、このようなOperatorをJavaで書くことができるということは、非常にマッチしています。
設定
Quarkusプロジェクトを設定したら、プロジェクトのベースディレクトリーで次のコマンドを実行して、 kubernetes-client エクステンションをプロジェクトに追加できます。
quarkus extension add kubernetes-client
./mvnw quarkus:add-extension -Dextensions='kubernetes-client'
./gradlew addExtension --extensions='kubernetes-client'
これにより、 pom.xml に以下が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
implementation("io.quarkus:quarkus-kubernetes-client")
使用方法
Quarkusは、よく知られたCDIメソッドを使用してアプリケーションコードに注入できる KubernetesClient タイプのBeanを設定します。このクライアントは、以下の例にあるように、さまざまなプロパティーを使用して設定することができます。
quarkus.kubernetes-client.trust-certs=false
quarkus.kubernetes-client.namespace=default
なお、プロパティの全リストは、 設定リファレンスのDev Servicesセクション にあります。
devモードやテスト実行時には、 Dev Services for Kubernetes が自動的にKubernetes APIサーバーを起動します。
カスタマイズとオーバーライド
Quarkusは、CDI Beanとして提供されるKubernetes Clientに影響を与えるための複数の統合ポイントを提供します。
Kubernetes クライアント設定のカスタマイズ
最初の統合ポイントは、 io.quarkus.kubernetes.client.KubernetesConfigCustomizer インターフェイスの使用です。このようなBeanが存在する場合、Quarkusが作成した io.fabric8.kubernetes.client.Config ( quarkus.kubernetes-client.* のプロパティを考慮します)を任意にカスタマイズすることができます。
あるいは,アプリケーションコードは,単にそれらのBeanのカスタムバージョンを宣言することによって,(通常エクステンションによって提供される) io.fabric8.kubernetes.client.Config ,あるいは io.fabric8.kubernetes.client.KubernetesClient Beanをオーバーライドすることもできます。
この例は、次のスニペットの通りです:
@Singleton
public class KubernetesClientProducer {
@Produces
public KubernetesClient kubernetesClient() {
// here you would create a custom client
return new DefaultKubernetesClient();
}
}
KubernetesクライアントObjectMapperのカスタマイズ
Fabric8 Kubernetes Clientは、Kubernetesリソースのシリアライズとデシリアライズのために独自の ObjectMapper インスタンスを使用します。このマッパーは、 KubernetesClient Beanに注入された KubernetesSerialization インスタンスを通してクライアントに提供されます。
何らかの理由で、このエクステンションによって提供され、Kubernetes Clientによって使用されるデフォルトの ObjectMapper Beanをカスタマイズする必要がある場合は、 KubernetesClientObjectMapperCustomizer インターフェイスを実装するBeanを宣言することでカスタマイズできます。
次のコード・スニペットには、 ObjectMapper ロケールを設定する KubernetesClientObjectMapperCustomizer の例が含まれています:
@Singleton
public static class Customizer implements KubernetesClientObjectMapperCustomizer {
@Override
public void customize(ObjectMapper objectMapper) {
objectMapper.setLocale(Locale.ROOT);
}
}
さらに、エクステンションが自動的に作成する Kubernetes Client が使用するデフォルトの ObjectMapper Bean を置き換える必要がある場合は、 @KubernetesClientObjectMapper 型の Bean を宣言することで置き換えることができます。次のコードスニペットは、このBeanを宣言する方法を示しています:
@Singleton
public class KubernetesObjectMapperProducer {
@KubernetesClientObjectMapper
@Singleton
@Produces
public ObjectMapper kubernetesClientObjectMapper() {
return new ObjectMapper();
}
}
静的な io.fabric8.kubernetes.client.utils.Serialization utils クラスは非推奨であり、使用すべきではありません。 Serialization.jsonMapper() へのアクセスは、 @KubernetesClientObjectMapperCustomizer で宣言された Bean の使用に置き換える必要があります。
|
テスト
モックのKubernetes APIに対するテストを非常に簡単にするために、Quarkusでは、Kubernetes APIサーバーのモックを自動的に起動し、Kubernetesクライアントがそのモックを使用するように設定するために必要な適切な環境変数を設定する KubernetesMockServerTestResource を提供しています。テストは、 @MockServer アノテーションを使用して、特定のテストに必要な方法でモックを注入し、設定することができます。
このようにRESTエンドポイントが定義されているとします。
@Path("/pod")
public class Pods {
private final KubernetesClient kubernetesClient;
public Pods(KubernetesClient kubernetesClient) {
this.kubernetesClient = kubernetesClient;
}
@GET
@Path("/{namespace}")
public List<Pod> pods(String namespace) {
return kubernetesClient.pods().inNamespace(namespace).list().getItems();
}
}
このエンドポイントのテストは次のように簡単に書けます。
// you can even configure aspects like crud, https and port on this annotation
@WithKubernetesTestServer
@QuarkusTest
public class KubernetesClientTest {
@KubernetesTestServer
KubernetesServer mockServer;
@Inject
KubernetesClient client;
@BeforeEach
public void before() {
final Pod pod1 = new PodBuilder().withNewMetadata().withName("pod1").withNamespace("test").and().build();
final Pod pod2 = new PodBuilder().withNewMetadata().withName("pod2").withNamespace("test").and().build();
// Set up Kubernetes so that our "pretend" pods are created
client.pods().resource(pod1).create();
client.pods().resource(pod2).create();
}
@Test
public void testInteractionWithAPIServer() {
RestAssured.when().get("/pod/test").then()
.body("size()", is(2));
}
}
これらの機能を利用するには、例えば次のように quarkus-test-kubernetes-client 依存関係を追加する必要があることに注意してください。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-kubernetes-client</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.quarkus:quarkus-test-kubernetes-client")
デフォルトでは、モックサーバはCRUDモードになっているので、アプリケーションがステートを取得する前に、クライアントを使ってステートを構築する必要がありますが、非CRUDモードに設定して、KubernetesへのすべてのHTTPリクエストをモックすることもできます。
// you can even configure aspects like crud, https and port on this annotation
@WithKubernetesTestServer(crud = false)
@QuarkusTest
public class KubernetesClientTest {
@KubernetesTestServer
KubernetesServer mockServer;
@BeforeEach
public void before() {
final Pod pod1 = new PodBuilder().withNewMetadata().withName("pod1").withNamespace("test").and().build();
final Pod pod2 = new PodBuilder().withNewMetadata().withName("pod2").withNamespace("test").and().build();
// Mock any HTTP request to Kubernetes pods so that our pods are returned
mockServer.expect().get().withPath("/api/v1/namespaces/test/pods")
.andReturn(200,
new PodListBuilder().withNewMetadata().withResourceVersion("1").endMetadata().withItems(pod1, pod2)
.build())
.always();
}
@Test
public void testInteractionWithAPIServer() {
RestAssured.when().get("/pod/test").then()
.body("size()", is(2));
}
}
また、 @WithKubernetesTestServer アノテーションの setup 属性を使用して、 KubernetesServer インスタンスを設定するクラスを提供することもできます。
@WithKubernetesTestServer(setup = MyTest.Setup.class)
@QuarkusTest
public class MyTest {
public static class Setup implements Consumer<KubernetesServer> {
@Override
public void accept(KubernetesServer server) {
server.expect().get().withPath("/api/v1/namespaces/test/pods")
.andReturn(200, new PodList()).always();
}
}
// tests
}
または、 `KubernetesServerTestResource`クラスの拡張を作成して、 ` @ QuarkusTest`が有効なすべてのテストクラスが `QuarkusTestResource`アノテーションを介して同じモックサーバーセットアップを共有するようにすることもできます。
public class CustomKubernetesMockServerTestResource extends KubernetesServerTestResource {
@Override
protected void configureServer() {
super.configureServer();
server.expect().get().withPath("/api/v1/namespaces/test/pods")
.andReturn(200, new PodList()).always();
}
}
そして、これを次のように他のテストクラスで使用します。
@QuarkusTestResource(CustomKubernetesMockServerTestResource.class)
@QuarkusTest
public class KubernetesClientTest {
//tests will now use the configured server...
}
ジェネリック型の実装または拡張に関する注意
GraalVMによって課せられた制限のため、アプリケーションがネイティブモードで動作することを意図している場合、 クライアントによって提供されるジェネリック型を実装または拡張する際には特別な注意が必要です。基本的に、 Watcher、 ` ResourceHandler`、 CustomResource`などのジェネリッククラスのすべての実装または拡張は、クラス定義時に関連するKubernetesモデルクラス(または、 ` CustomResource の場合は通常のJavaタイプ)を指定する必要があります。 よく理解するために、例えばKubernetesの Pod`リソースへの変更を監視するとします。 ネイティブでの動作が保証されているこのような `Watcher を作成するには、いくつかの方法があります。
client.pods().watch(new Watcher<Pod>() {
@Override
public void eventReceived(Action action, Pod pod) {
// do something
}
@Override
public void onClose(KubernetesClientException e) {
// do something
}
});
または
public class PodResourceWatcher implements Watcher<Pod> {
@Override
public void eventReceived(Action action, Pod pod) {
// do something
}
@Override
public void onClose(KubernetesClientException e) {
// do something
}
}
...
client.pods().watch(new PodResourceWatcher());
以下の例のようにクラス階層を介してジェネリック型を定義した場合も、正しく動作することに注目してください。
public abstract class MyWatcher<S> implements Watcher<S> {
}
...
client.pods().watch(new MyWatcher<Pod>() {
@Override
public void eventReceived(Action action, Pod pod) {
// do something
}
});
| 以下の例では、クラスやメソッドの定義を見てウォッチャーのジェネリック型を判断できないため、Quarkusはリフレクション登録が必要なKubernetesモデルクラスを適切に判断できないため、ネイティブモードでは動作 しません 。 |
public class ResourceWatcher<T extends HasMetadata> implements Watcher<T> {
@Override
public void eventReceived(Action action, T resource) {
// do something
}
@Override
public void onClose(KubernetesClientException e) {
// do something
}
}
client.pods().watch(new ResourceWatcher<Pod>());
楕円曲線鍵使用時の注意点
なお、Kubernetes Clientで楕円曲線鍵を使用したい場合は、BouncyCastle PKIXの依存関係を追加する必要があります:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
</dependency>
implementation("org.bouncycastle:bcpkix-jdk18on")
なお、内部的には、 org.bouncycastle.jce.provider.BouncyCastleProvider プロバイダーがまだ登録されていない場合に登録されます。
BouncyCastleまたは BouncyCastle FIPSのセクションで説明したように、このプロバイダーを登録させることができます。
Kubernetes APIへのアクセス
多くの場合、Kubernetes API サーバーにアクセスするには ServiceAccount 、 Role 、 RoleBinding が必要になります。すべてのPodをリスト可能な例は以下のようになります。
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: <applicationName>
namespace: <namespace>
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: <applicationName>
namespace: <namespace>
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: <applicationName>
namespace: <namespace>
roleRef:
kind: Role
name: <applicationName>
apiGroup: rbac.authorization.k8s.io
subjects:
- kind: ServiceAccount
name: <applicationName>
namespace: <namespace>
<applicationName> と <namespace> は値に置き換えてください。 PodのService Accountの設定 を参照して、詳細な情報を入手してください。
OpenShiftクライアント
対象となるKubernetesクラスターがOpenShiftクラスターであれば、同様の方法で、 openshift-client エクステンションを利用してアクセスすることが可能です。これは専用の fabric8 openshift クライアントを利用し、 OpenShift 固有のオブジェクト(例: Route , ProjectRequest , BuildConfig …)へのアクセスを提供します。
設定プロパティーは kubernetes-client エクステンションと共有されていることに注意してください。特に、これらは同じ quarkus.kubernetes-client プレフィックスを持っています。
以下のコマンドでエクステンションを追加します。
quarkus extension add openshift-client
./mvnw quarkus:add-extension -Dextensions='openshift-client'
./gradlew addExtension --extensions='openshift-client'
openshift-client エクステンションは kubernetes-client エクステンションに依存していることに注意してください。
クライアントを使用するには、 KubernetesClient の代わりに OpenShiftClient を注入します。
@Inject
private OpenShiftClient openshiftClient;
デフォルトの OpenShiftClient を上書きする必要がある場合は、次のようなプロデューサーを提供してください。
@Singleton
public class OpenShiftClientProducer {
@Produces
public OpenShiftClient openshiftClient() {
// here you would create a custom client
return new DefaultOpenShiftClient();
}
}
前節で説明した @WithKubernetesTestServer を使用することで、同様の方法でモック・サポートも提供されます:
@WithKubernetesTestServer
@QuarkusTest
public class OpenShiftClientTest {
@KubernetesTestServer
KubernetesServer mockServer;
@Inject
OpenShiftClient client;
@Test
public void testInteractionWithAPIServer() {
RestAssured.when().get("/route/test").then()
.body("size()", is(2));
}
}
この機能を使うには、 quarkus-test-kubernetes-client への依存関係を追加する必要があります:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-kubernetes-client</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.quarkus:quarkus-test-kubernetes-client")
ネイティブイメージの最適化
Kubernetes および OpenShift クライアントエクステンションは、クライアントが ネイティブモード で動作できるようにしつつ、優れた 開発者エクスペリエンス を提供することを目指しています。ネイティブイメージをビルドする場合、Kubernetes クライアントエクステンションは、アクセス可能なすべての Kubernetes モデルクラスをリフレクション用に登録します。残念ながら、これはネイティブイメージのサイズを大きくし、ビルド時間を長くする可能性があります。
アプリケーションの実装が完了したら、そのアプリケーションを ネイティブイメージ として配布およびデプロイしたい場合、以下のガイドラインに従ってサイズを削減することを検討すべきです。
Kubernetes クライアントエクステンションの使用
OpenShift クライアント は、一般的な OpenShift リソースへのドメイン固有言語 (DSL) アクセサーを提供します。さらに、このエクステンションは、OpenShift モデルタイプモジュールを取り込むために必要なプロジェクト設定を提供します。
JVM モードでは、開発者として設定を気にする必要がないため、これは非常にうまく機能します。しかし、ネイティブモードでは、OpenShift エクステンションに依存することで、アプリケーションが不要な多くのリソースを取り込み、そのサイズを不必要に増加させる可能性があります。
この文脈では、Kubernetes クライアントエクステンションと最小限の OpenShift モデル依存関係のみに依存を追加することで、必要なものだけを依存させる方が良いでしょう。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>openshift-model</artifactId>
</dependency>
implementation("io.quarkus:quarkus-kubernetes-client")
implementation("io.fabric8:openshift-model")
OpenShiftClient の代わりに KubernetesClient 型の Bean を持つことになるため、OpenShift 固有の DSL アクセサーは利用できなくなります。ただし、Fabric8 Kubernetes Client は、あらゆるリソースに対して操作を実行するための汎用的なエントリーポイントを提供します。
// List OpenShift Routes in any namespace
kubernetesClient
.resources(io.fabric8.openshift.api.model.Route.class)
.inAnyNamespace().list();
// Delete an OpenShift Route
kubernetesClient
.resources(io.fabric8.openshift.api.model.Route.class)
.inNamespace("default").withName("the-route").delete();
// Create or replace a new OpenShift Route
kubernetesClient
.resource(new RouteBuilder()/* ... */.build())
.inNamespace("default").createOr(NonDeletingOperation::update);
必要なモジュールのみに依存
Kubernetes クライアントエクステンションは、すべての標準 Kubernetes API モデルタイプへの推移的依存関係を持っています。これは、プロジェクトの設定を気にする必要がないため、JVM モードでは非常に便利です。
しかし、ネイティブモードでは、これはアプリケーションでまず使用しないであろうモデルタイプをリフレクション用に登録することを意味します。よりきめ細かなプロジェクト設定を提供し、アプリケーションが使用すると確信しているモデルのみに依存することで、これを軽減できます。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client-api</artifactId>
<!-- Exclude all transitive dependencies -->
<exclusions>
<exclusion>
<groupId>io.fabric8</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Include only those that make sense for your application -->
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-client</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model-core</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model-admissionregistration</artifactId>
</dependency>
<dependency>
<groupId>io.fabric8</groupId>
<artifactId>kubernetes-model-apps</artifactId>
</dependency>
<!-- ... -->
implementation("quarkus-kubernetes-client")
implementation("io.fabric8:kubernetes-client-api") {
// Exclude all transitive dependencies
exclude group: "io.fabric8"
}
// Include only those that make sense for your application
implementation("io.fabric8:kubernetes-client")
implementation("io.fabric8:kubernetes-model-core")
implementation("io.fabric8:kubernetes-model-admissionregistration")
implementation("io.fabric8:kubernetes-model-apps")
// ...
設定リファレンス
ビルド時に固定される設定プロパティ - 他のすべての設定プロパティは実行時にオーバーライド可能
Configuration property |
型 |
デフォルト |
|---|---|---|
Enable the generation of the RBAC manifests. If enabled and no other role binding are provided using the properties Environment variable: Show more |
boolean |
|
Whether the client should trust a self-signed certificate if so presented by the API server Environment variable: Show more |
boolean |
|
URL of the Kubernetes API server Environment variable: Show more |
string |
|
Default namespace to use Environment variable: Show more |
string |
|
CA certificate file Environment variable: Show more |
string |
|
CA certificate data Environment variable: Show more |
string |
|
Path to a kubeconfig file to use for configuring the client. When set, the file will be read and used as the base configuration. Environment variable: Show more |
string |
|
Client certificate file Environment variable: Show more |
string |
|
Client certificate data Environment variable: Show more |
string |
|
Client key file Environment variable: Show more |
string |
|
Client key data Environment variable: Show more |
string |
|
Client key algorithm Environment variable: Show more |
string |
|
Client key passphrase Environment variable: Show more |
string |
|
Kubernetes auth username Environment variable: Show more |
string |
|
Kubernetes auth password Environment variable: Show more |
string |
|
Kubernetes oauth token Environment variable: Show more |
string |
|
Watch reconnect interval Environment variable: Show more |
||
Maximum reconnect attempts in case of watch failure By default there is no limit to the number of reconnect attempts Environment variable: Show more |
int |
|
Maximum amount of time to wait for a connection with the API server to be established Environment variable: Show more |
||
Maximum amount of time to wait for a request to the API server to be completed Environment variable: Show more |
||
Maximum number of retry attempts for API requests that fail with an HTTP code of >= 500 Environment variable: Show more |
int |
|
Time interval between retry attempts for API requests that fail with an HTTP code of >= 500 Environment variable: Show more |
||
HTTP proxy used to access the Kubernetes API server Environment variable: Show more |
string |
|
HTTPS proxy used to access the Kubernetes API server Environment variable: Show more |
string |
|
Proxy username Environment variable: Show more |
string |
|
Proxy password Environment variable: Show more |
string |
|
IP addresses or hosts to exclude from proxying Environment variable: Show more |
文字列のリスト |
|
型 |
デフォルト |
|
If Dev Services for Kubernetes should be used. (default to true) If this is true and kubernetes client is not configured then a kubernetes cluster will be started and will be used. Environment variable: Show more |
boolean |
|
The kubernetes api server version to use. If not set, Dev Services for Kubernetes will use the latest supported version of the given flavor. Environment variable: Show more |
string |
|
The kubernetes image to use. If not set, Dev Services for Kubernetes will use default image for the specified Environment variable: Show more |
string |
|
The flavor to use (kind, k3s or api-only). If not set, Dev Services for Kubernetes will set it to: api-only. Environment variable: Show more |
|
|
By default, if a kubeconfig is found, Dev Services for Kubernetes will not start. Set this to true to override the kubeconfig config. Environment variable: Show more |
boolean |
|
A list of manifest file paths that should be applied to the Kubernetes cluster Dev Service on startup. If not set, no manifests are applied. Environment variable: Show more |
文字列のリスト |
|
Indicates if the Kubernetes cluster managed by Quarkus Dev Services is shared. When shared, Quarkus looks for running containers using label-based service discovery. If a matching container is found, it is used, and so a second one is not started. Otherwise, Dev Services for Kubernetes starts a new container. The discovery uses the Container sharing is only used in dev mode. Environment variable: Show more |
boolean |
|
The value of the This property is used when you need multiple shared Kubernetes clusters. Environment variable: Show more |
string |
|
Environment variables that are passed to the container. Environment variable: Show more |
Map<String,String> |
|
期間フォーマットについて
期間の値を書くには、標準の 数字で始まる簡略化した書式を使うこともできます:
その他の場合は、簡略化されたフォーマットが解析のために
|