5

Kubernetes 工作流引擎:Argo(1)

 2 years ago
source link: https://www.qikqiak.com/post/argo-workflow-engine-for-k8s/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

ArgoApplatix 推出的一个开源项目,为 Kubernetes 提供 container-native(工作流中的每个步骤是通过容器实现)工作流程。Argo 可以让用户用一个类似于传统的 YAML 文件定义的 DSL 来运行多个步骤的 Pipeline。该框架提供了复杂的循环、条件判断、依赖管理等功能,这有助于提高部署应用程序的灵活性以及配置和依赖的灵活性。使用 Argo,用户可以定义复杂的依赖关系,以编程方式构建复杂的工作流、制品管理,可以将任何步骤的输出结果作为输入链接到后续的步骤中去,并且可以在可视化 UI 界面中监控调度的作业任务。

Argo

Argo 简介

Argo V2 版本通过 Kubernetes CRD(Custom Resource Definition)来进行实现的,所以我们可以通过 kubectl 工具来管理 Argo 工作流,当然就可以和其他 Kubernetes 资源对象直接集成了,比如 Volumes、Secrets、RBAC 等等。新版本的 Argo 更加轻量级,安装也十分简单,但是依然提供了完整的工作流功能,包括参数替换、制品、Fixture、循环和递归工作流等功能。

Argo 中的工作流自动化是通过使用 ADSL(Argo 领域特定语言)设计的 YAML 模板(因为 Kubernetes 主要也使用相同的 DSL 方式,所以非常容易使用)进行驱动的。ADSL 中提供的每条指令都被看作一段代码,并与代码仓库中的源码一起托管。Argo 支持6中不同的 YAML 结构:

  • 容器模板:根据需要创建单个容器和参数
  • 工作流模板:定义一个作业任务(工作流中的一个步骤可以是一个容器)
  • 策略模板:触发或者调用作业/通知的规则
  • 部署模板:创建一个长期运行的应用程序模板
  • Fixture 模板:整合 Argo 外部的第三方资源
  • 项目模板:可以在 Argo 目录中访问的工作流定义

Argo 支持几种不同的方式来定义 Kubernetes 资源清单:KsonnectHelm Chart 以及简单的 YAML/JSON 资源清单目录。

安装 Argo 非常简单,首先当然需要一个 Kubernetes 集群(1.9+版本),kubectl 工具以及访问集群的 kubeconfig 文件(默认位于~/.kube/config)。

Mac 系统:

$ brew install argoproj/tap/argo

Linux 系统:

$ curl -sSL -o /usr/local/bin/argo https://github.com/argoproj/argo/releases/download/v2.2.1/argo-linux-amd64
chmod +x /usr/local/bin/argo

安装完成后,可以使用下面命令校验是否安装成功:

$ argo version
argo: v2.3.0
  BuildDate: 2019-05-20T22:11:23Z
  GitCommit: 88fcc70dcf6e60697e6716edc7464a403c49b27e
  GitTreeState: clean
  GitTag: v2.3.0
  GoVersion: go1.11.5
  Compiler: gc
  Platform: darwin/amd64

然后安装控制器和 UI 界面:

$ kubectl create ns argo
$ kubectl apply -n argo -f https://raw.githubusercontent.com/argoproj/argo/v2.3.0/manifests/install.yaml

安装完成后,为了访问方便,我们将 argo-ui 改成 NodePort 类型的 Service(当然也可以创建 Ingress 对象通过域名进行访问):

$ kubectl get pods -n argo
NAME                                   READY   STATUS              RESTARTS   AGE
argo-ui-76c6cf75b4-vh6w6               0/1     ContainerCreating   0          14s
workflow-controller-69f6ff7cbc-5pqbj   0/1     ContainerCreating   0          14s
$ kubectl get pods -n argo
NAME                                   READY   STATUS    RESTARTS   AGE
argo-ui-76c6cf75b4-vh6w6               1/1     Running   0          10m
workflow-controller-69f6ff7cbc-5pqbj   1/1     Running   0          10m
$ kubectl get svc -n argo
NAME      TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
argo-ui   ClusterIP   10.97.124.167   <none>        80/TCP    10m
$ kubectl edit svc argo-ui -n argo
kind: Service
metadata:
......
spec:
......
  sessionAffinity: None
  type: NodePort
......
service/argo-ui edited
$ kubectl get svc -n argo
NAME      TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
argo-ui   NodePort   10.97.124.167   <none>        80:32686/TCP   12m
$ kubectl get crd |grep argo
workflows.argoproj.io                         2019-09-10T03:27:41Z
$ kubectl api-versions |grep argo
argoproj.io/v1alpha1

然后我们就通过上面的 32686 端口来访问 argo-ui 了:

argo ui emptyargo ui empty

到这里就证明 Argo 的基础环境就已经安装完成了。

基本的 Argo 工作流模板

下面是一个非常简单的模板,首先定义了一个工作流,创建一个带有两个容器的 Pod,其中一个容器带有 curl 命令,而另外一个容器是一个 nginx sidecar 容器,这里 curl 这个容器是“主”容器,用于轮询 nginx sidecar 容器,直到它准备好为请求提供服务为止。

Argo 配置工作流模板Argo 配置工作流模板

将上面模板保存为名为 argo-base-template.yaml 的文件,然后可以使用 argo 命令来提交这个工作流:

$ argo submit argo-base-template.yaml
Name:                sidecar-nginx-ftcpf
Namespace:           default
ServiceAccount:      default
Status:              Pending
Created:             Tue Sep 10 12:05:53 +0800 (now)
$ argo list
NAME                  STATUS    AGE   DURATION   PRIORITY
sidecar-nginx-ftcpf   Running   15m   15m        0

当然同样的我们可以直接使用 kubectl 来进行安装,但是 Argo CLI 提供了更强大的功能,比如 YAML 校验、参数传递、重试等等功能。

argo base template eventsargo base template events

上面就是我们定义的一个工作流,创建一个 Pod 并执行 Workflow 中定义的配置:

argo workflow lifecycleargo workflow lifecycle

同样可以通过argo logs查看容器日志,也可以通过 argo-ui 在页面上查看相关信息:

argo dashboard viewsargo dashboard views

带条件的工作流模板

前面我们提到过 Argo 支持工作流执行过程中的条件语句。Argo 提供的 Coinflip 示例就描述了如何在模板中使用“when”,其执行依赖于从父级接收的输出。

argo workflow condition demoargo workflow condition demo

将 Coinflip 保存到本地:

$ wget https://raw.githubusercontent.com/argoproj/argo/master/examples/coinflip.yaml
argo coinflip demoargo coinflip demo

上面的 Worflow 运行一个随机的整数脚本,常量为 0=heads、1=tails,调用特定模板(heads 或者 tails)取决于“flip-coin”任务的输出,如上面 Workflow 图中所示,flip-coin 任务执行 heads 任务只有当 heads 模板被执行的时候。

同样,使用argo submit来提交 Coinflip 这个 Workflow:

$ argo submit coinflip.yaml
Name:                coinflip-pr9x9
Namespace:           default
ServiceAccount:      default
Status:              Pending
Created:             Tue Sep 10 15:56:04 +0800 (now)
$ argo get coinflip-pr9x9
Name:                coinflip-pr9x9
Namespace:           default
ServiceAccount:      default
Status:              Failed
Message:             child 'coinflip-pr9x9-3371049263' failed
Created:             Tue Sep 10 15:56:04 +0800 (4 minutes ago)
Started:             Tue Sep 10 15:56:04 +0800 (4 minutes ago)
Finished:            Tue Sep 10 15:59:40 +0800 (51 seconds ago)
Duration:            3 minutes 36 seconds

STEP               PODNAME                    DURATION  MESSAGE
 ✖ coinflip-pr9x9                                       child 'coinflip-pr9x9-3371049263' failed
 └---⚠ flip-coin   coinflip-pr9x9-3371049263  3m        failed to save outputs: verify serviceaccount default:default has necessary privileges

可以看到这里出现了一个权限错误,Argo 官网上给出的解决方案是给 default:default 绑定上 admin 的 clusterrole 权限:

$ kubectl create rolebinding default-admin --clusterrole=admin --serviceaccount=default:default

然后删除上面的 Workflow,重新创建:

$ argo delete coinflip-pr9x9
$ argo submit coinflip.yaml
Name:                coinflip-jxmzx
Namespace:           default
ServiceAccount:      default
Status:              Pending
Created:             Tue Sep 10 16:30:59 +0800 (now)
argo coinflip getargo coinflip get

上面的 Workflow 将会创建两个容器,一个是用于执行 randomint python 脚本,另外一个是用于根据脚本的执行结果执行的 tails 模板,如下所示,tails 模板根据 randomint 脚本的结果(result==tails)被调用执行了:

$ kubectl get pods
NAME                                   READY   STATUS      RESTARTS   AGE
coinflip-jxmzx-1126897109              0/2     Completed   0          3m28s
coinflip-jxmzx-3981997132              0/2     Completed   0          3m36s
$ kubectl logs coinflip-jxmzx-3981997132 main
tails
$ kubectl logs coinflip-jxmzx-1126897109 main
it was tails
argo coinflip ui viewargo coinflip ui view

类似地,递归(递归调用模板)也可以添加到条件规范中,例如,下面的模板输出显示 flip-coin 模板执行 n 次,直到结果为 heads 为止,下载 flip-coin 递归模板示例:

$ wget https://raw.githubusercontent.com/argoproj/argo/master/examples/coinflip-recursive.yaml

我们可以简单对比下前面的 coinflip,基本上是一致的,唯一的区别就是 tails 模板重新指向了 coinflip,这样就形成了递归:

argo coinflip recursiveargo coinflip recursive

然后用同样的方法来提交这个 Workflow,可以通过argo get命令来查看具体的执行步骤:

argo coinflip recursiveargo coinflip recursive

我们可以看到这里递归执行了4次,最后才出现 flip-coin 的模板输出 heads,这个时候递归才退出,每一次递归调用都会产生一个 Pod,加上最后的 heads 模板,所以一共会产生 5 个 Pod:

$ kubectl get pods
NAME                                   READY   STATUS      RESTARTS   AGE
coinflip-recursive-9dpxn-1771762865    0/2     Completed   0          8m33s
coinflip-recursive-9dpxn-177901715     0/2     Completed   0          8m26s
coinflip-recursive-9dpxn-3162439927    0/2     Completed   0          8m41s
coinflip-recursive-9dpxn-3886219258    0/2     Completed   0          8m19s
coinflip-recursive-9dpxn-545668525     0/2     Completed   0          8m49s

同样可以在 argo-ui 中查看这个 Workflow 的调用示意图:

argo coinflip recursive ui viewargo coinflip recursive ui view

带循环和参数的 Workflow 模板

Argo 可以很方便的迭代 Workflow 中的一组输入,也可以处理用户提供参数(比如:输入参数)。在下面的 Workflow 中,使用两个输入参数“hello kubernetes”“hello argo”来执行 Whalesay 模板。

下载这里我们需要使用的 Workflow 示例:

$ wget https://raw.githubusercontent.com/argoproj/argo/master/examples/loops.yaml

不过需要注意,我们需要把 loops.yaml 文件里面的 withItems 修改成下面的参数值:

withItems:
- hello kubernetes
- hello argo

完整的 YAML 文件内容如下所示:

argo loops configurationargo loops configuration

上面的模板包含一个单独的模板,通过使用一个 items 列表并根据提供的参数值数量来运行任务,所以,会创建两个 Pod,一个使用“hello kubernetes”参数,另外一个使用“hello argo”参数,同样使用argo submit命令来创建这个 Workflow:

$ argo submit loops.yaml
Name:                loops-ftm5r
Namespace:           default
ServiceAccount:      default
Status:              Pending
Created:             Tue Sep 10 17:33:50 +0800 (now)

使用argo get命令来查看这个 Workflow 的详细信息,可以看到迭代了两个步骤出来,当然就会产生两个 Pod:

argo loop eventsargo loop events

我们去查看生成的两个 Pod 的日志信息,里面就包含上面的传入的两个参数“hello kubernetes”“hello argo”的信息:

Workflow Execution with Looping ConfigurationWorkflow Execution with Looping Configuration

类似的我们还可以完成更加复杂的循环:循环迭代一组 items,动态生成 items 列表等,具体的实现我们直接查看 Argo GitHub 仓库上面提供的 example 样例:https://github.com/argoproj/argo/blob/master/examples/

由 DAG(有向无环图)和步骤的依赖定义的多步骤工作流模板

Argo 允许用户使用简单的 Python 对象 DAG 启动多步骤的 Pipeline,还可以在工作流规范中定义多个模板(嵌套工作流)。

下载使用的示例文件:

$ wget https://raw.githubusercontent.com/argoproj/argo/master/examples/dag-diamond.yaml

Workflow 更详细的内容如下所示:

DAG Dependency based Workflow ConfigurationDAG Dependency based Workflow Configuration

接下来我们来提交这个 Workflow:

$ argo submit dag-diamond.yaml
Name:                dag-diamond-qv45w
Namespace:           default
ServiceAccount:      default
Status:              Pending
Created:             Tue Sep 10 18:59:24 +0800 (now)

然后使用argo get命令来查看这个 Workflow 的详细信息:

DAG ExecutionDAG Execution

同样在 argo-ui 中也可以查看到这个 Workflow 的依赖关系:

argo dag ui viewargo dag ui view

使用 Minio 进行制品管理和 Argo 集成

制品是任何工作流的一部分(比如:CI/CD 中),工作流中的步骤会生成制品,然后其他后续步骤可以使用这个制品。

我们这里使用 Minio 来作为制品仓库,Minio 是兼容 Amazon S3 API 的开源对象存储服务器。

首先先安装 Minio,我们这里使用 Helm 来快速的安装,如果对 Helm 的使用还不熟悉的,可以查看前面我们的文章:Kubernetes Helm 初体验

$ helm install stable/minio --name minio --set service.type=NodePort --set defaultBucket.enabled=true --set defaultBucket.name=my-bucket --set persistence.enabled=false --namespace argo

我们这里指定了一个名为 my-bucket 的默认 Bucket,使用 NodePort 类型的 Service,另外需要注意的是我这里单纯为了测试,所以将 persistence.enabled 设置为了 false,对于线上环境一定要记得持久化数据:

$ kubectl get pods -n argo  -l app=minio
NAME                     READY   STATUS    RESTARTS   AGE
minio-7954d6976d-jjm42   1/1     Running   0          9m25s
$ kubectl get svc -n argo  -l app=minio
NAME    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
minio   NodePort   10.109.167.218   <none>        9000:31311/TCP   9m31s

到这里证明 Minio 就已经安装成功了,然后我们就可以通过 31311 这个 NodePort 端口访问 Minio 的 Dashboard 页面,我们可以使用默认的 accessKey(AKIAIOSFODNN7EXAMPLE) 和 secretKey(wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY)登录:

minio uiminio ui

然后我们需要把 Minio 和 Argo 集成在一起,通过编辑 workflow-controller configmap 来引用上面的 Minio Service 和 Secret,上面我们通过 Helm 安装 Minio 的时候会自动将默认的 accessKey 和 secretKey 添加到名为 minio 的 Secret 对象中去:

$ kubectl get secret minio -n argo -o yaml
apiVersion: v1
data:
  accesskey: QUtJQUlPU0ZPRE5ON0VYQU1QTEU=
  secretkey: d0phbHJYVXRuRkVNSS9LN01ERU5HL2JQeFJmaUNZRVhBTVBMRUtFWQ==
kind: Secret
......
type: Opaque

直接编辑 workflow-controller-configmap,按照如下方式添加上 Minio 相关配置:

...
data:
  config: |
    artifactRepository:
      s3:
        bucket: my-bucket  # 默认的 bucket 名称
        endpoint: minio.argo:9000  # Minio 服务地址
        insecure: true
        # accessKeySecret 和 secretKeySecret 是 secret 中包含的,引入名为 minio 的 k8s secret 对象,这两个 key:'accesskey' 和 'secretkey', 存储 真是的 minio 认证信息。
        accessKeySecret:
          name: minio
          key: accesskey
        secretKeySecret:
          name: minio
          key: secretkey
kind: ConfigMap
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
      {"apiVersion":"v1","kind":"ConfigMap","metadata":{"annotations":{},"name":"workflow-controller-configmap","namespace":"argo"}}
  creationTimestamp: "2019-09-10T03:27:43Z"
  name: workflow-controller-configmap
  namespace: argo
  resourceVersion: "1890436"
  selfLink: /api/v1/namespaces/argo/configmaps/workflow-controller-configmap
  uid: b1fd1a24-721d-4ce1-a02c-90fff0e931ee

编辑完成后我们就完成了 Minio 和 Argo 的集成。不过这里需要注意的是 Secret 对象是 namespace 作用域的,上面 ConfigMap 解析 Secret 对象是和我们使用的 Workflow 的 namespace 中获取 Minio Secret 的,所以如果 Minio 和 Workflow 不在同一个 namespace 下面,需要我们拷贝一份 Secret 到对应的 namespace 下面去,比如我们这里 Workflow 都在 default 这个 namespace 下面,那么我就需要在 default 下面创建相同的 Secret:(minio-secret.yaml)

apiVersion: v1
kind: Secret
metadata:
  name: minio
type: Opaque
data:
  accesskey: QUtJQUlPU0ZPRE5ON0VYQU1QTEU=
  secretkey: d0phbHJYVXRuRkVNSS9LN01ERU5HL2JQeFJmaUNZRVhBTVBMRUtFWQ==

创建上面的 Secret 对象:

$ kubectl create -f minio-secret.yaml

然后下载我们这里使用到的 Workflow 示例文件:

$ wget https://raw.githubusercontent.com/argoproj/argo/master/examples/artifact-passing.yaml

详细的 Workflow 内容如下图所示:

Artifactory Management ConfigurationArtifactory Management Configuration

上面 Workflow 包括两个步骤:

  • 步骤1生成制品:使用 whalesay 模板生成制品
  • 步骤2消费制品:使用步骤1中创建的制品并打印消息。

同样,我们使用argo submit命令提交这个 Workflow:

$ argo submit artifact-passing.yaml
Name:                artifact-passing-x4rhq
Namespace:           default
ServiceAccount:      default
Status:              Pending
Created:             Wed Sep 11 12:01:07 +0800 (now)
argo artifact eventsargo artifact events

我们可以看到上面 Workflow 的两个步骤都已经成功了,然后我们去 minio-ui 上面就可以查看到上面 Workflow 生成的制品了:

minio ui dataminio ui data

上面我们创建的制品被存储在 Minio 的 my-bucket 中,消费制品的任务根据 Workflow 中的定义根据提供的配置拉取制品,Minio 类似于 S3 提供了一个可共享的链接来使用制品:

minio ui sharedataminio ui sharedata

除了上面提到的这些用法之外,Argo Workflow 还有很多其他用法,我们可以查看 Argo 官方提供的样例了解更多使用方法:https://github.com/argoproj/argo/tree/master/examples

本文更多的是提到 Argo Workflow 的一些基本使用方法,下一篇文章我们再通过一个完整的示例来演示下 Argo Workflow 的实际用途。

Kubernetes进阶训练营

微信公众号

扫描下面的二维码关注我们的微信公众帐号,在微信公众帐号中回复◉加群◉即可加入到我们的 kubernetes 讨论群里面共同学习。

wechat-account-qrcode

「真诚赞赏,手留余香」


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK