Kubernetesクライアント
Quarkusには、 Fabric8 Kubernetesクライアント をネイティブモードで使用できるようにする kubernetes-client
エクステンションが含まれています。
Having a Kubernetes Client extension in Quarkus is very useful in order to unlock the power of Kubernetes Operators. Kubernetes Operators are quickly emerging as a new class of Cloud Native applications. These applications essentially watch the Kubernetes API and react to changes on various resources and can be used to manage the lifecycle of all kinds of complex systems like databases, messaging systems and much more. Being able to write such operators in Java with the very low footprint that native images provide is a great match.
設定
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
プロパティーの完全なリストは、 KubernetesClientBuildConfig クラスで確認できます。
オーバーライド
また、このエクステンションでは、アプリケーションコードは、単にそれらのBeanのカスタムバージョンを宣言することで、通常はエクステンションによって提供される io.fabric8.kubernetes.client.Config
や io.fabric8.kubernetes.client.KubernetesClient
のいずれかをオーバーライドすることができます。
この例は、次のスニペットの通りです:
@Singleton
public class KubernetesClientProducer {
@Produces
public KubernetesClient kubernetesClient() {
// here you would create a custom client
return new DefaultKubernetesClient();
}
}
テスト
モックの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;
@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
mockServer.getClient().pods().create(pod1);
mockServer.getClient().pods().create(pod2);
}
@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>());
Note on using Elliptic Curve keys
Please note that if you would like to use Elliptic Curve keys with Kubernetes Client then adding a BouncyCastle PKIX dependency is required:
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
</dependency>
implementation("org.bouncycastle:bcpkix-jdk15on")
Note that internally an org.bouncycastle.jce.provider.BouncyCastleProvider
provider will be registered if it has not already been registered.
You can have this provider registered as described in the BouncyCastle or BouncyCastle FIPS sections.
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
…)へのアクセスを提供します。
Note that the configuration properties are shared with the kubernetes-client
extension. In particular, they have the same quarkus.kubernetes-client
prefix.
以下のコマンドでエクステンションを追加します。
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();
}
}
モックサポートも同様の方法で提供されています。
@QuarkusTestResource(OpenShiftMockServerTestResource.class)
@QuarkusTest
public class OpenShiftClientTest {
@MockServer
private OpenShiftMockServer mockServer;
...
または、前のセクションで説明した @WithKubernetesTestServer
と同様の @WithOpenShiftTestServer
を使用することによって:
@WithOpenShiftTestServer
@QuarkusTest
public class OpenShiftClientTest {
@OpenShiftTestServer
private OpenShiftServer mockOpenShiftServer;
...
この機能を使用するには、 quarkus-test-openshift-client
に依存関係を追加する必要があります。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-openshift-client</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.quarkus:quarkus-test-openshift-client")
設定リファレンス
ビルド時に固定される設定プロパティ - それ以外の設定プロパティは実行時に上書き可能
タイプ |
デフォルト |
|
---|---|---|
Whether the client should trust a self-signed certificate if so presented by the API server Environment variable: |
boolean |
|
URL of the Kubernetes API server Environment variable: |
string |
|
Default namespace to use Environment variable: |
string |
|
CA certificate file Environment variable: |
string |
|
CA certificate data Environment variable: |
string |
|
Client certificate file Environment variable: |
string |
|
Client certificate data Environment variable: |
string |
|
Client key file Environment variable: |
string |
|
Client key data Environment variable: |
string |
|
Client key algorithm Environment variable: |
string |
|
Client key passphrase Environment variable: |
string |
|
Kubernetes auth username Environment variable: |
string |
|
Kubernetes auth password Environment variable: |
string |
|
Kubernetes oauth token Environment variable: |
string |
|
Watch reconnect interval Environment variable: |
|
|
Maximum reconnect attempts in case of watch failure By default there is no limit to the number of reconnect attempts Environment variable: |
int |
|
Maximum amount of time to wait for a connection with the API server to be established Environment variable: |
|
|
Maximum amount of time to wait for a request to the API server to be completed Environment variable: |
|
|
Maximum amount of time in milliseconds to wait for a rollout to be completed Environment variable: |
|
|
HTTP proxy used to access the Kubernetes API server Environment variable: |
string |
|
HTTPS proxy used to access the Kubernetes API server Environment variable: |
string |
|
Proxy username Environment variable: |
string |
|
Proxy password Environment variable: |
string |
|
IP addresses or hosts to exclude from proxying Environment variable: |
list of string |
|
Enable the generation of the RBAC manifests. Environment variable: |
boolean |
|
期間フォーマットについて
期間のフォーマットは標準の 数値で始まる期間の値を指定することもできます。この場合、値が数値のみで構成されている場合、コンバーターは値を秒として扱います。そうでない場合は、 |