Argo Workflows Workflow Spec 结构解析:从 Kubernetes 头部到模板编排
【免费下载链接】argo-workflowsWorkflow Engine for Kubernetes项目地址: https://gitcode.com/gh_mirrors/ar/argo-workflows
导读
本文基于 Argo Workflows 官方 Walk-through 系列中《The Structure of Workflow Specs》一文,系统拆解 Workflow 清单(Manifest)的两层结构:Kubernetes 标准头部与spec主体,并深入每一个模板(Template)内部的输入、输出与执行体组织方式。读完本文,你将能够读懂任意一个 Workflow YAML 的骨架,理解 entrypoint 如何驱动模板调用链,掌握 container 与 steps 两类模板的编写方法,以及 Workflow 的 container 段为何能直接复用 Pod Spec 的全部能力。
从整体看 Workflow Spec:一个清单,两层结构
在 Argo Workflows 中,Workflow 是运行在 Kubernetes 之上的自定义资源(CRD)。因此,一份 Workflow 清单天然由两部分构成——Kubernetes 标准头部与Argo 特有的 spec 主体。官方文档将其概括为:
- Kubernetes 头部(header),包含
apiVersion、kind与元数据(meta-data); - Spec 主体(spec body),包含:
- Entrypoint 调用(可携带可选参数);
- 一组模板(template)定义列表。
逐层向下,每个模板定义又由以下部分组成:
- 模板名称(name);
- 可选的输入(inputs)列表;
- 可选的输出(outputs)列表;
- 一个容器调用(container,即叶子模板)或一个步骤列表(steps),其中每个步骤都会调用另一个模板。
这一结构在仓库中的 Go 类型定义里有着完全对应的实现:WorkflowSpec与Template两个结构体定义在 pkg/apis/workflow/v1alpha1/workflow_types.go 中,WorkflowSpec从 第 299 行 开始,Template从 第 706 行 开始。CRD 的完整字段说明可以查阅 docs/fields.md 中的 WorkflowSpec 与 Template 两节。可以说,"Kubernetes 头部 + spec 主体"这种分层,正是 Argo Workflows 能原生融入 Kubernetes 生态(kubectl、RBAC、Secret、Volume)的根本原因。
第一层:Kubernetes 头部与元数据
任何 Workflow 清单的第一层都是标准 Kubernetes 头部。以仓库中最基础的示例 examples/hello-world.yaml 为例:
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: hello-world- labels: workflows.argoproj.io/archive-strategy: "false" annotations: workflows.argoproj.io/description: | This is a simple hello world example. spec: entrypoint: hello-world templates: - name: hello-world container: image: busybox command: [echo] args: ["hello world"]这里的关键信息:
apiVersion: argoproj.io/v1alpha1表明这是 Argo Workflows 定义的 API 组与版本;kind: Workflow是 Argo 新增的一种 Kubernetes 资源类型(而非 Pod 或 Job),这一点在 docs/walk-through/hello-world.md 中有明确说明;metadata中既可以使用generateName(如上例,让控制器自动生成带随机后缀的名字),也可以使用name固定资源名;labels与annotations与普通 Kubernetes 资源一致。
由于 Workflow 是标准 CRD,metadata段的写法与普通 Kubernetes 对象完全相同,这意味着你可以用kubectl直接创建、查看和删除 Workflow,也可以借助 label/annotation 实现归档策略、描述信息等扩展能力。
第二层:Spec 主体 —— Entrypoint 与 Templates
头部之下是spec主体,它只做两件事:声明从哪个模板开始执行,定义可被引用的模板集合。这在WorkflowSpec结构体中体现得极为直白:
// Entrypoint is a template reference to the starting point of the workflow. Entrypoint string `json:"entrypoint,omitempty"` // Arguments contain the parameters and artifacts sent to the workflow entrypoint Arguments Arguments `json:"arguments,omitempty"` // Templates is a list of workflow templates used in a workflow Templates []Template `json:"templates,omitempty"`(见 workflow_types.go)
Entrypoint:工作流的起点
entrypoint是对某个模板的引用,它指定 Workflow 执行时第一个被调用的模板。官方文档特别指出:当 Workflow 中定义了多个模板时,指定 entrypoint 就尤为重要——因为执行器需要明确知道从哪里开始。
仓库 examples/arguments-parameters.yaml 演示了 entrypoint 与 spec 级参数(arguments)配合的写法:
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: arguments-parameters- spec: entrypoint: print-message # Parameters can be passed/overridden via the argo CLI. # To override the printed message, run `argo submit` with the -p option: # $ argo submit examples/arguments-parameters.yaml -p message="goodbye world" arguments: parameters: - name: message value: hello world templates: - name: print-message inputs: parameters: - name: message container: image: busybox command: [echo] args: ["{{inputs.parameters.message}}"]这里的spec.arguments.parameters会作为入口参数传给 entrypoint 模板,而argo submit -p message="goodbye world"可以在命令行覆盖默认值。由源码注释可见,Workflow 级参数还可以通过workflow.parameters.myparam这样的变量前缀在工作流内全局引用(见 workflow_types.go)。
Templates:模板定义列表
templates是Template结构体的列表。需要注意两个来自 CRD 校验规则的约束:
- 单个 Workflow 中模板数量上限为 200(
MaxItems=200),这是为了避免过高的 CEL 校验成本; - 每个模板只能拥有一种执行体类型——container、script、dag、steps、resource、suspend、containerSet、data、http、plugin 中至多出现一个(
template must have at most one template type)。
这两条规则都写在 workflow_types.go 的校验注解中,是理解模板定义边界的第一手依据。
第三层:单个模板的内部结构
回到官方文档给出的模板四要素:名称、可选输入、可选输出、执行体。Template结构体原样反映了这一设计:
// Name is the name of the template Name string `json:"name,omitempty"` // Inputs describe what inputs parameters and artifacts are supplied to this template Inputs Inputs `json:"inputs,omitempty"` // Outputs describe the parameters and artifacts that this template produces Outputs Outputs `json:"outputs,omitempty"` // Steps define a series of sequential/parallel workflow steps Steps []ParallelSteps `json:"steps,omitempty"` // Container is the main container image to run in the pod Container *apiv1.Container `json:"container,omitempty"`(见 workflow_types.go)
- name:模板名称,受正则
^[a-zA-Z0-9][-a-zA-Z0-9]*$约束且长度不超过 128,是模板被 entrypoint、steps、dag 任务引用的唯一标识; - inputs:可选,声明该模板需要接收的参数(parameters)与工件(artifacts);
- outputs:可选,声明该模板产出并对外暴露的参数与工件;
- 执行体:二选一(或多选一,见上文"至多一种执行体类型"的校验)——要么是
container叶子执行体,要么是steps(或dag等)复合编排体。
叶子模板:Container 调用
当模板直接运行一个容器时,它就是"叶子模板"(leaf template)。container字段的类型是*apiv1.Container——直接复用了 Kubernetes 标准core/v1.Container类型,这一点意义重大,详见下文"与 Pod Spec 的兼容性"一节。
Hello World 示例中的hello-world模板就是最典型的叶子模板:image: busybox、command: [echo]、args: ["hello world"],执行完毕即结束,不再派生子任务。
复合模板:Steps 列表与模板调用链
当模板需要编排多个任务时,它使用steps字段。官方文档对 steps 的定性是:每个步骤都调用另一个模板。仓库 examples/steps.yaml 给出了标准写法:
apiVersion: argoproj.io/v1alpha1 kind: Workflow metadata: generateName: steps- spec: entrypoint: hello-hello-hello templates: - name: hello-hello-hello steps: - - name: hello1 template: print-message arguments: parameters: [{name: message, value: "hello1"}] - - name: hello2a template: print-message arguments: parameters: [{name: message, value: "hello2a"}] - name: hello2b template: print-message arguments: parameters: [{name: message, value: "hello2b"}] - name: print-message inputs: parameters: - name: message container: image: busybox command: [echo] args: ["{{inputs.parameters.message}}"]这个例子同时揭示了 steps 的两条关键语义:
- 模板即步骤:
hello-hello-hello模板本身不运行容器,它通过steps引用了三次print-message模板;而print-message才是真正执行echo的叶子模板。 - 列表的嵌套即编排顺序:
steps是"列表的列表"([]ParallelSteps,见 workflow_types.go)。外层每个子列表代表一个"阶段"(stage),阶段之间串行;同一阶段内的步骤并行。因此该示例中hello1先执行完毕,之后hello2a与hello2b并行执行。
同时,步骤通过arguments.parameters把参数message传入被调用模板,而print-message模板通过inputs.parameters声明入参,并在容器命令中用{{inputs.parameters.message}}占位符完成替换——这就是"每个步骤调用另一个模板"这一链式结构的完整闭环。更多关于 steps 编排的细节可继续阅读 docs/walk-through/steps.md,参数机制见 docs/walk-through/parameters.md。
与 Pod Spec 的兼容性:Container 段的完整能力
官方文档特别强调了一条容易忽略但极为重要的设计:Workflow spec 中的 container 段接受与 Pod spec 的 container 段完全相同的选项,包括但不限于:
- 环境变量(environment variables)
- Secrets
- 卷挂载(volume mounts)
同理,Workflow 级也支持卷声明(volume claims)与卷(volumes)。
这一保证的根源在于类型定义:Template.Container直接使用 Kubernetes 的*apiv1.Container类型(见 workflow_types.go),而不是 Argo 自造的简化类型。因此你在 Pod 里能给容器配置的一切——env、envFrom、volumeMounts、resources、imagePullPolicy、ports、securityContext、livenessProbe等——都可以原样写进模板的container段。
与之配套,WorkflowSpec还提供了与 Pod 对等的编排能力:
volumes:Workflow 级卷列表,可被各容器挂载(workflow_types.go);volumeClaimTemplates:PVC 模板列表,控制器会在 Workflow 开始时创建 PVC、在 Workflow 结束时删除(workflow_types.go);- 模板级同样可以声明
volumes、initContainers、sidecars(见 workflow_types.go)。
这意味着你在编写 Workflow 时,可以把已有的 Pod/Deployment 容器配置几乎原样搬入模板,Secrets、ConfigMap、PVC 的接入方式与原生 Kubernetes 完全一致,学习与迁移成本极低。
从"二选一"到"多选一":执行体类型的现代扩展
官方文档撰写时所描述的是"container 或 steps"两类执行体;而从当前仓库的Template结构体(workflow_types.go)可以看出,Argo Workflows 已将该模型扩展为多种执行体类型,且它们遵循同样的"一个模板一种执行体"规则:
| 执行体字段 | 作用 | 文档参考 |
|---|---|---|
container | 运行单个容器(叶子模板) | docs/walk-through/hello-world.md |
steps | 串行/并行步骤编排 | examples/steps.yaml、docs/walk-through/steps.md |
dag | 基于依赖关系的有向无环图编排 | examples/dag-diamond.yaml |
script | 在解释器容器中运行脚本片段 | examples/scripts-bash.yaml |
resource | 直接创建/管理 Kubernetes 资源 | examples/k8s-jobs.yaml |
suspend | 挂起流程等待人工批准 | examples/suspend-template.yaml |
containerSet | 在单个 Pod 内运行多个容器 | examples/container-set-template/parallel-workflow.yaml |
data | 数据转换模板 | examples/data-transformations.yaml |
http | 发起 HTTP 请求 | examples/http-hello-world.yaml |
plugin | 使用自定义插件模板(自由格式结构) | examples/workflow-level-executor-plugin.yaml |
无论是哪种执行体,它们都遵守本文所讲的外层骨架:模板有名字、可选输入、可选输出,而 steps/dag 等复合模板内部引用的仍是其他模板——整套"模板调用模板"的递归模型保持不变。这也正是"Workflow spec 由一组 Argo 模板构成,每个模板包含可选输入、可选输出,以及容器调用或步骤列表"这一官方总结在今日依然成立的深层原因。
小结:一张图读懂 Workflow Spec 的骨架
把官方文档的层次结构整理成如下骨架,可作为阅读任意 Workflow YAML 的速查表:
Workflow 清单 ├── Kubernetes 头部 │ ├── apiVersion: argoproj.io/v1alpha1 │ ├── kind: Workflow │ └── metadata(generateName/name、labels、annotations) └── spec 主体 ├── entrypoint:指定起始模板(可携带 arguments 参数) ├── arguments(可选):传给 entrypoint 的参数与工件 └── templates:模板定义列表 └── 每个模板 ├── name:模板唯一标识 ├── inputs(可选):入参 parameters / artifacts ├── outputs(可选):出参 parameters / artifacts └── 执行体(至多一种) ├── container:叶子模板,直接运行容器 └── steps / dag 等复合模板:内部步骤再调用其他模板实践中,读者可以对照 examples/hello-world.yaml(单模板、纯 container 叶子)、examples/arguments-parameters.yaml(entrypoint + arguments + inputs 参数链路)与 examples/steps.yaml(复合 steps 编排 + 模板调用链)三个示例,逐层验证本文总结的结构。如果想继续系统学习,官方 Walk-through 系列建议按顺序阅读 docs/walk-through/argo-cli.md 起步,随后进入参数、工件、步骤、DAG 等专题;完整字段级说明则以 docs/fields.md 中的WorkflowSpec与Template两节为最终权威参考。
【免费下载链接】argo-workflowsWorkflow Engine for Kubernetes项目地址: https://gitcode.com/gh_mirrors/ar/argo-workflows
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考