对于容器技术、工作流等概念完全不懂的情况下理解dflow的工作方式会很吃力,这里记录一下个人理解。
工作流的概念很好理解,即某个项目可以分为多个步骤,每个步骤可以实现独立运行,只保留输入输出接口,把每个步骤按顺序串起来就形成了工作流。这样的框架的目的或作用是1、为用户提供一种标准的模板用于记录每个步骤要完成的事(工业上可以叫工序卡);2、负责管理工序执行顺序,收集记录和传递输入输出;3、向用户以友好的方式展示当前工作状态。
dflow是一个基于argo工作流框架的框架,猜测是因为argo模板和执行顺序指令的制作缺乏标准化封装所以推出的。除了通常意义上的封装,dflow还实现了把带输入输出的python脚本打包成argo模板的功能,而原先要在argo里写python只能手写模板,这相当于实现了类似于自动代码生成的功能。
如前面所述,工作流(workflow)是由一个个的步骤(step)组成的。因此要完成一个工作流的设计,用户需要定义每一个步骤(包括每个步骤接受的输入,执行的内容,以及输出),再将步骤按顺序串起来。要编写步骤,需要完成两件事:1、编写模板(template),模板中记载了输入输出的名称类型和数量,该模板要使用的工作环境,和具体的操作(比如将名为a.txt的文件内容读出,写入名为b.txt的文件中);2、编写步骤(step),即引用刚才编写好的模板,指定具体的输入输出文件。这个过程和函数调用很像,函数本身是模板,调用函数时的语句是步骤。
下面的代码来自dflow-helloworld:
'''
这里开始定义名为Hello的模板对象。image是容器的镜像即工作环境,script是这个模板将要执行的linux shell脚本
'''
step1_templ = ShellOPTemplate(
name="Hello",
image="alpine:latest",
script="echo {{inputs.parameters.msg}} > /tmp/msg.txt && echo {{inputs.parameters.number}} > /tmp/results.txt",
)
#这里仍然在定义模板,定义了模板的输入输出。这块内容也可以在上面一块写,只是编程习惯的问题
step1_templ.inputs.parameters = {
"msg": InputParameter(),
"number": InputParameter(),
}
step1_templ.outputs.parameters = {
"out_param": OutputParameter(value_from_path="/tmp/results.txt")
}
step1_templ.outputs.artifacts = {
"out_art": OutputArtifact(path="/tmp/msg.txt")
}
'''
这里引用了上面的模板,定义了一个步骤,并且赋予了具体的输入内容,即名为msg的字符串和名为number的数值
'''
step1 = Step (
name="step1",
template=step1_templ,
parameters={"msg":"HelloWorld!", "number": 1},
)
argo自身支持的模板有好几种,感觉dflow主要用的是HTTP template,即将整个工作流打包成一个json或yaml文件,通过http post到服务器端。dflow内部定义的shellOPtemplate,pythonOPtemplate等模板,写到最终这个json文件里其实本质结构都是一样的。在dflow的代码中,首先将dflow定义的对象转换为argo对象,再转为json。
对于上面提到的“工作环境”和“镜像”,则是容器技术领域的概念。argo是基于容器的,即使用容器技术,将各个step放到容器里去执行,可以理解为argo主程序开启了很多个虚拟机来执行这些step,并管理着这些虚拟机之间的输入输出。要使用容器,首先要安装容器引擎。kubernetes是大型服务集群上常用的平台,而对于小型任务可能过于麻烦,因此dflow使用的是docker+minikube,可以比较轻量化地实现kubernetes的功能。对于一个容器来说,他要具有执行代码的环境,比如是ubuntu还是centos,里面安装的是python还是gcc,python有哪些库等等。这些信息可以被打包成一个镜像来被容器使用。当在dflow中指定模板的镜像时,就指定了模板中代码的运行环境。虽说可以理解为虚拟机,但容器和镜像比虚拟机占用的资源要小得多,一个容器镜像大小在几百兆到1G左右,并且启动只需要数分钟。
大致的架构是这样的:本地机器运行着docker+minikube,minikube中开启一个pod(最小调度单元,可以近似认为就是一个容器)运行着argo的几个主要进程。当通过dflow向argo提交工作流时,argo进程就会开启新的pod来执行工作流。这些pod可能在本地,也可以在远程服务器上。
下面简单解释一下dflow的安装过程都在做些什么。以下内容来自
https://github.com/kianpu34593/dflow_helloworld/blob/master/dflow-helloworld.ipynb
1、安装docker+minikube,作为argo运行的基础。
2、本地python安装dflow库,里面包含了dflow使用的库函数,作用是将定义的模板、步骤等转换为argo能接受的格式化文件,同时有些与argo服务器端通信的函数。(理论上dflow开启debug模式后也可以纯本地运行,不依赖argo)
3、本地启动minikube,它会默认下载并使用一个1G多的镜像运行,在国内可以加个参数让下载更快些。这里注意如果步骤设计多进程并行任务,要指定好minikube的核数,否则工作流所面对的cpu数量不足,容器无法运行。
4、在minikube中安装argo框架。先创建命名空间,之后的操作指定该命名空间后就可以实现操作上的隔离。安装框架时使用不同的源可能会安上不同版本的argo,版本不同会导致某些地方有问题。。。
5、监测一下argo的几个pod运行状况,都running的话说明argo完全启动了
6、将argo容器的端口转到本地上,2746是用于监测的界面,9000是一个叫minio的存储控制软件,负责管理各个pod产生的文件
至此就可以运行dflow脚本提交工作流了。