6

Argo Workflow介绍:一款强大的云原生持续集成工具

 1 year ago
source link: https://cloudnative.to/blog/cloudnative-ci-argo-workflow/
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

点击查看目录

Argo workflow 是什么

老牌的 CICD 工具 Jenkins 应该是大部分都接触过的,而在云原生时代,诞生了两大 CI/CD 框架,也就是 Argo Workflow 和 Tekton,本文主要介绍一下 Argo Workflow。

Argo Workflow 是一个云原生的工作流引擎,基于 kubernetes 来做编排任务,目前 Argo 项目是 CNCF 的毕业项目。

只有当需要执行对应的 step 时才会创建出对应的 pod,因此和 Tekton 一样,对资源的申请和释放具有很好的利用性。

基于 Argo Workflow 可以完成一些比较复杂的工作流,下面是一个来自某个 issue 的图:

Argo Workflow

Argo Workflow

架构图

架构图

在 Argo Workflow 中,每一个 step/dag task 就是一个 pod 中的容器,最基础的 pod 会有 1 个 init 容器和两个工作容器,其中 init 容器和主容器都是 argoproj/argoexec 容器,另一个则是 step 中需要使用的容器,也就是实际执行内容的容器,在 pod 中充当 sidecar。

  • main 容器,也就是 step/dag task 中定义的容器,用于执行实际内容。
  • init 容器,用于为 main 容器处理 artifact 以及参数相关的逻辑。
  • wait 容器,等待 main 容器执行完成,以及处理一些清理任务,例如上传 artifact 到 S3。

需要理清的一点是虽然 Argo Workflow 将工作容器定义为main容器,但实际上wait容器是 pod 中的主容器。

在 Argo Workflow 中主要的 CRD 对象有几个:

  • Workflow
  • WorkflowTemplate
  • CronWrokflow

接下来分别了解一下三个CRD对象。

Workflow

Workflow 定义的字段和 workflowTemplate 定义的字段基本上是一致的,因此将字段的解释放在 workflowTemplate 部分,对 Workflow 的理解只需要知道Workflow 是一个流水线的"实例",也就是只有创建了 Workflow 对象是才会真正的运行流水线。

WorkflowTemplate

WorkflowTemplate 是最重要的对象了,基本上绝大部分时间你都是和它在打交道,其中还有一个 template 的定义,在刚认识 Argo workflow 时需要注意区分的一点是 workflowTemplate 和 template,这在我刚入门时也造成了一点困惑,接下来讲一下这两个的区别:

workflowTemplate 是 argo workflow 中实现的 CRD 对象,而 template 则是对象内的一个字段,实际执行内容都是在 template 中定义的,一个 workflowTemplate 至少要包含一个 template。 workflowTemplate 需要将一个 template 配置为 entrypoint,也就是流水线的起点,在这个 template 的 steps 中又可以应用多个相同或不同的 template。

简单举一个例子来理解 workflowTemplate 多个 template,假设要封装一个 workflowTemplate 来处理 git 相关的场景:

分别为以下三个操作创建三个 template,假设需要在同一份代码中多次 merge && commit,那么流水线入口是 git clone,然后 git merge, git add && git commit,在这种情况下 template2 和 template3 是作为 template1 的一部分存在的。而当流水线入口直接就是 git merge 或 git add && git commit 的情况时, template2 或 template3 是作为单独的流水线逻辑存在。

  1. git clone
  2. git merge
  3. git add && git commit

因此 template 可以单独作为流水线入口执行,也可以被其他的 template 引用。

先列出几个关键词做一个简单的概述来更好的了解 Template:

  • steps, 流水线每一步的执行内容,--表示与同级别的step并行执行,-表示与同级别的 step 顺序执行。
  • container,真正执行内容的定义,与 kubernetes container spec 定义一致。
  • script,这是一个基于 container 的类型,可以让用户直接在CI中直接执行一些脚本并且得到返回的结果,例如执行 python 代码,执行 node 代码以及执行 shell 等等。
  • resource,这个类型可以支持在 CI 中对 Kubernetes 的对象进行操作,例如创建一个 configMap,然后根据这个 Kubernetes 资源对象的状态来判断该步骤是否成功。(这个功能太酷了!)

以上几个点是理解 template 最主要的内容,一个简单示意的 yaml 格式如下:

...
  entrypoint: hello-hello-hello #配置template入口
  templates:
  - name: hello-hello-hello
    steps:
    - - name: hello1            
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello1"
    - - name: hello2a   
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello2a"   #hello2a与hello1 是顺序执行
      - name: hello2b          #hello2a与hello2b是并行执行
        template: whalesay
        arguments:
          parameters:
          - name: message
            value: "hello2b"

  - name: whalesay  # 定义一个用于真正执行内容的 template
    inputs:
      parameters:
      - name: message
    container:
      image: docker/whalesay
      command: [cowsay]
      args: ["{{inputs.parameters.message}}"]
...

我们在执行代码测试的过程中经常会有一些依赖服务要怎么在 Argo Workflow 中实现呢?

Argo Workflow 为 step 提供了 sidecars 参数,可以配置你需要的依赖容器,例如 DID,etcd,Redis 和 Mysql 等等.

下面是一个简单的 yaml 示例,为 CI 添加一个 redis 依赖服务:

...
        container:
          image: busybox:1.36.1
          command: [sh, -c]
          args: ["echo hello"]
        sidecars:
        - name: redis
          image: redis:7.0.11
...

另一个比较常见的是 并行版本/参数测试,例如跑测试时希望让同一份代码基于多个版本的 Etcd 服务做测试,那么 Argo workflow 也提供了 withItems 的方式来实现这个功能。

还有一个常见的需求是编译缓存,例如 java 应用编译产物希望在下一个 CI 中继续应用,避免每次都去下载一些重复的 jar,Argo workflow 通过 volume 功能来实现这部分内容. 也可以通过 artifact 功能实现,例如上传到 S3,需要时再进行下载。

根据文件唯一性来确认编译缓存是否更改,对于并行测试来说编译缓存可能是一样的,例如只更新了代码而没有更新 pom.xml 那么缓存依赖是一样的. 对于 pom.xml 更改了,也就是编译缓存变更了,那么可以需要先更新编译缓存,然后再跑并行测试,当然这是具体的业务内容了。

接下来从官方一个默认的 workflowTemplate 来看一下实际的 yaml 是怎么样的。

一个默认的简单workflowTemplate

当创建 workflowTemplate 时会有一个默认的 workflowTemplate,来看一下这个 workflowTemplate 做了什么事情。

metadata:
  name: lovely-dragon
  namespace: default
  labels:
    example: 'true'
spec:
  workflowMetadata:
    labels:
      example: 'true'
  entrypoint: argosay
  arguments:
    parameters:
      - name: message
        value: hello argo
  templates:
    - name: argosay
      inputs:
        parameters:
          - name: message
            value: '{{workflow.parameters.message}}'
      container:
        name: main
        image: argoproj/argosay:v2
        command:
          - /argosay
        args:
          - echo
          - '{{inputs.parameters.message}}'
  ttlStrategy:
    secondsAfterCompletion: 300
  podGC:
    strategy: OnPodCompletion

默认创建的 workflowTemplate 只有一个 template 并且它做的唯一一件事情就是打印传参 message

需要注意的是 默认的 workflow 中设置了 podGC 和 workflow 的 TTL,一旦 pod 执行完成了就会删除 pod,并且由于默认没有配置日志持久化,这时候去查看日志的话只会看到空白。

为了方便研究测试,可以先将这部分内容给注释掉,或为 Argo Workflow 设置日志持久化。

注意:实际生产应用时请正确设置日志持久化。

下面的配置表示 workflow 会在 workflow 执行完成后的 300 秒删除,而 workflow 过程中产生的 pod 会在 pod 执行完成后立刻删除。

...
  ttlStrategy:
    secondsAfterCompletion: 300
  podGC:
    strategy: OnPodCompletion
...

DAG 有向无环图

在 Tekton 中,DAG 的表示可以直接理解为 Pipeline。在整个流水线的过程中,可以串行或并行地执行 Tekton Task 并且任务起点与终点不会形成一个闭环。

除了 steps template 之外,Argo WorkflowTemplate 同样支持 DAG,以 dag template 的方式存在,可以让用户更好的维护复杂的工作流。

这里基于一个官方文档的示例来简单了解一下 Argo workflow dag template:

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: dag-diamond-
spec:
  entrypoint: diamond
  templates:
  - name: echo
    inputs:
      parameters:
      - name: message
    container:
      image: alpine:3.7
      command: [echo, "{{inputs.parameters.message}}"]
  - name: diamond
    dag:
      tasks:
      - name: A
        template: echo
        arguments:
          parameters: [{name: message, value: A}]
      - name: B
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: B}]
      - name: C
        dependencies: [A]
        template: echo
        arguments:
          parameters: [{name: message, value: C}]
      - name: D
        dependencies: [B, C]
        template: echo
        arguments:
          parameters: [{name: message, value: D}]

可以看到工作流的入口 template 为 diamond,由于只有任务A没有顺序依赖,因此一开始只会执行任务A,任务A成功执行后开始同时执行任务B和任务C,最终任务B和任务C都顺利执行完后开始执行任务D。可以看到 dependencies 是一个数组传参,因此也可以将上述示例修改为任务D只需要等待任务C顺利执行后就开始执行。

支持Kubernetes资源操作

在前面已经知道有一个 resource 类型的 template,这在我看来是很酷的功能!接下来看一个官方例子:等待 workflow 执行完成。

apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
  generateName: Kubernetes-wait-wf-
spec:
  entrypoint: Kubernetes-wait-wf
  templates:
  - name: Kubernetes-wait-wf
    steps:
    - - name: create-wf
        template: create-wf
    - - name: wait-wf
        template: wait-wf
        arguments:
          parameters:
          - name: wf-name
            value: '{{steps.create-wf.outputs.parameters.wf-name}}'

  - name: create-wf
    resource:
      action: create
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Workflow
        metadata:
          generateName: sleep-
        spec:
          entrypoint: sleep
          templates:
          - name: sleep
            container:
              image: alpine:latest
              command: [sleep, "20"]        
    outputs:
      parameters:
      - name: wf-name
        valueFrom:
          jsonPath: '{.metadata.name}'

  - name: wait-wf
    inputs:
      parameters:
      - name: wf-name
    resource:
      action: get
      successCondition: status.phase == Succeeded
      failureCondition: status.phase in (Failed, Error)
      manifest: |
        apiVersion: argoproj.io/v1alpha1
        kind: Workflow
        metadata:
          name: {{inputs.parameters.wf-name}}        

可以看到,Argo Workflow 原生支持直接在流水线中创建 Kubernetes 对象,并且根据对象的字段来控制流水线的执行。上述的示例效果是在 step1 中创建一个 workflow,然后在 step2 中等待创建的 workflow 执行完成,或者说等待这个 workflow 对象变更成预期的 success 或 failure 对应的状态。

这个在 resource 操作在流水线需要处理一些 Kubernetes 资源时会是一个很有用的功能。

一个更完善的流水线可能还会包含很多复杂的内容,这里留下一些参考点为研究 Argo workflow 时提供一些方向:

  • 为 CI 配置环境变量
  • 为 CI 配置多个依赖服务 (sidecar)
  • 设置/使用特别 bucketName s3 artifact
  • 工件存储 artifact
  • volume 传递编译缓存
  • 条件判断 step,当某些条件成立时才执行对应的 step
  • workflow 和 step 并行度限制
  • resource 类型 template,直接编写 python 代码

以上都是 Argo Workflow 本身就提供的功能,不需要自己再做一些封装,因此足以看到 Argo Workflow 提供的功能的实用性。

CronWorkflow

CronWorkflow 是一个用于定时触发 workflow 的定义,在 CI 中也是很常见的,例如每晚构建。

同样地,通过 Argo 的 UI 界面创建一个定时的 workflow 时也会有一个默认的 cronWorkflow,可以通过这个默认的 cronWorkflow 来了解下:

metadata:
  name: sparkly-tiger
  namespace: default
  labels:
    example: 'true'
spec:
  workflowMetadata:
    labels:
      example: 'true'
  schedule: '* * * * *'
  workflowSpec:
    entrypoint: argosay
    arguments:
      parameters:
        - name: message
          value: hello argo
    templates:
      - name: argosay
        inputs:
          parameters:
            - name: message
              value: '{{workflow.parameters.message}}'
        container:
          name: main
          image: argoproj/argosay:v2
          command:
            - /argosay
          args:
            - echo
            - '{{inputs.parameters.message}}'
    ttlStrategy:
      secondsAfterCompletion: 300
    podGC:
      strategy: OnPodCompletion

经过前面 workflow 和 workflowTemplate 的了解后,可以看到 cronWorkflow 的 yaml 文件整体来说是差不多的,无非是多了一些定时相关的配置。

上述示例中 schedule 配置为 * * * * *,也就是每分钟会执行一次 workflow。关于定时的内容都会有一个注意点是定时任务的时区, cronWorkflow 支持为定时任务设置时区,具体可以看看官方的这个cron workflow 示例

与 Tekton 的对比

经过一番折腾后能够感受到一些很明显的区别:

从系统架构上来说,Tekton 做得更好,整体架构比较清晰,但从用户功能的角度上来说 Argo Workflow 更容易上手使用。

Argo workflow 的 UI 能够展现出比较直观的 CI 顺序效果,同时 Argo WOrkflow 会有很多实用的功能。

另一个是 Argo workflow 中提供了一些 Tekton 默认所没有的功能,在我看来这些也都是比较酷和实用的功能,例如:

  • resource 类型 template,可以直接创建 Kubernetes 对象以及 对 Kubernetes 对象 get,等待 Kubernetes 对象某个字段变更。
  • artifact 功能,例如和 S3 打交道,这在流水线中是很常见的需求,但 Tekton 本身并没有提供。

Argo workflow 的文档建设也比 Tekton 更好。

总的来说 Tekton 提供的内容处于更底层的位置,与 kubernetes 类似,是一个 CI/CD 底层的引擎,真正用好它需要基于它做一些事情。而 Argo Workflow 处于更上层一点的位置,提供了很多实用的功能,可以很方便的应用起来。

到目前为止,我们了解了 Argo Workflow 的强大特性以及与 Tekton 的一个简单对比,实际在企业内应该选择 Argo Workflow 还是 Tekton 还是需要根据业务特点以及实际验证一些测试后才能决定。

以上只是聊到了 Argo Workflow 的一部分功能,如果想了解更多的功能可以先从官方示例开始,官方代码仓库给了很多的示例yaml,因此可以通过这些示例 yaml 很快的了解到相关的功能。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK