尝试使用Java运行Kubernetes的作业
以下是简要概述:
实际上,Kubernetes为调用API准备了一个官方的Java封装库,这使得从Java应用程序相对容易地进行Kubernetes操作成为可能。
- https://github.com/kubernetes-client/java
这次我们将尝试用Spring Boot创建一个启动Job的REST API。
环境
-
- Java 8
-
- Spring Boot 1.5.10.RELEASE
- Kubernetes 1.8
这次应用程序的规格或者这个App的特点。
-
- 执行从公式文档中得到的计算pi的作业示例。
-
- 作业的定义从YAML文件中读取。
-
- 由于client-java库使用的是JSON(GSON),因此需要将YAML转换为JSON并进行绑定。
-
- 作业名称将附加日期以保证其唯一性。
- 使用服务账号的Kubernetes配置进行认证。
实施
创建项目
curl -s https://start.spring.io/starter.tgz \
-d baseDir=k8s-job-sample \
-d type=gradle-project \
-d javaVersion=1.8 \
-d dependencies=web,lombok | tar -xzvf -
在 build.gradle 中添加依赖
compile('io.kubernetes:client-java:1.0.0-beta2')
放置工作清单
apiVersion: batch/v1
kind: Job
metadata:
name: pi
spec:
template:
spec:
containers:
- name: pi
image: perl
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(100)"]
restartPolicy: Never
backoffLimit: 4
潤而略味之實物。
package com.example.demo;
import com.google.gson.Gson;
import io.kubernetes.client.ApiClient;
import io.kubernetes.client.apis.BatchV1Api;
import io.kubernetes.client.util.Config;
import java.io.IOException;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor;
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public Gson gson() {
return new Gson();
}
@Bean
public Yaml yaml() {
return new Yaml(new SafeConstructor());
}
@Bean
public ApiClient apiClient() throws IOException {
return Config.fromConfig("/path/to/k8s-config.yaml");
}
@Bean
public BatchV1Api batchV1Api(ApiClient apiClient) {
return new BatchV1Api(apiClient);
}
}
※为了简化,将代码写在Application类中
控制器
package com.example.demo;
import com.google.gson.Gson;
import io.kubernetes.client.ApiException;
import io.kubernetes.client.apis.BatchV1Api;
import io.kubernetes.client.models.V1Job;
import io.kubernetes.client.models.V1ObjectMeta;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.core.io.ResourceLoader;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.yaml.snakeyaml.Yaml;
@RestController
@RequestMapping("jobs")
@RequiredArgsConstructor
public class JobController {
private final BatchV1Api batchApi;
private final ResourceLoader resourceLoader;
private final Gson gson;
private final Yaml yaml;
private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
@PostMapping
public V1Job executeJob(@RequestParam(required = false, defaultValue = "default") String nameSpace)
throws IOException, ApiException {
V1Job job = loadJobFromYaml("job.yaml");
V1ObjectMeta metaData = job.getMetadata();
metaData.setName(String.format("%s-%s", metaData.getName(), dateTimeFormatter.format(LocalDateTime.now())));
return batchApi.createNamespacedJob(nameSpace, job, null);
}
private V1Job loadJobFromYaml(String fileName) throws IOException {
Map jobManifest = (Map) yaml.load(
resourceLoader.getResource(ResourceLoader.CLASSPATH_URL_PREFIX + fileName).getInputStream());
return gson.fromJson(gson.toJson(jobManifest), V1Job.class);
}
}
确认行动
$ curl -X POST http://localhost:8080/jobs?nameSpace=develop