当数据团队需要在 Kubernetes 上跑一个「拉取数据 → 训练模型 → 评估指标 → 推送产物」的多步任务时,手工拼 shell 既难维护也容易因单点失败而前功尽弃。Argo Workflows 正是为解决这类 K8s 原生工作流编排 而生的开源引擎:它用 CRD 把每一步定义成一个 Pod,再用 DAG 描述依赖,让复杂流水线变成声明式 YAML。
一、核心概念:Workflow、Template 与 DAG
Argo 的对象模型非常克制,理解三个概念即可上手。Workflow 是一次运行的实例(对应一次提交),Template 是可复用的步骤定义(类似函数),而 DAG 与 Steps 则描述模板之间的依赖关系。当你习惯「用 YAML 声明意图,而不是用脚本编排过程」时,价值就出来了。
1.1 DAG 与 Steps 的区别
| 维度 | DAG(有向无环图) | Steps(线性步骤) |
|---|---|---|
| 依赖表达 | 任意拓扑,用 dependencies 声明 | 只能串行或简单并行 |
| 适用场景 | 训练、ETL、多分支流水线 | 脚本的简单串联 |
| 可读性 | 复杂图需谨慎设计 | 直观易懂 |
| 失败定位 | 精确到单个 task 节点 | 逐段线性排查 |
如果你的流程是「A 完成且 B 完成之后才能跑 C」,DAG 是天然的表达方式;如果只是「依次执行 1、2、3」,Steps 更省心。两者模板定义完全共用,切换成本极低。
二、快速上手:安装与 Hello World
2.1 安装 Argo Workflows
Argo 以命名空间级 CRD 方式部署,几条命令即可拉起控制器与 UI:
kubectl create namespace argo
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.5.5/install.yaml
# 为方便演示,临时改用 server 鉴权模式(生产请走 SSO/OIDC)
kubectl -n argo patch deploy argo-server \
-p '[{"op":"replace","path":"/spec/template/spec/containers/0/args","value":["server","--auth-mode=server"]}]' \
--type=json
kubectl -n argo port-forward svc/argo-server 2746:2746
部署前建议先复习 K8s 入门:Pod、Deployment、Service,理解命名空间、Service 与端口转发,安装过程会更顺。
2.2 第一个 Hello World
一个最小可运行的 Workflow,entrypoint 指向模板名,模板里声明容器镜像与命令:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: hello-world-
spec:
entrypoint: whalesay
templates:
- name: whalesay
container:
image: docker/whalesay:latest
command: [cowsay]
args: ["hello argo"]
使用 kubectl create -f hello.yaml 提交后,Argo 会为每个模板启动一个 Pod;用 kubectl get workflow 即可看到整体状态,比盯着一堆散落的 Job 清晰得多。
三、DAG 编排实战:依赖、并行与条件
真正的价值在 DAG:下面这条流水线表示「抽取数据 → 训练 → 评估 → 通知」,后一步依赖前一步成功,Argo 会自动按拓扑顺序调度,任务失败则后续节点不再启动。
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: dag-pipeline-
spec:
entrypoint: main
templates:
- name: main
dag:
tasks:
- name: extract
template: extract
- name: train
template: train
dependencies: [extract]
- name: evaluate
template: evaluate
dependencies: [train]
- name: notify
template: notify
dependencies: [evaluate]
- name: extract
container:
image: alpine:3.19
command: [sh, -c]
args: ["echo 'extracting data'"]
- name: train
container:
image: python:3.11
command: [python]
args: ["train.py"]
- name: evaluate
container:
image: python:3.11
command: [python]
args: ["evaluate.py"]
- name: notify
container:
image: curlimages/curl
command: [sh, -c]
args: ["curl -X POST https://hooks.example.com/done"]
3.1 用 withParam 做参数化批量任务
当需要对一组参数并行跑同一模板(例如对 10 个地区各训练一次),用 withParam 读取上一步输出的 JSON 数组,自动展开成多个 task:
- name: fan-out
dag:
tasks:
- name: train-region
template: train
arguments:
parameters: [{name: region, value: "{{item}}"}]
withParam: "{{tasks.list.outputs.result}}"
- name: train
inputs:
parameters: [{name: region}]
container:
image: python:3.11
command: [python]
args: ["train.py", "{{inputs.parameters.region}}"]
注意 {{tasks.xxx.outputs.result}} 这种表达式语法是 Argo 的变量替换机制,它让你能在步骤之间传递数据,而不必把中间结果写死在 YAML 里。
四、与 CI/CD 生态的边界
Argo 家族和周边工具容易让人混淆。一句话区分:Argo Workflows 编排「任务」,ArgoCD 实战:用 GitOps 实现 Kubernetes 持续部署 负责「把期望状态同步到集群」,Tekton 实战:K8s 原生 CI/CD 流水线 偏「构建与测试」,而 GitHub Actions 实战:从零搭建 CI/CD 流水线 更适合仓库级的 CI。它们可以组合,但职责不同。
| 工具 | 核心定位 | 典型触发 |
|---|---|---|
| Argo Workflows | 通用 DAG 任务编排 | 定时 / 手动 / 事件 |
| Argo CD | GitOps 持续部署 | Git 变更 |
| Tekton | 云原生 CI/CD | 代码推送 |
| GitHub Actions | 仓库级 CI | Push / PR |
五、生产实践:Artifact、重试与超时
5.1 重试与超时
生产环境最怕「偶发失败直接整条流水线挂掉」。Argo 内置 retryStrategy 与 timeout,把容错写进声明:
- name: train
retryStrategy:
limit: 3
backoff:
duration: "30s"
factor: 2
maxDuration: "5m"
timeout: 3600
container:
image: python:3.11
command: [python]
args: ["train.py"]
5.2 Artifact 在步骤间传递产物
训练产出的模型文件,需要交给评估步骤使用。Argo 通过 Artifact 仓库(MinIO/S3/GCS)在 Pod 之间传递,无需把大文件塞进 etcd:
- name: train
outputs:
artifacts:
- name: model
path: /tmp/model.pkl
s3:
endpoint: minio:9000
bucket: mlpipeline
key: models/{{workflow.name}}/model.pkl
container:
image: python:3.11
command: [python]
args: ["train.py", "--out", "/tmp/model.pkl"]
六、可观测与排障:把状态接进监控
流水线跑得多,就一定需要可观测。Argo 自带 Prometheus 指标(如 argo_workflows_count、argo_workflows_task_duration),配合 Prometheus+Grafana:K8s 监控告警实战 即可把「失败率、平均时长、卡住的工作流」做成看板。排障时优先三板斧:kubectl get workflow 看整体状态、kubectl logs -l workflows.argoproj.io/workflow=xxx 看聚合日志、进 Argo UI 点开 DAG 节点看单步失败原因。
如果任务本质上是「长期运行的服务编排」而非「一次性流水线」,也可以对照 Nomad 实战:用轻量级调度器统一编排容器与批处理任务 评估选型:Workflows 胜在 DAG 表达力与 K8s 原生,Nomad 胜在轻量与多负载统一调度。
七、定时与事件触发:CronWorkflow
手动提交只是开始,生产环境里更多依赖定时触发。Argo 提供了 CronWorkflow 资源,它像 Linux 的 crontab 一样,按标准 5 段 cron 表达式周期性地自动提交 Workflow,非常适合「每天凌晨训练一次」「每小时同步一批数据」这类场景。
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
name: nightly-train
spec:
schedule: "0 2 * * *"
concurrencyPolicy: Forbid
startingDeadlineSeconds: 300
workflowSpec:
entrypoint: main
templates:
- name: main
container:
image: python:3.11
command: [python]
args: ["train.py"]
其中 schedule 使用标准 cron 表达式;concurrencyPolicy: Forbid 能避免「上一次还没跑完,下一次又触发」的重叠执行——在每日训练这种长任务里尤其关键。此外 Argo 还支持基于事件(如 Git 推送、消息队列)的触发,通过 EventSource 与 Sensor 接入,适合做实时流水线。
八、常见误区与排障清单
在多个项目的实操里,我踩过不少坑,整理成一份高频问题清单,供你排障时对照使用:
| 现象 | 可能原因 | 排查对策 |
|---|---|---|
| Workflow 一直处于 Pending | 控制器未就绪或 RBAC 权限不足 | kubectl get pod -n argo 查控制器;检查 ServiceAccount 绑定 |
| 某 task 反复失败但日志空白 | 镜像拉取失败或命令路径写错 | kubectl describe pod 看 Events;先在本地跑通命令 |
| Artifact 上传失败 | MinIO endpoint 或密钥配置错误 | 用独立 mc 客户端验证存储连通性 |
| DAG 卡在中间节点不动 | 上游依赖失败且无重试 | 检查 retryStrategy 与 dependencies 拼写 |
另一类高频坑是「变量表达式写错」。Argo 的 {{...}} 在提交时由控制器渲染,一旦写成 {{tasks.x.outputs.result}} 但 x 并不是真实的 task 名,整个 Workflow 会直接校验失败而非单步失败,排查时要特别留意提交瞬间返回的报错信息。养成「先在本地用 argo lint 校验 YAML」的习惯,能省下大量来回试错的时间。
九、小结
Argo Workflows 把「多步任务的编排」从脆弱的脚本提升为声明式、可观测、可重试的 K8s 原生工作流。记住三件事:用 DAG 表达依赖、用 Artifact 传递产物、用重试与超时兜底生产稳定性。当你下一次要串起「数据 → 训练 → 评估 → 发布」时,它会是一个比 shell 脚本可靠得多的选择。




