量一量 DAG 流水线与 Job 的距离
目标
使用清单描述 Argo Workflows 的 DAG、制品和模板复用,并用 Kubernetes Job 与 CronJob 实际部署相同的工作,直观比较两种模型的表达能力。
为什么重要
要判断是否应该引入 Workflows,首先必须了解 Job 能做到什么程度。Job 可以表达重试(backoffLimit)和并行(parallelism),却无法表达任务之间的依赖关系和文件传递。因此,只使用 Job 的组织最终往往会把所有 Shell 脚本塞进一个容器,或把执行顺序交给集群外部的编排器;这两种方式都会让失败点变得难以定位。在本实验中并排创建两类清单,你会切实理解它们的能力边界。
步骤
- 创建
/root/capa-wf/目录,在workflow.yaml中写入 apiVersionargoproj.io/v1alpha1、kindWorkflow、metadata.namecapa-build和spec.entrypointmain。spec.templates中必须有一个 name 为main的模板。 - 在
main模板中创建dag.tasks,并加入checkout、build、test三个任务。让build依赖checkout,让test依赖build,不要给checkout设置 dependencies。 - 在
spec.templates中添加一个 name 为build的模板;在inputs.parameters中声明名为revision的参数,并在outputs.artifacts中声明名为binary、path 为/out/app的制品。 - 在
/root/capa-wf/cronworkflow.yaml中写入 kindCronWorkflow、metadata.namecapa-nightly、spec.schedule0 3 * * *、spec.concurrencyPolicyForbid和spec.workflowSpec.entrypointmain。 - 在
/root/capa-wf/workflowtemplate.yaml中写入 kindWorkflowTemplate和metadata.namecapa-common,并在其中添加一个 name 为notify的模板。然后在workflow.yaml的maindag 中添加notify任务,将templateRef.name设为capa-common、templateRef.template设为notify,并将 dependencies 设为test。 - 在集群中创建命名空间
capa-wf,并在其中实际创建 Jobcapa-build-job。将spec.backoffLimit设为2,Pod 的restartPolicy设为Never,容器镜像设为busybox:1.36。 - 在同一命名空间中实际创建 CronJob
capa-nightly-job。将spec.schedule设为0 3 * * *、spec.concurrencyPolicy设为Forbid、spec.successfulJobsHistoryLimit设为1。 - 在同一命名空间中实际创建 ConfigMap
capa-wf-summary。键dag-tasks的值应为workflow.yaml中maindag 的任务数,键cron-schedule的值应为cronworkflow.yaml中的 schedule 值,键job-name的值应为capa-build-job。
参考
- 可以先运行
kubectl create job capa-build-job --image=busybox:1.36 -n capa-wf --dry-run=client -o yaml生成骨架,再补上 backoffLimit,这样更快。 - 可以运行
yq '.spec.templates[] | select(.name == "main") | .dag.tasks | length' /root/capa-wf/workflow.yaml统计 dag 的任务数。 - 常见错误 1:把 Workflow 的 spec 字段直接写进 CronWorkflow。这里需要用一个字段再包一层。
- 常见错误 2:包含空格的 Cron 表达式没有加引号。请在 YAML 中用引号将它括起来。
Workflow 骨架与 entrypoint
创建 /root/capa-wf/ 目录,在 workflow.yaml 中写入 apiVersion argoproj.io/v1alpha1、kind Workflow、metadata.name capa-build 和 spec.entrypoint main。spec.templates 中必须有一个 name 为 main 的模板。
entrypoint 指向 templates 数组中某个模板的 name。如果所指名称并不存在,工作流将无法启动。
绘制依赖关系图
在 main 模板中创建 dag.tasks,并加入 checkout、build、test 三个任务。让 build 依赖 checkout,让 test 依赖 build,不要给 checkout 设置 dependencies。
dag.tasks 中的每一项都有 name、template(或 templateRef)以及 dependencies。不要给图中的起始节点设置 dependencies。
参数与制品
在 spec.templates 中添加一个 name 为 build 的模板;在 inputs.parameters 中声明名为 revision 的参数,并在 outputs.artifacts 中声明名为 binary、path 为 /out/app 的制品。
parameters 表示字符串,artifacts 表示文件。输出制品必须同时指定名称和容器内路径。
使用 CronWorkflow 定期运行
在 /root/capa-wf/cronworkflow.yaml 中写入 kind CronWorkflow、metadata.name capa-nightly、spec.schedule 0 3 * * *、spec.concurrencyPolicy Forbid 和 spec.workflowSpec.entrypoint main。
CronWorkflow 会把 Workflow 的整个 spec 包在一个字段下面。找到这个字段名就是本步骤的一半。
复用 WorkflowTemplate
在 /root/capa-wf/workflowtemplate.yaml 中写入 kind WorkflowTemplate 和 metadata.name capa-common,并在其中添加一个 name 为 notify 的模板。然后在 workflow.yaml 的 main dag 中添加 notify 任务,将 templateRef.name 设为 capa-common、templateRef.template 设为 notify,并将 dependencies 设为 test。
templateRef 需要同时指定要使用哪个对象(name)中的哪个模板(template)。这个任务也是依赖关系图的一部分,因此必须设置前置条件。
实际部署执行相同工作的 Job
在集群中创建命名空间 capa-wf,并在其中实际创建 Job capa-build-job。将 spec.backoffLimit 设为 2,Pod 的 restartPolicy 设为 Never,容器镜像设为 busybox:1.36。
Job Pod 的 restartPolicy 不能使用 Always。重试次数通过 Job spec 中的一个字段设置,而不是在 Pod 中设置。
使用 CronJob 表达相同的周期
在同一命名空间中实际创建 CronJob capa-nightly-job。将 spec.schedule 设为 0 3 * * *、spec.concurrencyPolicy 设为 Forbid、spec.successfulJobsHistoryLimit 设为 1。
CronJob 也有并发执行策略。还要注意,成功任务和失败任务各自有独立的字段来设置历史记录保留数量。
连接文件与集群的摘要
在同一命名空间中实际创建 ConfigMap capa-wf-summary。键 dag-tasks 的值应为 workflow.yaml 中 main dag 的任务数,键 cron-schedule 的值应为 cronworkflow.yaml 中的 schedule 值,键 job-name 的值应为 capa-build-job。
需要从前面步骤创建的文件中提取值。可以把 yq 的输出直接用作 ConfigMap 的值,也可以手动计数。