メモ：Kubernetes の Java API を利用した Pod のスケールアップを試してみました

Kubernetes の[Java Client](https://github.com/kubernetes-client/java) というのがあったので、試しに pods のスケール・アウトを実装してみました。

```java
import java.io.IOException;
import io.kubernetes.client.custom.V1Patch;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Deployment;
import io.kubernetes.client.openapi.models.V1PodList;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import io.kubernetes.client.util.PatchUtils;

public class Test{
    // Kubernetes 関連の設定
    private static final int NUMBER_OF_INCREMENT_PODS = 3;
    private final static String JSON_PATCH_STRING_PREFIX = "[{\"op\":\"replace\",\"path\":\"/spec/replicas\",\"value\":";
    private final static String JSON_PATCH_STRING_SUFFIX = "}]";
    private final static String K8S_DEPLOYMENT_NAME = "my-service";
    private final static String K8S_DEPLOYMENT_NAMESPACE = "default";
    private final static String LABEL_SELECTOR = "app=my-service";
    private static Logger LOGGER = Logger.getLogger(ScaleKubernetesInsntace.class.getName());    
    private static final String KUBE_CONFIG_PATH = "$PATH_TO_KUBE_CONFIG/config";

    ...省略

	private void implementScaleUpRequest() {
            try {
				ApiClient apiclient = ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(KUBE_CONFIG_PATH))).build();

                // 現在稼働している Pod 数を取得
                CoreV1Api coreApi = new CoreV1Api(apiclient);
                V1PodList list =
                coreApi.listNamespacedPod(K8S_DEPLOYMENT_NAMESPACE, null, null, null, null, LABEL_SELECTOR, null, null, null, null, null);
                LOGGER.log(Level.INFO, "Number of running pods: " + list.getItems().size());

                // 現在稼働している Pod 数に、NUMBER_OF_INCREMENT_PODS を加算
                int numberOfNewInstances = list.getItems().size() + NUMBER_OF_INCREMENT_PODS;
                AppsV1Api api = new AppsV1Api(apiclient);
                String patchString = JSON_PATCH_STRING_PREFIX + numberOfNewInstances + JSON_PATCH_STRING_SUFFIX;
                // パッチを適用しレプリカ数を増加
                V1Deployment deploy = PatchUtils.patch(V1Deployment.class,
                    () -> 
                        api.patchNamespacedDeploymentCall(
                            K8S_DEPLOYMENT_NAME,
                            K8S_DEPLOYMENT_NAMESPACE,
                            new V1Patch(patchString),
                            null,
                            null,
                            null,
                            null, // field-manager is optional
                            null,
                            null),
                    V1Patch.PATCH_FORMAT_JSON_PATCH,
                    api.getApiClient());
  					LOGGER.log(Level.INFO,"Scale out done. Number of Replicas : " + deploy.getSpec().getReplicas());
            } catch (ApiException | IOException  e) {
                e.printStackTrace();
            }
    }
}
```

上記を利用するために、`pom.xml` ファイルに下記の依存関係を追加しています。

```xml
		<dependency>
			<groupId>io.kubernetes</groupId>
			<artifactId>client-java-api</artifactId>
			<version>16.0.0</version>
		</dependency>
		<dependency>
			<groupId>io.kubernetes</groupId>
			<artifactId>client-java</artifactId>
			<version>16.0.0</version>
		</dependency>
		<dependency>
			<groupId>io.kubernetes</groupId>
			<artifactId>client-java-extended</artifactId>
			<version>16.0.0</version>
		</dependency>
```

仮に jlink でカスタム JRE を作る場合は、`jdk.crypto.ec` を含めてください。含めない場合、API Server に対して SSL で通信する際に失敗するため、こちらをご指定ください。

```bash
 jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.logging,java.naming,java.desktop,java.management,java.security.jgss,jdk.crypto.ec,java.instrument,java.sql --output custom-jre
```