1、pom.xml文件中引入依赖
<!--k8s相关jar包-->
<dependency>
<groupId>io.kubernetes</groupId>
<artifactId>client-java</artifactId>
<version>8.0.2</version>
<scope>compile</scope>
</dependency>
2、逻辑流程
大致流程
* 1)创建一个命名空间
* 2)根据资源对象文件创建deployment,创建多个副本,并指定自定义调度器
* 3)通过API获取节点和pod
* 4)选择phase=pending和schedulerName=my-scheduler的pod
* 5)然后通过自定义的调度算法(这里只采用随机数的方法)计算出pod的合适目标节点。并使用Binding对象去绑定。
3、配置连接k8s
4、项目工程目录如下
只需要关注config文件、myScheduler包、uitl包即可。
5、util包中工具类是配置连接客户端
package com.example.demo.util;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.auth.ApiKeyAuth;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import java.io.FileReader;
import java.io.IOException;
/**
* 配置信息
*/
public class Config {
// 返回client
// 默认使用这个方法
public static ApiClient defaultClient() throws IOException {
String kubeConfigPath = "config";
//
ApiClient client =
ClientBuilder.kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath))).build();
return client;
}
}
6、在主类中实现,具体代码如下
package com.example.demo.myScheduler;
import com.example.demo.util.Config;
import io.kubernetes.client.ProtoClient;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.AppsV1beta1Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.apis.ExtensionsV1beta1Api;
import io.kubernetes.client.openapi.models.*;
import io.kubernetes.client.proto.Meta;
import io.kubernetes.client.proto.V1;
import io.kubernetes.client.util.Yaml;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Random;
/**
* 大致流程
* 1)创建一个命名空间
* 2)根据资源对象文件创建deployment,创建多个副本,并指定自定义调度器
* 3)通过API获取节点和pod
* 4)选择phase=pending和schedulerName=my-scheduler的pod
* 5)然后通过自定义的调度算法(这里只采用随机数的方法)计算出pod的合适目标节点。并使用Binding对象去绑定。
*/
public class myScheduler {
public static File deploymentFile = new File("test-scheduler.yaml");
public static void main(String[] args) throws IOException, ApiException {
String namespaceStr = "shiyan";
// 配置client
ApiClient client = Config.defaultClient();
Configuration.setDefaultApiClient(client);
AppsV1Api apiInstance = new AppsV1Api(client);
CoreV1Api api = new CoreV1Api(client);
ProtoClient protoClient = new ProtoClient(client);
// 创建命名空间和deployment
//createNameSpaceAndDepoyment(namespaceStr,apiInstance,protoClient);
// 通过api获得节点和pod,并完成预选,优选的过程
//getNodeAndPod(namespaceStr,api,client);
// 删除deployment
//deleteDeploymentByYaml(apiInstance,namespaceStr);
}
/**
* 删除对应的deployment
* @param api
* @param namespaceStr
*/
private static void deleteDeploymentByYaml(AppsV1Api api, String namespaceStr) throws ApiException {
// 传入deployment的名字,命名空间,就可以删除deployment以及所有的pod了
V1Status v1Status = api.deleteNamespacedDeployment("pause",namespaceStr,null,null,null,null,null,null);
System.out.println(v1Status.getCode()+"删除完毕");
}
/**
* 获得可用节点和判断pod的状态完成绑定
* @param namespaceStr
* @param api
* @param client
* @throws ApiException
*/
private static void getNodeAndPod(String namespaceStr, CoreV1Api api, ApiClient client) throws ApiException {
Random random = new Random();
// 调用方法,计算出所有可用的节点
// 预选
V1NodeList nodeList = ready_node(api);
// 通过api获取指定命名空间(shiyan)中的pod
V1PodList list = api.listNamespacedPod(namespaceStr,null,null,null,null,null,null,null, null, null);
// 遍历list,循环判断pod的状态,并完成pod的调度
for(V1Pod item:list.getItems()){
// 优选
int n = random.nextInt(nodeList.getItems().size());
// 获取pod的状态
String podStatus = item.getStatus().getPhase();
String nodeName = item.getSpec().getNodeName();
// 根据pod的状态和所属节点的名称进行绑定
if (podStatus.equals("Pending") && nodeName == null){
// 执行调度方法 pod的名字;可用node;命名空间;客户端;api
schedluer(item.getMetadata().getName(),nodeList.getItems().get(n),namespaceStr,client,api);
}
}
}
/**
* binding 绑定的过程
* @param name
* @param v1Node
* @param namespaceStr
* @param client
* @param api
* @throws ApiException
*/
private static void schedluer(String name, V1Node v1Node, String namespaceStr, ApiClient client, CoreV1Api api) throws ApiException {
V1Binding body = new V1Binding();
V1ObjectReference target = new V1ObjectReference();
V1ObjectMeta meta = new V1ObjectMeta();
target.setKind("Node");
target.setApiVersion("v1");
target.setName(v1Node.getMetadata().getName()); // 节点的名称
meta.setName(name);
body.setTarget(target);
body.setMetadata(meta);
api.createNamespacedBinding(namespaceStr,body,null,null,null);
}
/**
* 获得可用的node,这个方法相当于预选阶段
* @param api
* @return
* @throws ApiException
*/
private static V1NodeList ready_node(CoreV1Api api) throws ApiException {
// 定义list装所有符合条件的节点
V1NodeList nodeSelectList = new V1NodeList();
// 通过api获取所有的节点
V1NodeList nodeList = api.listNode(null,null,null,null,null,null,null,null,null);;
// 遍历,找出能用的node,存进list中去
for (V1Node node:nodeList.getItems()){
List<V1NodeCondition> conditionsList = node.getStatus().getConditions();
// 取出最后一个
String status = conditionsList.get(conditionsList.size()-1).getStatus();
String type = conditionsList.get(conditionsList.size()-1).getType();
// 这里的预选策略相当于就是判断node节点的两个状态值
if (status.equals("True")&&type.equals("Ready")){
nodeSelectList.addItemsItem(node);
}
}
// 返回所有符合条件的节点
return nodeSelectList;
}
/**
* 创建命名空间和通过deployment资源对象文件来创建deployment
* @param namespaceStr
* @param apiInstance
* @param protoClient
* @throws IOException
* @throws ApiException
*/
private static void createNameSpaceAndDepoyment(String namespaceStr, AppsV1Api apiInstance, ProtoClient protoClient) throws IOException, ApiException {
// 1、创建一个命名空间 shiyan
V1.Namespace namespace =
V1.Namespace.newBuilder().setMetadata(Meta.ObjectMeta.newBuilder().setName(namespaceStr).build()).build();
protoClient.create(namespace,"/api/v1/namespaces","v1","Namespace");
// 删除指定的命名空间
//protoClient.delete(V1.Namespace.newBuilder(),"/api/v1/namespaces/"+namespaceStr);
// 2、根据资源对象文件创建deployment,创建多个副本,并指定自定义调度器
// File deploymentFile = new File("test-scheduler.yaml");
V1Deployment body = (V1Deployment) Yaml.load(deploymentFile);
try {
V1Deployment result = apiInstance.createNamespacedDeployment(namespaceStr,body,null,null,null);
System.out.println("success,工作负载创建成功");
}catch (ApiException e){
if (e.getCode() == 409) {
System.out.println("error 工作负载创建已重复!");
} else if (e.getCode() == 200) {
System.out.println("success 工作负载创建成功!");
} else if (e.getCode() == 201) {
System.out.println("error 工作负载创建已重复!");
} else if (e.getCode() == 401) {
System.out.println("error 无权限操作!");
} else {
System.out.println("error 工作负载创建失败!");
}
System.out.println("Exception when calling AppsV1Api#createNamespacedDeployment");
System.out.println("Status code: {}"+ e.getCode());
System.out.println("Reason: {}"+ e.getResponseBody());
System.out.println("Response headers: {}"+ e.getResponseHeaders());
}
}
}
7、用到的deployment资源对象文件也在工程目录的根目录下,其具体的内容如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: pause # 名称
namespace: shiyan #指定命名空间
spec:
replicas: 5 # 副本数
selector:
matchLabels:
app: pause
template:
metadata:
labels:
app: pause
spec:
schedulerName: my-scheduler # 指定自定义的调度器
containers:
- name: pause
image: docker.io/mirrorgooglecontainers/pause:3.1 # 镜像
8、通过java-client操作k8s集群内的资源对象,可以使用命令kubectl get pod -n shiyan(这个是命名空间的名称) 查看所有pod的状态。
补充几条命令:
kubectl get node
kubectl get pod -n shiyan
kubectl describe pod -n shiyan pod的名称
kubectl log pod的名称