我把 Jenkins 夜间批处理迁到 Argo Workflows 后,K8s 资源利用率从 23% 提到 71%

发布时间:2026/9/25 2:56:22

我把 Jenkins 夜间批处理迁到 Argo Workflows 后,K8s 资源利用率从 23% 提到 71% 我把 Jenkins 夜间批处理迁到 Argo Workflows 后K8s 资源利用率从 23% 提到 71%说实话我之前一直觉得 Jenkins 夜间跑批处理这事挺稳的。凌晨 0 点 30 分自动触发三台固定 slave 节点吭哧吭哧跑 5 个多小时第二天早上我上班看报告就行。直到有天早上 7 点 15 分我打开 Grafana 看到三条曲线三台 slave 的 CPU 平均 11%队列长度 47最长一个 job 在队列里躺了 4 小时 12 分钟。那一刻我就意识到我们不是缺资源而是在把资源当摆设。白天三台机器空转晚上任务又互相排队等锁。这种架构不改成本只会越来越高。01 问题Jenkins 批处理就像租了三间常年空着的仓库先交代一下我们的 nightly 流程大概是给第二天 BI 报表准备数据00:30 从 6 个业务库抽取增量数据01:00 做清洗、脱敏、打标签生成中间表02:00 跑三个模型训练任务输出特征权重和预测结果03:30 汇总报告生成 CSV 和 PDF04:30 推送到数据仓库和对象存储05:00 触发下游 BI 刷新。全部写在一个 Jenkins pipeline 里串在 3 台固定节点nightly-slave-01/02/03上。每台 8C16G全年 24 小时开机只为凌晨 6 小时服务。更难受的是一次故障。1 号节点凌晨 2 点因为磁盘满了 crash整个 pipeline 从头再来。早上 8 点业务上班报表还没出来老板直接在群里 我。我列了 5 个核心痛点资源分配和任务调度强耦合。slave 一旦绑定任务其他 job 只能排队即使旁边节点空闲。失败重试粒度是整个 pipeline。一个步骤失败前面 2 小时全部白跑。没有真正的 DAG。步骤之间要么全串行要么靠 shell 里写自己拼出错很难定位。资源利用率极低。白天三台机器 95% 时间空转凌晨又因为串行导致节点利用率起不来。扩容成本线性。想加并发加机器。机器加完白天继续空转。我算了一笔账三台 8C16G 云主机按包年包月每月 3200 块一年接近 4 万。但这三台机器真正在干活的时间每月不到 180 小时利用率不到 25%。02 选型为什么是 Argo Workflows 而不是 Airflow / Temporal我先看了一圈方案Airflow编排能力强生态成熟。但对我们来说太重需要单独维护 scheduler、webserver、metadata DB而且任务最终还是要跑在 K8s Pod 上多了一层抽象。Temporal我之前做对账系统时用过durable execution 很强适合长状态、需要补偿的业务流程。但批处理场景我们更想要 “任务即容器”不想常驻 worker 吃资源。Argo Workflows直接基于 K8s CRDWorkflow 就是一组 Pod 的 DAG。天然能分时复用节点资源失败可以按 step 重试扩缩完全交给 K8s scheduler。最终选 Argo Workflows 的核心原因就一句话它让我把 “任务调度” 交给 K8s scheduler把 “业务编排” 交给 YAML。没有额外中间层也少了一套系统需要维护。03 迁移两周时间分四步走我没敢一次性全切而是制定了为期两周的迁移计划第 1-2 天在测试 namespace 部署 Argo Workflows controller验证 WorkflowTemplate 和 CronWorkflow 基本功能第 3-5 天把 nightly pipeline 拆成 5 个 DAG step在测试环境跑通三次完整流程第 6-10 天灰度切流50% 日期用 Argo、50% 日期仍用 Jenkins对比耗时和资源占用第 11-14 天全量切到 Argo回收 Jenkins slave 节点补监控和告警。下面说说拆分 DAG 时的具体做法。整个流程拆成 5 个 stepextract → transform → train → export → load-to-warehouse每个 step 运行在自己的 Pod 里依赖关系通过 DAG 表达。transform 必须等 extract 完成export 必须等 train 完成但 extract 和后续一些前置准备可以并行。3.1 用 WorkflowTemplate 沉淀可复用模板我先写了一个通用模板所有 step 都引用它apiVersion:argoproj.io/v1alpha1kind:WorkflowTemplatemetadata:name:nightly-batch-stepnamespace:batchspec:templates:-name:batch-containerinputs:parameters:-name:image-name:command-name:cpuvalue:500m-name:memoryvalue:1Gi-name:storagevalue:10Gicontainer:image:{{inputs.parameters.image}}command:[/bin/sh,-c]args:[{{inputs.parameters.command}}]resources:requests:cpu:{{inputs.parameters.cpu}}memory:{{inputs.parameters.memory}}limits:cpu:{{inputs.parameters.cpu}}memory:{{inputs.parameters.memory}}volumeMounts:-name:batch-datamountPath:/datavolumes:-name:batch-datapersistentVolumeClaim:claimName:batch-data-pvc统一模板的好处很明显每个 step 只声明自己需要的资源训练 step 给 4C8G导出 step 给 500m/1Gi谁也不多占。资源请求精确到 step 级别K8s scheduler 才能把碎片时间利用起来。3.2 CronWorkflow 定时触发然后用 CronWorkflow 替代 Jenkins 的定时任务apiVersion:argoproj.io/v1alpha1kind:CronWorkflowmetadata:name:nightly-pipeline-v2namespace:batchspec:schedule:30 0 * * *timezone:Asia/ShanghaistartingDeadlineSeconds:120concurrencyPolicy:ForbidsuccessfulJobsHistoryLimit:3failedJobsHistoryLimit:3workflowSpec:entrypoint:nightly-dagserviceAccountName:argo-batch-satemplates:-name:nightly-dagdag:tasks:-name:extracttemplateRef:name:nightly-batch-steptemplate:batch-containerarguments:parameters:-name:imagevalue:registry/batch-extract:v2.1-name:commandvalue:python extract.py --date {{workflow.parameters.batch-date}}-name:storagevalue:50Gi-name:transformdependencies:[extract]templateRef:name:nightly-batch-steptemplate:batch-containerarguments:parameters:-name:imagevalue:registry/batch-transform:v2.1-name:commandvalue:python transform.py --stage full-name:cpuvalue:2-name:memoryvalue:4Gi-name:storagevalue:80Gi-name:traindependencies:[transform]templateRef:name:nightly-batch-steptemplate:batch-containerarguments:parameters:-name:imagevalue:registry/batch-train:v2.1-name:commandvalue:python train.py --models all-name:cpuvalue:4-name:memoryvalue:8Gi-name:storagevalue:100Gi-name:exportdependencies:[train]templateRef:name:nightly-batch-steptemplate:batch-containerarguments:parameters:-name:imagevalue:registry/batch-export:v2.1-name:commandvalue:python export.py-name:load-to-warehousedependencies:[export]templateRef:name:nightly-batch-steptemplate:batch-containerarguments:parameters:-name:imagevalue:registry/batch-load:v2.1-name:commandvalue:python load.py --warehouse prod这里有两个细节我认为很关键concurrencyPolicy: Forbid防止前一次没跑完又触发一次造成资源踩踏startingDeadlineSeconds: 120如果 2 分钟内 scheduler 没把 workflow 调度起来直接视为失败避免静默错过调度窗口。3.3 资源分时复用训练 step 独占、其余 step 错峰填缝我把训练 step 放在 01:30-03:00 这个窗口给它nodeAffinity优先落到带高内存的节点上。其他导出、load 步骤用通用计算节点跑完立刻释放。affinity:nodeAffinity:preferredDuringSchedulingIgnoredDuringExecution:-weight:100preference:matchExpressions:-key:workload-typeoperator:Invalues:[batch-memory]结果是同一批节点白天跑微服务 Pod凌晨跑批处理 Pod24 小时都有人干活。K8s 集群的夜间利用率从 23% 直接拉到 71%。04 量化对比23% → 71% 是怎么算的改造前后各跑了两周数据如下。需要说明的是灰度阶段我用标签把 Jenkins 和 Argo 跑的日子区分开确保对比的是同一业务负载指标改造前Jenkins改造后Argo变化夜间固定节点数3 台0 台全部释放夜间平均 CPU 利用率23%71%48%夜间平均内存利用率31%68%37%pipeline 平均耗时5h 40min2h 15min-60%最长排队等待4h 12min0消除单 step 失败重跑耗时从头 5h平均 8min按 step 重试月均节点成本约 3,200 元约 1,100 元-66%调度失败次数/周2-3 次0 次消除数据产出准时率87%100%稳定 5:30 前产出说明一下利用率计算的是凌晨 0-6 点批处理窗口内所有实际运行 Pod 的container_cpu_usage_seconds_total / kube_pod_container_resource_requests_cpu平均值没有到 100% 是因为 K8s 预留了系统进程、kubelet 开销以及我们故意保留了 20% buffer 防止某个 step 突发暴涨成本下降主要来自于白天不再保留空转节点批处理 Pod 用集群现有容量跑完即走。最让我意外的是 pipeline 耗时从 5 小时 40 分降到 2 小时 15 分。原因不是机器变快了而是 DAG 把能并行的步骤并行起来并且 K8s scheduler 能根据资源实时填缝不再受固定 slave 的锁限制。05 踩坑记录这 5 条建议能省你半天1. 默认 Pod 起不来检查 service account 权限Argo controller 需要给 Pod 创建、查看日志等权限。如果 service account 没配workflow 会一直 Pending。我建了一个专用 sa 和 roleapiVersion:v1kind:ServiceAccountmetadata:name:argo-batch-sanamespace:batch---apiVersion:rbac.authorization.k8s.io/v1kind:Rolemetadata:name:argo-batch-rolenamespace:batchrules:-apiGroups:[]resources:[pods,pods/log]verbs:[get,list,watch]-apiGroups:[argoproj.io]resources:[workflows]verbs:[get,list,watch]---apiVersion:rbac.authorization.k8s.io/v1kind:RoleBindingmetadata:name:argo-batch-bindingnamespace:batchsubjects:-kind:ServiceAccountname:argo-batch-sanamespace:batchroleRef:kind:Rolename:argo-batch-roleapiGroup:rbac.authorization.k8s.io2. 大文件不要用默认 minio artifact 存储我们一开始用 minio 做 artifacttransform 输出 60GB Parquet每次上传下载要 20 分钟。后来改成 NFS 共享卷 volumeClaimTemplates同 namespace 下多个 step 直接挂载省掉串行上传。volumeClaimTemplates:-metadata:name:batch-dataspec:accessModes:[ReadWriteOnce]storageClassName:nfs-batchresources:requests:storage:100Gi3. retryStrategy 别只写 count要写 expression无脑重试会把 OOM 也重试 3 次浪费资源。我改成只重试非资源类失败retryStrategy:limit:3retryPolicy:OnErrorexpression:asInt(lastRetry.exitCode) ! 137 asInt(lastRetry.exitCode) ! 143137 是 OOMKilled143 是 SIGTERM这两种情况重试基本没用应该直接告警人工介入。4. CronWorkflow missed schedule 很难查有天凌晨 pipeline 没触发查了半天才发现 controller 当时重启了。建议配 Prometheus 告警-alert:ArgoCronWorkflowMissedScheduleexpr:|(argo_workflows_cronworkflows_info - argo_workflows_cronworkflows_triggered_total) 0for:5mlabels:severity:warningannotations:summary:CronWorkflow missed schedule5. 监控 UI 只看 Argo UI 不够要加 workflow_duration 和 pod_phase我搭了 Grafana 看板核心指标有三个argo_workflows_workflow_duration按 workflow 名分位看整体耗时趋势kube_pod_status_phase{phase~Pending|Failed}按 workflow 标签过滤快速定位卡住的 Podcontainer_cpu_usage_seconds_total / kube_pod_container_resource_requests_cpu_cores按 Pod 聚合算实际资源利用率。另外我还加了一个指标每个 CronWorkflow 的last_successful_time和last_scheduled_time差值超过 10 分钟就触发告警。这个比单纯看 Pod 是否成功更直接因为有时候 workflow 根本没被触发Pod 监控是看不到的。6. 别忘了给 Argo 组件本身做高可用controller 默认只跑一个副本某天节点维护时它重启了导致 3 个 workflow 同时挂起。我后来给 controller 配了 2 个副本 PodDisruptionBudget并把它固定在两个不同可用区的节点上。虽然 Argo 号称 stateless但 controller 重启时正在执行的 workflow 会短暂卡住关键业务还是要考虑这一点。07 迁移 checklist如果你也准备动手按这个顺序来我把这次迁移的 checklist 整理出来方便你复制粘贴梳理现有 pipeline画出每个步骤的输入输出、执行时间、资源占用、失败重试点搭建 Argo Workflows先在测试 namespace 部署 controller确认版本 ≥ 3.5开启 metrics 端点设计 WorkflowTemplate把通用容器模板抽象出来参数化 image、command、cpu、memory拆 DAG用依赖关系替代时间 sleep把能并行的步骤并行选 artifact 方案小文件用 minio/S3大文件用共享 PVC 或 NFS配 RBAC service account给 workflow Pod 最小权限别用 default sa写 CronWorkflow设置concurrencyPolicy: Forbid和startingDeadlineSeconds灰度对比至少跑 5-7 天双跑记录耗时、资源利用率、失败率加监控告警workflow_duration、pod_phase、cron missed schedule、资源利用率回收旧资源确认稳定后再下线 Jenkins slave 节点省钱。按这个顺序走基本不会踩大坑。06 架构讨论不是 Jenkins 不好是用错了地方迁移完我复盘了一下Jenkins 并不是被 “淘汰” 了而是回归它该干的事CI/CD 流水线、代码构建、镜像打包。这些场景 Jenkins 的插件生态和可视化流水线依然很能打。批处理这种 “定时触发、DAG 编排、资源弹性” 的场景交给 K8s-native 的 Argo Workflows 更对味。整个架构变成GitLab / GitHub - Argo Workflows - K8s Job Pod ^ | CronWorkflow 定时触发 | Prometheus Grafana 监控这个架构的核心好处是调度层和编排层分离。调度层K8s scheduler 根据节点资源实时决定 Pod 落在哪台机器上不需要人工指定 slave编排层Argo Workflows 用 DAG 表达依赖失败重试可以精确到 step资源层Pod 跑完即释放不再占用固定节点白天和晚上都能充分利用集群。如果规模再大一点我会考虑这几个方向Argo Events做事件触发替代部分 CronWorkflow。比如上游数据到达 S3 后自动触发 workflow而不是死等半夜 0 点 30 分Hera SDK让数据科学家用 Python 写 workflow而不是手写 YAML。团队里大部分人不是 K8s 专家降低门槛很重要workflow-level 成本分摊把每个批处理任务的资源成本打到业务线账上。这一步做好了能反向推动业务优化自己的任务资源申请archive 和 artifact GC 策略。workflow 历史记录默认保存在 etcd 里跑久了会成为集群负担需要定期归档到 S3 并清理。还有一个很多人忽略的点是Argo Workflows 让你的批处理变成了 “声明式” 的。以前 Jenkins pipeline 的改动是改 Groovy 脚本现在改 YAML 并走 Git 流程。配合 Argo CD 或 Flux批处理流程本身也可以被 GitOps 管理。写在最后这次迁移最值钱的一课不是学会了 Argo Workflows 的 YAML 语法而是让我重新理解了 “资源利用率” 这个词。以前我以为利用率低就是机器买大了。其实很多时候是调度模型太旧。把任务从固定节点里解放出来让 K8s 根据实际资源去填缝71% 并不是上限而是我们刻意留的 buffer。如果胆子大一点把训练任务进一步拆分并行把 buffer 压到 10%利用率还能再往上走。对于还在用 Jenkins 跑定时批处理的团队我的建议是分步走先拿一条非核心 pipeline 试点跑通 WorkflowTemplate 和 CronWorkflow再逐步把高耗时的步骤拆成独立 Pod最后把资源请求精确化让 scheduler 真正发挥作用。不要一上来就追求全切灰度对比数据才是说服老板和团队最好的材料。Argo Workflows 的 YAML 乍看啰嗦但写顺之后你会爱上那种 “资源按任务走失败按步回滚” 的清爽感。下一篇我可能会写写怎么用 Argo Events 把这些批处理改成事件驱动或者聊聊用 Hera SDK 让数据团队不写 YAML 也能跑 Argo。感兴趣的可以蹲一下。参考链接Argo Workflows 官方文档https://argoproj.github.io/argo-workflows/CronWorkflow 调度说明https://argoproj.github.io/argo-workflows/cron-workflows/Hera Python SDKhttps://github.com/argoproj-labs/hera
延伸阅读

更多相关文章

2026/9/20 3:27:37

从电竞选手行为分析看团队协作:环境、角色与个人表现的动态关系

这类围绕职业选手、教练和队伍内部关系的讨论,最值得关注的往往不是单方面的“爆料”,而是如何理解不同环境下选手表现出的差异,以及这些信息对于理解团队协作和选手成长的实际价值。对于关注电竞、团队管理或者单纯想了解选手另一面的读者来…

2026/9/20 7:19:28

Claude封号引发人机恋危机:用户如何面对AI恋人的“离去”?

【突如其来的告别】2026年6月27日晚,演唱会终场曲响起,刘洋收到Anthropic的封号通知,这天是她与AI恋人Claude相识满一个月纪念日。同一时间,大量中国Claude用户账号被封,账号里的聊天记录、共同记忆及AI“恋人”面临消…

2026/9/21 3:47:05

基于YOLO与Web技术的危险物品检测系统实战指南

1. 项目概述:从需求到实现的完整闭环 最近在做一个挺有意思的项目,一个基于深度学习的危险物品检测系统,而且带网页界面。这玩意儿听起来挺高大上,但其实核心逻辑很清晰:就是让电脑能像人一样,从摄像头或者…

2026/9/25 2:52:41

C#实现欧姆龙PLC FINS通信:绕过地址偏移、字节序与帧头校验

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/25 2:52:41

HHO-LSBoost多输入回归预测:哈里斯鹰优化与Matlab实现

做预测建模这些年,我最深刻的体会就是:调参的功夫往往比跑模型本身还多。尤其是用集成学习做回归预测时,弱学习器的数量、学习率、树深这些超参数,直接决定了模型的上限,可手动一个个试又费时又费力。所以当我尝试把哈…

2026/9/25 2:52:41

四向链表从创建到遍历:指针维护与DFS/BFS实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/24 20:24:47

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/25 0:02:35

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:02:35

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:02:35

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑