痛点
你的 Kubernetes 集群里跑着一堆 CronJob:每小时清理日志、每天凌晨跑 ETL、定期生成报表。最初几个还好管,数量超过 30 个后问题集中爆发:
- 依赖关系没法表达——报表任务依赖 ETL 完成,但 CronJob 只能用"延迟 30 分钟启动"这种粗暴方式,ETL 慢了就拿到脏数据。
- 失败重试全靠运气——
backoffLimit只能整个 Job 重试,一个 5 步流程的第 4 步失败,得从头跑。 - 执行历史无法追溯——Job 跑完 Pod 就被 GC 了,排查问题时日志都找不到。
Jenkins Pipeline 能解决编排问题,但在 K8s 环境里它是个"异类"——Java 进程吃内存、插件体系老旧、和 K8s 原生资源割裂。你需要一个 Kubernetes 原生的工作流引擎。
方案:Argo Workflows
Argo Workflows 是 CNCF 毕业项目,专为 Kubernetes 设计的工作流引擎。核心特点:
- DAG + Steps 双模式:支持有向无环图和顺序步骤两种编排方式,天然表达任务依赖
- 每个步骤是一个 Pod:天然隔离、独立资源限制、可用任意容器镜像
- Artifact 传递:步骤间通过 S3/MinIO/OSS 自动传递文件产出物
- 原生重试与条件分支:单步骤重试、失败跳过、条件执行,不用从头来
- 完整 UI + API:内置 Web 界面查看执行历史、日志、DAG 拓扑图
实操步骤
第 1 步:安装 Argo Workflows
# 创建命名空间
kubectl create namespace argo
# 安装(快速模式,生产建议用 Helm)
kubectl apply -n argo -f https://github.com/argoproj/argo-workflows/releases/download/v3.6.4/quick-start-minimal.yaml
# 验证
kubectl -n argo get pods
# NAME READY STATUS RESTARTS AGE
# argo-server-xxxx 1/1 Running 0 30s
# workflow-controller-xxxx 1/1 Running 0 30s
# 暴露 UI(开发环境)
kubectl -n argo port-forward svc/argo-server 2746:2746 &
# 访问 https://localhost:2746
安装 CLI:
# Linux
curl -sLO https://github.com/argoproj/argo-workflows/releases/download/v3.6.4/argo-linux-amd64.gz
gunzip argo-linux-amd64.gz && chmod +x argo-linux-amd64 && mv argo-linux-amd64 /usr/local/bin/argo
argo version
第 2 步:编写 DAG 工作流——ETL Pipeline 示例
一个典型的数据处理流程:拉取数据 → 清洗 → 聚合(两个并行任务)→ 生成报表。
# etl-pipeline.yaml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: etl-pipeline-
namespace: argo
spec:
entrypoint: etl-dag
# Artifact 存储配置(生产用 S3/MinIO)
artifactRepositoryRef:
configMap: artifact-repositories
key: default-v1
templates:
- name: etl-dag
dag:
tasks:
- name: extract
template: run-step
arguments:
parameters: [{name: cmd, value: "echo 'Extracting data...' && curl -sL https://api.example.com/data > /tmp/raw.csv && echo 'Done'"}]
- name: clean
depends: "extract"
template: run-step
arguments:
parameters: [{name: cmd, value: "echo 'Cleaning data...' && sleep 5 && echo 'Clean done'"}]
- name: agg-daily
depends: "clean"
template: run-step
arguments:
parameters: [{name: cmd, value: "echo 'Daily aggregation...' && sleep 3"}]
- name: agg-weekly
depends: "clean"
template: run-step
arguments:
parameters: [{name: cmd, value: "echo 'Weekly aggregation...' && sleep 3"}]
- name: report
depends: "agg-daily && agg-weekly"
template: run-step
arguments:
parameters: [{name: cmd, value: "echo 'Generating report...' && sleep 2 && echo 'All done!'"}]
- name: run-step
inputs:
parameters: [{name: cmd}]
retryStrategy:
limit: 3
retryPolicy: "OnError"
backoff:
duration: "30s"
factor: 2
container:
image: curlimages/curl:8.10.1
command: [sh, -c]
args: ["{{inputs.parameters.cmd}}"]
resources:
requests:
memory: "64Mi"
cpu: "100m"
limits:
memory: "256Mi"
cpu: "500m"
提交并查看:
argo submit etl-pipeline.yaml --watch
# 实时看到 DAG 各节点状态:extract ✔ → clean ✔ → agg-daily ✔ / agg-weekly ✔ → report ✔
# 查看所有工作流
argo list -n argo
# NAME STATUS AGE DURATION
# etl-pipeline-x7k2p Succeeded 2m 45s
# 查看单步骤日志
argo logs etl-pipeline-x7k2p --follow
在 UI 中你能看到 DAG 拓扑图,每个节点可点击查看日志、耗时、资源用量——CronJob 做不到的可视化。
第 3 步:配置定时触发(CronWorkflow)
用 CronWorkflow 替代 K8s CronJob,获得完整的执行历史和重试能力:
# etl-cron.yaml
apiVersion: argoproj.io/v1alpha1
kind: CronWorkflow
metadata:
name: etl-daily
namespace: argo
spec:
schedule: "0 2 * * *" # 每天凌晨 2 点
timezone: "Asia/Shanghai"
concurrencyPolicy: "Replace" # 上一次没跑完就替换
successfulJobsHistoryLimit: 7 # 保留 7 天成功记录
failedJobsHistoryLimit: 14 # 保留 14 天失败记录
workflowSpec:
entrypoint: etl-dag
templates:
# ... 同上 DAG 模板
kubectl apply -f etl-cron.yaml
argo cron list -n argo
# NAME SCHEDULE TIMEZONE SUSPENDED
# etl-daily 0 2 * * * Asia/Shanghai false
对比 CronJob 的核心优势:successfulJobsHistoryLimit 配合 UI 可追溯每次执行的 DAG 状态和日志,故障排查效率提升一个量级。
避坑指南
坑 1:Pod GC 策略未配置,Completed Pod 堆积把节点打满
Argo 默认不清理已完成的 Pod。集群跑几百个 Workflow 后,Completed 状态的 Pod 堆积上千个,kubelet 的 Pod 列表查询变慢,甚至影响调度。
解法:在 Workflow 或 Controller 级别配置 podGC:
spec:
podGC:
strategy: OnWorkflowCompletion # Workflow 结束后清理所有 Pod
# 其他选项:OnPodSuccess / OnPodCompletion
ttlStrategy:
secondsAfterCompletion: 86400 # Workflow 记录保留 24 小时
坑 2:步骤间传数据用 Volume 共享,多节点集群翻车
开发环境单节点用 emptyDir 共享没问题,上了多节点集群后不同步骤 Pod 可能调度到不同 Node,emptyDir 数据丢失。
解法:用 Argo 原生的 Artifact 机制,配 S3 或 MinIO 做中转:
# 在 argo 命名空间创建 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: artifact-repositories
namespace: argo
data:
default-v1: |
s3:
bucket: argo-artifacts
endpoint: minio.minio:9000
insecure: true
accessKeySecret:
name: argo-minio-creds
key: accessKey
secretKeySecret:
name: argo-minio-creds
key: secretKey
坑 3:RBAC 权限不足导致 Workflow 提交 403
Argo 需要创建 Pod、ConfigMap 等资源的权限。默认安装的 ServiceAccount 权限在 argo 命名空间内有效,跨命名空间提交会 403。
解法:为目标命名空间创建专用 ServiceAccount + RoleBinding:
# 在 data-team 命名空间创建 Argo 执行角色
kubectl create rolebinding argo-workflow \
--clusterrole=argo-workflow-role \
--serviceaccount=data-team:argo-workflow \
-n data-team
总结
| 维度 | K8s CronJob | Jenkins Pipeline | Argo Workflows |
|---|---|---|---|
| 任务依赖 | ❌ 无 | ✅ Stage 依赖 | ✅ DAG + Steps |
| 单步重试 | ❌ 整 Job 重试 | ⚠️ 需插件 | ✅ 原生支持 |
| 执行历史 | ⚠️ Pod 被 GC 就没了 | ✅ 但 Java 进程重 | ✅ CRD 持久化 |
| K8s 原生 | ✅ | ❌ 外挂 | ✅ CRD |
| 可视化 | ❌ | ✅ BlueOcean | ✅ 内置 DAG UI |
Argo Workflows 的定位很清晰:当你的 K8s 集群里有超过 10 个 CronJob 或批处理任务,且存在依赖关系和重试需求时,它就是 Kubernetes 原生的最优解。配合已有的 Argo CD(持续部署)和 Argo Rollouts(渐进交付),可以构建完整的 Argo 生态工作流体系。
落地建议:先从一个现有的多步骤 CronJob 迁移起,验证 DAG 编排和 Artifact 传递能力,再逐步推广到数据处理、AI 训练、自动化运维等场景。