DolphinScheduler源码学习之K8S插件代码(将其从源码中单独拿出)

找到任务插件中的k8s那一块,并创建一个项目,将与之相关的类都添加至自己代码中:

大概有这么多,最下面那两个测试类是我自己创建的,用来辅助的

 

 K8s类是让传来的参数进行加工处理,通过BuildCommand方法转换成String类型,用于AbstractK8sTask类中handle方法

@Override
protected String buildCommand() {
    K8sTaskMainParameters k8sTaskMainParameters = new K8sTaskMainParameters();
    Map<String, Property> paramsMap = taskExecutionContext.getPrepareParamsMap();
    Map<String, String> namespace = JSONUtils.toMap(k8sTaskParameters.getNamespace());
    String namespaceName = namespace.get(NAMESPACE_NAME);
    String clusterName = namespace.get(CLUSTER);
    k8sTaskMainParameters.setImage(k8sTaskParameters.getImage());
    k8sTaskMainParameters.setNamespaceName(namespaceName);
    k8sTaskMainParameters.setClusterName(clusterName);
    k8sTaskMainParameters.setMinCpuCores(k8sTaskParameters.getMinCpuCores());
    k8sTaskMainParameters.setMinMemorySpace(k8sTaskParameters.getMinMemorySpace());
    k8sTaskMainParameters.setParamsMap(ParameterUtils.convert(paramsMap));
    k8sTaskMainParameters.setLabelMap(convertToLabelMap(k8sTaskParameters.getCustomizedLabels()));
    k8sTaskMainParameters
            .setNodeSelectorRequirements(convertToNodeSelectorRequirements(k8sTaskParameters.getNodeSelectors()));
    k8sTaskMainParameters.setCommand(k8sTaskParameters.getCommand());
    k8sTaskMainParameters.setArgs(k8sTaskParameters.getArgs());
    return JSONUtils.toJsonString(k8sTaskMainParameters);
}

handler方法里使用了abstractK8sTaskExecutor.run方法,这是另外一个抽象类中的方法,这个抽象类在AbstractK8sTask中以私有变量的形式将这两个类连接起来。

@Override
public void handle(TaskCallBack taskCallBack) throws TaskException {
    try {
        TaskResponse response = abstractK8sTaskExecutor.run(buildCommand());
        setExitStatusCode(response.getExitStatusCode());
        setAppIds(response.getAppIds());
    } catch (Exception e) {
        log.error("k8s task submit failed with error", e);
        exitStatusCode = -1;
        throw new TaskException("Execute k8s task error", e);
    }
}

 

而K8sTaskExecutor继承AbstractK8sTaskExecutor重写其中的方法,并新增创建job等方法

在其重写的run方法中,

if (null == TaskExecutionContextCacheManager.getByTaskInstanceId(taskInstanceId)) {
   result;
    result.setExitStatusCode(EXIT_CODE_KILL);
    return result;
}

这一段代码是在dolphin的ui页面创建好工作流后,任务通过Master分配到Worker中进行运行。并且任务运行的状态也会实时的通知到Master。两者之间的交互是通过netty实现的,TaskDispatchProcessor会接收从Master发送的task dispatch消息,并加入到worker任务队列waitSubmitQueue中

取自:Dolphinscheduler 任务运行流程 - 掘金 (juejin.cn)

WorkerTaskDispatchProcessor的process方法中会将taskIntancedID缓存至TaskExecutionContextCacheManager的taskRequestContextCache中,这样就可以在其重写的run方法里获取而不是返回,可以将k8s插件单独的提取出来,将这一段代码注释掉。

在run方法中有

k8sUtils.buildClient(configYaml);
submitJob2k8s(k8sParameterStr);
registerBatchJobWatcher(job, Integer.toString(taskInstanceId), result, k8STaskMainParameters);

这三个方法,buildClient分别是用来创建k8s集群的客户端,可以操作k8s集群。

submitJob2k8s:提交k8s任务,而在这个方法中

job = buildK8sJob(k8STaskMainParameters);
stopJobOnK8s(k8sParameterStr);
String namespaceName = k8STaskMainParameters.getNamespaceName();
k8sUtils.createJob(namespaceName, job);

先build,创建一个k8s任务,再将与任务名称相同的任务删除,再创建任务

再在运行时,注册观察,这时代码会进入执行状态,一直运行,直到任务完成或失败会将其结束。

接下来是实验:

在test里设置参数:

参数1:image:  镜像  这里我随便写了一个java将其打包至虚拟机的docker的registry中。
public class CountA {
    public static void main( String[] args ) {

        for ( int i = 0; i < args.length; i++ ) {
            System.out.println( "args[" + i + "]=" + args[ i ] );
        }

    }

}

参数2:namespace   命名空间,是你k8s集群的命名空间,如果不知道,可以通过

NonNamespaceOperation< Namespace, NamespaceList, Resource< Namespace > > namespaces = client.namespaces();
NamespaceList list = namespaces.list();
System.out.println("----------this is namespace-----------------");
for (Namespace namespace : list.getItems()) {
    System.out.println("Name: " + namespace.getMetadata().getName());
    System.out.println("Labels: " + namespace.getMetadata().getLabels());
    System.out.println("----------------------------------");
}
System.out.println("namespace is over =============================");

代码查询,前提:先用java客户端连接上k8s集群

参数3:configYaml   java客户端连接k8s集群的配置,找到k8s集群的admin.conf,由于我的是虚拟机中安装的,所以我的是在 /etc/kubernetes/文件夹下,使用finalshell(虚拟机与本机交互的一大利器)下载到电脑后,将clusters下的cluster的server改为https://xxxxxxx:6443这里xxxx改为k8s集群master的ip地址。

然后将其使用json转换工具转换为json格式。

参数4:minCpuCores参数5:minMemorySpace   最小cpu与磁盘设置

参数6:taskInstanceId任务实例id(因为是将关于k8s插件从总源码中拿去出来的,所以这个要手动设置),随便写个int类型的数值

参数7:taskName任务名称,这个参数例子中给的有问题,不可以使用_,将其改为-,同时将K8sTaskExecutor下的buildK8sJob中的

String k8sJobName = String.format("%s-%s-job", taskName, taskInstanceId);

修改,这是我修改后的,原本的是以id结尾,这种是k8s集群不允许的jobname

参数8:

private final String PARAM1 = "param1";
private final String PARAM2 = "param2";
private  final String param1Value = "cdtsaygbxhunjivdysabhunvdwysbaaaaaaaaaaun";
private  final String param2Value = "a";

这四个可以视为一个参数集合,设置为本此job的环境变量

参数9和10:

private final String command = "[\"java\", \"-jar\",\"app.jar\"]";
private final String args = "[\"param1=aaaaaaaabbbbbbbb\",\"param2=a\"]";

这两个是命令行command和args参数  这是在拉取镜像的时候,镜像是通过Dockerfile打成的镜像,

# command、args两项实现覆盖Dockerfile中ENTRYPOINT的功能,具体的command命令代替ENTRYPOINT的命令行,args代表集体的参数。

# 以下是使用场景
1. 如果command和args均没有指定,那么则使用Dockerfile的配置。

2. 如果command没有指定,但指定了args,那么Dockerfile中配置的ENTRYPOINT的命令行会被执行,并且将args中填写的参数追加到ENTRYPOINT中。

3. 如果command指定了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command(不带任何参数,当然command中可自带参数)。

4. 如果command和args都指定了,那么Dockerfile的配置被忽略,执行command并追加上args参数。

内容取自:https://blog.csdn.net/a13568hki/article/details/124268380

参数11与12:

private final List< Label > labels = Arrays.asList( new Label( "test", "1234" ) );
private final List< NodeSelectorExpression > nodeSelectorExpressions =
        Arrays.asList( new NodeSelectorExpression( "kubernetes.io/hostname", "In", "master" ) );

labels是标签,被用来与k8s的其他功能连用时匹配的,

nodeSelectorExpressions是节点选择器,而节点怎么选可以通过代码:

System.out.println("this is nodes ------------------------");
NodeList nodeList = client.nodes().list();
for ( Node node : nodeList.getItems()) {
    System.out.println("Node: " + node.getMetadata().getName());
    System.out.println("Labels: " + node.getMetadata().getLabels());
    System.out.println("----------------------------------");
}
System.out.println("nodes is over ===========================");

new NodeSelectorExpression( "kubernetes.io/hostname", "In", "master" )的三个参数可以通过刚刚选择节点的代码中的label选择一个label,三个参数的意思分别为下:

key(键):一个字符串,表示要用于选择节点的标签键(Label Key)。

operator(运算符):一个字符串,表示进行节点选择时采用的运算符。常见的运算符有 “In”、“NotIn”、“Exists”、“DoesNotExist” 等。在这个例子中,使用的运算符是 “In”,表示节点的标签键值必须在给定的值列表中。

values(值):一个字符串数组,表示用于节点选择的标签值列表。在这个例子中,标签键为 “kubernetes.io/hostname”,值列表中只有一个元素 “master”。

而operator的这几个数值中:

“In”:表示节点的标签值必须包含在给定的值列表中。只有当节点的标签值在指定的值列表中时,选择器才会匹配该节点。

“NotIn”:表示节点的标签值不能在给定的值列表中。只有当节点的标签值不在指定的值列表中时,选择器才会匹配该节点。

“Exists”:表示节点必须具有指定的标签键,而不考虑该标签的值是什么。只要节点具有该标签键,选择器就会匹配该节点。

“DoesNotExist”:表示节点不能具有指定的标签键。只有当节点不具有指定的标签键时,选择器才会匹配该节点。

ok,所有的参数介绍完毕

然后将测试类进行修改一下:

 直接使用handle方法,这个参数是因为父类有所以必须存在,而在k8s重写的方法里面又没有用处,所以赋予null

执行结果:

可以在k8s集群中的容器组内看到执行成功的容器:点击进去查看日志:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值