目录

kubernetes中使用java-client完成deployment的部署以及删除

目录

kubernetes中使用java-client完成deployment的部署以及删除

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

https://i-blog.csdnimg.cn/blog_migrate/a0bda327b8641de8d58a1585a87d4858.png

https://i-blog.csdnimg.cn/blog_migrate/be9e25a43a8bf0c0ec10bd7edf562aa4.png

4、项目工程目录如下

https://i-blog.csdnimg.cn/blog_migrate/d33314c70064b53f047317ae8ab4544b.png

只需要关注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 的名称