饮墨

子安饮墨馀三斗,留与卿儿作赋来

Argo Workflows 实战:3 步在 Kubernetes 上搭建声明式任务编排引擎,替代 Jenkins Pipeline 和 CronJob

7 views

痛点

你的 Kubernetes 集群里跑着一堆 CronJob:每小时清理日志、每天凌晨跑 ETL、定期生成报表。最初几个还好管,数量超过 30 个后问题集中爆发:

  1. 依赖关系没法表达——报表任务依赖 ETL 完成,但 CronJob 只能用"延迟 30 分钟启动"这种粗暴方式,ETL 慢了就拿到脏数据。
  2. 失败重试全靠运气——backoffLimit 只能整个 Job 重试,一个 5 步流程的第 4 步失败,得从头跑。
  3. 执行历史无法追溯——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 训练、自动化运维等场景。