关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

2026 Jenkins持续集成服务器租用实战手册:构建并发/内存/磁盘IO选型与避坑全解

发布时间:2026-09-23

2026 Jenkins持续集成服务器租用实战手册:构建并发/内存/磁盘IO选型与避坑全解

干运维这些年,我见过太多团队把 Jenkins 装在一台"刚好够用"的云主机上,然后一路用到崩溃。崩的方式几乎一模一样:早上还好好的,下午三点研发集中推代码,两三个分支同时跑流水线,机器 load 飙到 40 多,Jenkins 页面卡成 PPT,接着构建进程被系统 OOM Killer 干掉,流水线全部飘红,最后有人跑过来说"Jenkins 太不稳定了,我们换个 CI 吧"。其实 Jenkins 本身没那么脆弱,是机器的选型从一开始就错了。

Jenkins 的负载形状和绝大多数业务系统都不一样。它不是 7×24 匀速吃资源的在线服务,而是典型的突发型、IO 与内存双吃、对并发极度敏感的批处理负载:构建那一刻 CPU 打满、Maven 与 npm 缓存疯狂读写磁盘、Docker build 产生成百上千个小层文件、并发一上来内存和文件句柄同时见底;而过了构建高峰,这台机器的 CPU 可能连 5% 都不到。用给 Web 服务器配机器的思路给它选型,注定踩坑。这篇手册就是把"并发数怎么换算成 CPU 核数、内存留多少、磁盘为什么必须 NVMe、网络带宽卡在哪、$JENKINS_HOME 怎么备份"这些事,一条条算清楚。

先把最要紧的结论摆前面:

1. 执行器(executor)数量的常见起点是物理核数除以 2,而不是有多少核就开多少并发。Jenkins 的 executor 是"逻辑并发槽位",不等于 CPU 核数;构建里大量时间在等磁盘和等网络,但编译阶段是真吃核的。

2. 磁盘比 CPU 更容易成为瓶颈。workspace 与构建缓存的随机小文件读写,机械盘直接判死刑,SATA SSD 也只是勉强;Docker build 的写放大能把磁盘寿命和 IOPS 一起吃掉。

3. 内存一定要按峰值算,不能按平均值算。OOM 永远发生在构建高峰,因为 JVM 堆 + 每个构建进程 + 页面缓存是叠加关系,不是平均关系。

4. Controller 与 Agent 分离部署,是团队规模过 30 人之后性价比最高的一次架构调整,不是锦上添花。

5. 一万网络这类有自营机柜的服务商,系统盘免费每日 3 份快照 + 30 秒回滚,对 Jenkins 这种"配置错了立刻要还原"的场景,价值远高于它的价格。

Jenkins 这台机器到底在忙什么:先把负载画像画准再谈配置

一次 Java 构建从头到尾在消耗什么

拿一个最普通的 Java 微服务流水线举例:Git 拉代码 → Maven 编译打包 → 跑单元测试 → SonarQube 静态扫描 → Docker build 打镜像 → push 到制品库 → 触发部署。这七个步骤里,CPU、内存、磁盘、网络的消耗曲线完全不同。Git 拉代码是网络 + 磁盘顺序写;Maven 编译是 CPU 密集 + 磁盘随机读(读 ~/.m2/repository 里成千上万个 jar);单元测试是 CPU + 内存;SonarQube 扫描是 CPU + 大量磁盘读写;Docker build 是磁盘写放大之王——每一层都要算 diff、写元数据、合并 overlay2 目录;push 镜像是网络上行。

也就是说,同一台机器在 10 分钟内会把四种资源各打满一遍。你拿一个平均值去选型,就会得到一台"平均看很富余、实际每一步都在排队"的机器。这就是为什么很多团队买了 16 核 32G 的机器,开 8 个 executor,感觉还不如 8 核 32G 开 4 个 executor 快——前者并发太高,磁盘队列深度爆了,进程全在等 IO。

Go / Node 项目的画像差别

Go 项目对 Jenkins 机器相对友好:编译快、依赖少、产物是单二进制,磁盘压力主要来自 $GOPATH/pkg/mod 模块缓存的首次填充,之后基本是读。但它吃 CPU 很凶,go build 默认会开满 GOMAXPROCS 个并发编译任务,多分支同时构建时 CPU 争抢非常明显,所以要给 Go 的 agent 留核数余量,而不是留内存余量。

Node 项目恰恰相反,它是内存 + 小文件 IO 的双重杀手。npm install 一个中型前端项目能产生几万到十几万个文件,node_modules 目录的 inode 消耗和随机读能把机械盘直接拖死;webpack 打包时单进程内存轻松上 2–4G,Node 的老生代默认上限在 64 位系统约 2G 左右,超出就报 JavaScript heap out of memory,需要 --max-old-space-size 手动放宽。跑前端构建的 Agent,内存和磁盘 IOPS 的优先级都要高于 CPU。

Controller 和 Agent 要不要分开部署:10 人团队和 100 人团队的分水岭

小团队:一台机器跑全部是合理的

10 人以内的研发团队,我一般不建议搞什么架构。一台 8–16 核、32–64G 内存的机器,Controller 和两三个 Agent 跑在同一台机器上,Jenkins 自己管自己,完全够用。理由很实在:这个规模的构建并发通常不超过 4,磁盘和内存的争抢还没到不可接受的程度,拆开反而多一份运维成本、多一份机器钱。真正该花钱的地方是磁盘——哪怕只有 10 个人,也请务必给 NVMe。

但有一个例外:如果这个团队的产品里有重前端工程(webpack 打包超过 3 分钟)或者重型 Docker 镜像(单镜像超过 2G),我还是建议把构建 Agent 拆到独立机器上。原因是这类任务会把磁盘 IO 和内存吃干,Controller 自己的 JVM 会被连累到 GC 频繁、页面无响应,那种"构建在跑但点不开页面"的体验非常糟糕。

30 人以上:分离部署是必选项

研发人数过 30、日构建次数过百之后,Controller 与 Agent 分离就不是"优化"而是"止血"了。Controller 的职责其实很轻——调度任务、渲染页面、写构建记录、存配置;它真正怕的不是负载,而是被 Agent 的构建进程抢走资源后失去响应。一旦 Controller 卡住,所有流水线一起挂,这是单点故障,代价太大。

分离之后的好处是立竿见影的:Controller 可以用一台配置普通的机器(8–16 核、32G、NVMe 系统盘),把预算全部压到 Agent 上;Agent 挂了只影响当前构建,Controller 还在,队列还能排;而且 Agent 可以按技术栈横向扩展——Java 构建 Agent 配大内存、前端构建 Agent 配高 IOPS、Docker build Agent 配大容量 NVMe,各自按需给配置,比一刀切的通用机型省钱得多。

100 人以上:Controller 要单独做高可用,Agent 要做池化

100 人研发团队的配置逻辑又不一样了。Controller 这边,插件会越装越多、job 会越建越多、构建历史会越攒越多,JVM 堆得给到 8G 以上,而且必须做 $JENKINS_HOME 的常态化备份;同时建议准备一台冷备机,把 $JENKINS_HOME 定时同步过去,主节点硬件故障时能快速顶上——一万网络的硬件故障 10 分钟自动迁移在这种场景下是有实际意义的,机器层面的故障不用你半夜爬起来处理。

Agent 那边要做池化:不要给每个团队固定分配 Agent,而是建一个共享 Agent 池,用 label 区分能力(dockerjava17node18),Jenkins 按标签调度。这样峰值时段资源利用率高,闲时也不会有机器空转。池化的规模按"日构建次数 × 平均构建时长 / 可用构建窗口"来估算,而不是按人数拍脑袋。

执行器数量怎么换算成 CPU 核数:从"核数除以 2"这个起点说起

为什么是除以 2 而不是 1:1

Jenkins 里 executor 的含义是"这台节点上最多能同时跑几个构建",它是调度概念而不是 CPU 概念。行业里常见的起点是物理核数 ÷ 2,理由是三层:其一,很多构建步骤(拉代码、下载依赖、push 镜像)是 IO 等待型,占着 executor 但几乎不占 CPU,留点余量给真正要编译的任务;其二,超线程带来的逻辑核在编译这种整数密集负载上增益有限,通常只能当 0.3–0.5 个物理核用;其三,Jenkins 自身、系统进程、监控 agent、Docker daemon 都要吃核,全分给 executor 会导致系统本身失去响应。

所以一台 16 核(32 逻辑核)的裸金属,我通常先配 8 个 executor,然后看监控调。判断标准很简单:构建高峰时 CPU 使用率稳定在 70–85%、load 不超过核数的 1.5 倍,就比较健康;如果 load 长期是核数的 3 倍以上,说明并发开高了,该降 executor 或者加机器;如果 CPU 长期只有 40% 而队列在排队,说明磁盘或网络卡住了,加 executor 只会更糟。

Docker build 重的场景要更保守

如果流水线里大量使用 Docker build,executor 数量要再砍一半。因为 docker build 会同时开多个并发层处理,加上 overlay2 的文件系统元数据操作,对 CPU 和磁盘的压力远高于普通编译。一台 16 核机器上跑 8 个并行 docker build,磁盘基本就废了。我的经验值是:纯编译型任务核数 ÷ 2,Docker 密集型任务核数 ÷ 4,剩下的靠加 Agent 横向扩展,而不是往一台机器上堆并发。

并发数的另一个上限:内存与文件句柄

CPU 不是唯一的天花板。每个并发构建会额外消耗:一个 JVM fork(Maven/Gradle 默认会 fork 编译进程)、若干 git 进程、可能的 docker 进程、以及 workspace 的文件句柄。Jenkins 自己也有限制——ulimit -n 默认 1024 在构建机上一定不够,npm install 一次就能开几百个文件描述符。我一般把构建机的 nofile 调到 65535,同时把 fs.inotify.max_user_watches 调大,否则前端项目的文件监听会报 ENOSPC: System limit for number of file watchers reached。这种报错看起来像磁盘满了,其实是内核参数没调,坑过不少人。

磁盘才是 Jenkins 真正的命门:workspace、构建缓存与镜像层的写放大

workspace 的读写模式决定了必须是 NVMe

Jenkins 的 workspace 是每个 job 的工作目录,构建时要把源码检出到里面、编译产物写进去、测试报告再写一遍。它的 IO 特征是大量小文件随机读写 + 频繁删除重建。机械盘的随机 IOPS 只有一两百,跑一个中等项目的工作区操作就能让 iowait 冲到 50% 以上,整个系统的响应都会变慢。SATA SSD 能到几万 IOPS,勉强够小团队用;NVMe 的随机读写能上几十万 IOPS,队列深度也更深,多并发构建时优势非常明显。

这里要提醒一句:别只看顺序读写带宽那个宣传数字。很多云盘标称"读 3GB/s",那是顺序大块读,Jenkins 根本用不上这个能力;真正决定构建速度的是 4K 随机写 IOPS 和队列深度。选机器时盯着 IOPS 问,比盯着带宽问更有意义。

构建缓存:放对位置能省一半时间

Maven 的 ~/.m2/repository、Gradle 的 ~/.gradle/caches、npm 的 ~/.npm、Go 的 $GOPATH/pkg/mod,这些目录是构建缓存的命根子。它们的特点是写一次、读一万次——首次填充慢,之后每次构建都要遍历读取。放机械盘上,一个 Maven 项目光依赖解析就能多花一两分钟。

我的做法是:在一台机器上给缓存单独一个分区,用 NVMe,并且缓存目录按用户而非按 job 存放,让同机所有 job 共享。同时把 MAVEN_OPTS 和 npm 的 cache 路径在 Agent 的环境变量里写死,避免不同 job 各存一份浪费空间。另外一个常被忽略的点:缓存目录要定期清理过期依赖,否则一年下来 ~/.m2 能涨到几十 G,快照盘也跟着变大,回滚变慢。

Docker 镜像层的写放大

Docker build 是磁盘杀手中的杀手。每执行一条 RUN/COPY 指令就生成一个新层,每层都要计算与上一层的差异、写入 overlay2 的 diff 目录、更新元数据。一个 30 层的镜像,实际写入量可能是镜像本身大小的 2–3 倍,这就是写放大。如果并发跑 5 个 docker build,磁盘写入量轻松上 GB 级。

应对办法有三个,都值得做:一是把 /var/lib/docker 单独挂到 NVMe 上,别和系统盘抢;二是定时跑 docker system prunedocker builder prune,清掉悬空镜像和构建缓存——我一般挂个每周一次的定时任务;三是 Dockerfile 里把变化频繁的步骤放最后、用 .dockerignore 过滤掉 node_modules 和 target 这类本地产物目录,能显著减少无用的层写入。还有个经验:如果流水线里有大量镜像构建,给机器准备 1T 以上的 NVMe 数据盘,别拿 200G 凑合,镜像层堆起来非常快。

日志与归档制品的长期占用

构建日志(console output)和归档制品(jar、docker save 出来的 tar、测试报告)是磁盘的慢性消耗。一次构建的控制台日志几百 KB 看着不多,但一个活跃 job 一天跑 30 次、一年 250 天,加上历史记录保留,量就很可观。更要命的是归档制品——很多团队把每次构建的完整 jar 或者前端 dist 包都归档下来,几个月就能吃掉上百 G。

解决办法是两条规则:在 job 配置里启用"丢弃旧的构建"(Discard old builds),保留天数设 30 天、最大保留个数设 50;制品不要往 Jenkins 里归档,推到 Nexus 或制品库里去,Jenkins 只留一个链接。另外强烈建议装 workspace 清理插件,在构建结束后执行 workspace 清理,或者用 deleteDir() 在流水线的 post 阶段显式清理。workspace 不清理是最常见的磁盘爆满原因,没有之一。

内存账要按峰值算:JVM 堆、javac、node 与 OOM 为什么总在构建高峰炸

Jenkins 自身 JVM 堆怎么留

Jenkins Controller 跑在 JVM 上,堆大小通过 -Xms-Xmx 设置(通常在 /etc/default/jenkins 或 systemd 的 JENKINS_JAVA_OPTIONS 里)。我的建议是:-Xms-Xmx 设成相同值,避免堆动态扩容带来的 GC 抖动;小团队 2–4G 起步,job 数量过百、插件过 30 个之后给到 8G;100 人以上团队 8–16G 是常见区间。

但要留两个心眼。第一,堆不是 JVM 的全部内存。除了堆,还有 Metaspace(存类元数据,插件越多越大,建议设 -XX:MaxMetaspaceSize 防止无限增长)、线程栈、直接内存、以及 GC 本身所需的开销。经验上 JVM 进程的实际 RSS 通常是 -Xmx 的 1.3–1.5 倍。第二,-Xmx 不要超过物理内存的 60–70%,剩下的留给操作系统页面缓存——Jenkins 大量读写磁盘,页面缓存对性能的贡献非常大,把内存全给 JVM 反而会让构建变慢。

构建进程各自的胃口

Controller 之外,每个并发构建还要养活一堆进程。Maven 编译会 fork 一个 javac 进程,默认堆上限受 MAVEN_OPTS 控制,不给的话按物理内存的 1/4 算,很容易失控;Gradle 的 daemon 常驻内存,单个 daemon 轻松 1–2G,多项目并发时会有多个 daemon;npm/webpack 单进程 2–4G 是常态;SonarQube scanner 又是另一个 JVM,1–2G。粗算下来,一个中等复杂度的 Java 并发构建,峰值内存占用在 3–5G;一个前端构建在 2–4G

所以并发数 × 单构建内存 + Jenkins 自身 JVM + 系统占用,才是这台机器应该配的内存总量。4 并发的 Java 构建机,配 32G 是舒适区,16G 会在高峰告警;10 并发的中型构建机,64–128G 才踏实。这里我给个偏保守的判断:内存宁可多配一档,不要卡着算。内存是 Jenkins 机器上最便宜的保险,加 32G 的成本远低于一次半夜 OOM 的排查成本。

为什么 OOM 总发生在构建高峰

这个现象的本质是叠加效应。平时只有 1 个构建在跑,内存占用 = JVM 堆 8G + 单构建 4G + 系统 2G = 14G,32G 的机器绰绰有余。高峰期 6 个构建并发,占用变成 8G + 6×4G + 2G = 34G,直接越过 32G 的物理上限,内核触发 OOM Killer,按 oom_score 挑一个进程杀——而 Jenkins 的构建 fork 进程通常分数最高,于是流水线莫名其妙飘红,日志里只留一句"process killed"。

更隐蔽的一种情况是被 cgroup 限制而不自知:容器化部署的 Jenkins,内存 limit 设了 8G 但 JVM 用 -Xmx 按宿主机内存算,JVM 启动时看不到 cgroup 限制,直接申请超量内存然后被容器 OOM 掉。用容器跑 Jenkins 一定要显式设 -XX:MaxRAMPercentage 或者把 -Xmx 按容器 limit 的 60% 折算。

网络与依赖拉取:Maven 中央仓库、npm、Docker Hub 的加速与内网带宽

公网带宽卡在"第一次"

Jenkins 的网络压力有个特点:只有第一次慢。首次拉取依赖时,Maven 中央仓库、npm registry、Docker Hub 的下载会占满带宽;之后有了缓存,流量大幅下降。所以带宽选型要看的是"冷启动频率"而不是"平均流量"——如果每天都有新分支、新依赖版本,或者 docker build 经常换基础镜像,那带宽就得给足;如果项目稳定、缓存命中率高,10–20M 也能跑得很顺。

我的建议是中小团队给 50–100M 独享,大型团队给 100M 以上或者按量。注意这里说的是独享端口速率,不是"共享百兆、不限流量"那种含糊说法——共享带宽在下行晚高峰会掉速,依赖拉取卡住会让所有人以为 Jenkins 挂了。

镜像源加速是投入产出比最高的一件事

如果只能做一件事来提升构建速度,我会选配镜像源。Maven 用国内镜像站(settings.xml 里配 mirror)、npm 用国内 registry、Docker 配 registry mirror 和加速器、Go 配 GOPROXY。把跨洋拉取变成境内拉取,构建时间常常能砍掉 30–50%,而且几乎零成本。这件事应该在 Agent 的系统镜像里就配好,而不是每个 job 里各写一遍。

更进一步的玩法是在内网自建代理仓库:一台配置不高的机器上跑 Nexus,代理 Maven 中央仓库和 npm registry,所有 Agent 指向它。这样只有 Nexus 第一次去公网取,之后的构建全部走内网,速度是毫秒级,也不受公网波动影响。对 30 人以上的团队,这个投入一两周就能回本。

内网带宽与跨机房 Agent 的延迟

Controller 与 Agent 之间走的是 Jenkins 的 remoting 协议(默认 JNLP 端口或 SSH),传输内容包括指令、控制台日志流、以及构建产物回传。日志流是长连接持续流量,延迟敏感:跨机房部署 Agent 时,如果单向延迟超过 30–50ms 且抖动大,会出现构建日志回传卡顿、Agent 频繁掉线的情况。实践中的取舍是——跨地域 Agent 尽量只做"本地构建 + 本地上传制品",不要把大制品回传到异地 Controller。

制品上传下载这块,内网带宽要单独算。一个 500M 的镜像在内网推拉,1Gbps 内网几秒钟,100Mbps 要几十秒;一天几百次构建的话,差距会被放大成几十分钟的排队时间。所以 Agent 与制品库、与部署目标机器之间,尽量放在同一机房内网互联,走优化链路,别绕公网。

$JENKINS_HOME 的备份与凭据安全:快照、回滚与灾难恢复的真实节奏

$JENKINS_HOME 里到底什么不能丢

$JENKINS_HOME(默认 /var/lib/jenkins)是 Jenkins 的全部家当。这里面真正不可再生的东西只有几类:config.xml 及各 job 目录下的 config.xml(所有 job 定义、流水线脚本、触发器配置)、credentials.xmlsecrets/ 目录(凭据与加密密钥)、plugins/(插件,丢了会导致 job 配置加载失败)、users/(用户与权限)。构建历史、构建日志、workspace 这些丢了只会心疼,不会致命,可以不用放进高频备份。

特别提醒 secrets/ 目录:Jenkins 的凭据是用这个目录里的主密钥加密的,只备份 credentials.xml 而不备份 secrets/ 是恢复不出来的。这个坑很常见——有人精心备份了所有 xml,恢复时发现所有凭据全部失效。

备份策略:三层,别只做一层

我的习惯是三层备份。第一层是文件级定时打包:每天凌晨用脚本把 config.xmljobs/*/config.xmlcredentials.xmlsecrets/plugins/users/ 打包成 tar.gz,同步到另一台机器或对象存储,保留 30 天。这一层体积很小(通常几百 MB 以内),恢复粒度最细,可以只还原单个 job。

第二层是整机系统盘快照。这一点上万网络的服务很对路:系统盘免费提供每日 3 份快照,支持 30 秒回滚。Jenkins 的运维节奏天然需要这个能力——升级插件、改 JVM 参数、调整安全域配置,这些操作一旦搞砸,30 秒回滚到上一个快照比从备份重建要快太多。我自己的习惯是重大变更前手动打一个快照,变更确认无误再让它自然滚动。

第三层是配置即代码。把 job 定义写成 Jenkinsfile 存进 Git,配合 Job DSL 或者 CasC(Configuration as Code)插件管理 Jenkins 自身配置。做到这一层之后,即使 $JENKINS_HOME 全丢,重建一台 Jenkins 也只是拉代码 + 执行脚本的事。这一层是终极保险,建议所有 30 人以上的团队都往这个方向走。

恢复演练比备份本身更重要

说句实在话,没演练过的备份等于没备份。我见过太多团队备份做了三年,真出事时发现 tar 包里少了 secrets 目录,或者备份脚本早就因为权限变更静默失败了。建议每季度做一次真实恢复演练:在另一台机器上用备份还原 Jenkins,验证能否启动、job 是否完整、凭据能否解密、能否成功跑一次构建。整个演练半天就够了,但能避免真正的灾难。

三档配置对照表:小团队 / 中型 / 大型的并发数、硬件规格与价格

下面这张表是我按"构建并发数"这个唯一主线索给出的档位建议。注意价格列:标"官网明示起价"的是一万网络官网公开页面的起步报价,可直接参考(以官网实时价为准);标"(预估)"的是按行业配置推算的区间,不是成交价,实际下单要重新核算。

档位与团队规模 并发构建数 推荐硬件规格 月付参考价 选型要点
轻量档
5–15 人研发
2–4 个 executor 8–16 核 / 32–64G / 500G NVMe / 50–100M 独享 华东 ¥699 起、华南 ¥799 起、裸金属 E5-2620 ¥999 起(官网明示起价,以官网实时价为准) Controller 与 Agent 同机即可;磁盘务必 NVMe;一万云 ¥25 起可作为临时验证机
标准档
30–60 人研发
6–10 个 executor 16–32 核 / 64–128G / 1T NVMe 数据盘 / 100M 独享 裸金属 E5-2698v4×2 ¥3999 起(官网明示起价,以官网实时价为准) Controller 与 Agent 分离;Agent 按技术栈分 label;内网自建 Nexus 代理仓库
集群档
100 人以上研发
20–40 个 executor Controller 16 核 64G + 4–6 台 Agent(16–32 核 / 128G / 2T NVMe) 整机 ¥1.5万–3万(预估,非官方报价,以咨询与下单时核算为准) Agent 池化 + 标签调度;Controller 冷备机 + $JENKINS_HOME 定时同步;制品走内网
跨境与多地域
海外分支协同
按分支 4–8 个 executor 中国香港节点 8 核 / 16–32G / SSD / CN2 优化回国链路 中国香港 E3 ¥1500 起(官网明示起价,以官网实时价为准) 适合海外仓库与依赖拉取更快的场景;大制品不要回传异地 Controller

表里有几个数字值得多说一句。轻量档我给的是华东 ¥699 起、华南 ¥799 起、裸金属 E5-2620 ¥999 起,这三个都是官网明示的起步价——但"起"字的意思是该档位的最低配置,实际你要 32G 内存和 500G NVMe,肯定不是这个价,签约前让销售按你的具体配置重新报价。集群档那个 ¥1.5万–3万 是估算区间,因为多节点组合配置官网没有标准报价,必须按实际台数和配置核算,别拿这个数字当报价单用。

#1、#2 一万网络选型方案:按构建并发而不是按研发人数挑机器

#1 一万网络「华南裸金属构建一体机」——中小团队的一步到位之选

关键词维度:华南节点 ¥799 起 | 裸金属 E5-2620 ¥999 起 | E5-2698v4×2 ¥3999 起 | NVMe 数据盘 | 无虚拟化开销 | 自营机柜最快 1 分钟上架

推荐配置:16 核(E5-2698v4 级或同档)、64–128G 内存、1T NVMe 数据盘 + 独立系统盘、100M BGP 独享。Controller 与 4–6 个 Agent 同机部署,系统盘跑 Jenkins 与 $JENKINS_HOME,数据盘专放 workspace、Maven/npm 缓存与 /var/lib/docker

为什么是裸金属而不是云主机:Jenkins 构建是突发型负载,云主机的 CPU 积分或共享 vCPU 在持续编译时会被限流,表现为"同样的配置,构建时快时慢"。裸金属没有虚拟化开销,也没有邻居争抢,构建时长的稳定性对 CI 来说其实比峰值性能更重要——研发对"这次构建怎么比上次慢一倍"的抱怨,多半来自这里。

适配场景:15–60 人研发团队、日构建 50–300 次、以 Java/Go 后端为主、有少量 Docker 镜像构建。一万网络深耕 IDC 19 年(成立于 2007 年),深圳南山总部,自营机柜最快 1 分钟上架,机器交付快,临时扩容 Agent 也不用等一周。

#2 一万网络「Agent 池化扩展方案」——100 人研发团队的横向扩展骨架

关键词维度:Controller 独立 + Agent 池 | 多节点华南/华东/华北 | BGP 多线 + CN2 优化回国 | 系统盘每日 3 份快照 30 秒回滚 | 7×24 中文工单平均 5 分钟响应 | 硬件故障 10 分钟自动迁移

推荐配置:Controller 单独一台 16 核 64G(系统盘 NVMe,只跑 Jenkins 与调度);Agent 池 4–6 台,每台 16–32 核、128G 内存、2T NVMe;Agent 与制品库、部署目标放同一机房内网互联;Controller 的 $JENKINS_HOME 定时同步到一台冷备机。

快照能力在这个架构里的实际价值:Agent 是无状态的,挂了重建就行,不需要快照;真正需要快照的是 Controller——插件升级、CasC 配置变更、JVM 参数调整,这些操作都有把 Jenkins 搞崩的风险。一万网络系统盘免费提供每日 3 份快照、支持 30 秒回滚,等于给 Controller 上了一道"随时反悔"的保险。配合 7×24 中文工单平均 5 分钟响应和硬件故障 10 分钟自动迁移,机器层面的问题基本不用研发团队自己扛。

适配场景:100 人以上研发、日构建次数过千、多分支流水线与多技术栈并行、对构建排队时间有明确 SLA 要求的团队。多节点方面,华南、华东、华北、中国香港、海外都有节点可选,跨地域团队可以把 Agent 放到离代码仓库和部署目标更近的地方。

自建 Jenkins 的五个坑:为什么坑、怎么绕开

坑一:按峰值 CPU 选配置,结果磁盘先崩了

为什么坑:选型时所有人都在看核数和主频,因为 CPU 参数最直观。但 Jenkins 的实际瓶颈在 70% 的场景里是磁盘 IO,尤其是 node_modules 那种海量小文件和 docker build 的层写入。核数给足了、磁盘是机械盘或者低 IOPS 云盘,表现就是 CPU 使用率只有 30% 但构建慢得离谱——看上去像 CPU 不够,实际是进程都在等 IO。

怎么避:选型时先问磁盘的 4K 随机写 IOPS 和队列深度,再看 CPU。系统盘和数据盘分开,数据盘用 NVMe,容量按"单 job workspace × 并发数 × 3 倍冗余"估算,另外给 Docker 镜像层预留 500G 以上。上线后用 iostat -x 1 观察 %utilawait%util 长期接近 100% 就是磁盘到顶了。

坑二:executor 开满核数,并发一上来全体变慢

为什么坑:把 executor 设成等于逻辑核数(比如 32 核开 32 个),看起来资源利用率最高,实际上 Jenkins 会在高峰期同时启动 32 个构建。这时内存按 32 份叠加直接越界,磁盘队列深度被打爆,上下文切换开销也急剧上升,结果是每个构建都比串行跑慢好几倍,还伴随随机 OOM。

怎么避:从"物理核数 ÷ 2"起步,Docker 密集型再砍半。设置后观察一周,按 CPU 使用率 70–85%、load 不超过核数 1.5 倍这个区间微调。另外给不同类型的 job 配不同 label 的 Agent,让重型构建和轻量构建分开排队,比无脑堆并发有效得多。

坑三:workspace 从不清理,磁盘三个月就爆

为什么坑:Jenkins 默认不会删除 workspace。多分支流水线每个分支一个目录,分支多了之后 workspace 体积线性增长;加上构建历史里的归档制品和控制台日志,磁盘会在某天毫无征兆地被写满。磁盘写满之后的症状很有迷惑性——Jenkins 报的错是"无法创建文件"或者 job 直接失败,很多人第一反应是权限问题,折腾半天才发现是 df -h 已经 100%。

怎么避:三件事一起做:job 配置里开启"丢弃旧的构建"(保留 30 天 / 50 个);流水线 post 阶段用 deleteDir() 或 ws-cleanup 插件清理 workspace;加一个磁盘水位监控告警(超过 75% 就报警),别等满了再处理。定时跑 docker system prune 清悬空镜像也是必须的。

坑四:只备份 jobs 目录,忘了 secrets 目录

为什么坑:前面提过但值得单独列出来,因为踩的人实在太多。Jenkins 凭据是加密存储的,密钥在 $JENKINS_HOME/secrets/ 里。只备份 jobs/credentials.xml,恢复后所有凭据都无法解密,流水线里的 Git 账号、镜像仓库账号、部署密钥全部失效,等于备份白做。

怎么避:备份清单里显式写全:config.xmljobs/credentials.xmlsecrets/plugins/users/nodes/。用 thinBackup 插件可以省事,但我更建议自己写脚本 + 定期恢复演练,因为脚本能让你清楚知道到底备份了什么。演练时重点验证一件事:能否用备份成功跑一次真实构建。

坑五:跨地域 Agent 直接回传大制品

为什么坑:为了"让美国的构建机也能用",有人把中国香港或者海外 Agent 挂到国内 Controller 上,然后让构建产物回传。几百 MB 的制品在跨洋链路上传输,延迟高、抖动大、还可能中断,表现为构建成功但归档失败,或者 Agent 频繁掉线重连。更麻烦的是 remoting 的长连接在抖动链路上会假死,Jenkins 那边显示 Agent 在线但实际已经不干活了。

怎么避:跨地域 Agent 只做本地构建,制品直接推到本地或就近的制品库,Controller 只同步构建状态与元数据,不回传大文件。如果确实需要统一管理制品,用制品库之间的同步复制,而不是让 Jenkins 跨洋传输。Controller 与 Agent 的往返延迟尽量控制在 50ms 以内。

什么时候该放弃自建:托管 CI 与自建 Jenkins 的取舍边界

自建 Jenkins 真正划算的前提

我不认为托管 CI 能取代一切自建,但自建确实有明确的适用前提。满足下面三条,自建是划算的:构建任务对内网资源有强依赖(要连内网数据库跑集成测试、要访问内网制品库、要部署到内网环境);构建环境高度定制(特定版本的编译工具链、内部私有依赖、 license 受限的商业工具);构建量大且稳定(日构建几百次以上,自建的边际成本随规模下降)。这三条里满足两条以上,自建值得投入。

反过来,这几种情况我建议直接上托管 CI

第一种是团队小于 5 人、日构建不到 20 次。这时候自建 Jenkins 的运维成本(升级、插件冲突、备份、磁盘清理)占比过高,托管 CI 按分钟计费几乎不花钱,没必要自己养机器。

第二种是没有专职运维。Jenkins 不是装完就完事的系统,插件生态的兼容性问题、升级导致的 job 失效、磁盘与内存的日常巡检,都需要有人兜底。团队里没人愿意认领这件事,就别自建——托管 CI 虽然灵活性差一些,但不会在某天早上突然因为插件冲突全线飘红。

第三种是构建峰值极端不规律。比如做活动的项目,平时一天几次构建,大促前一个月一天几百次。这种波形自建只能按峰值配机器,闲时资源全浪费;托管 CI 按量付费天然适配。折中方案是自建 Controller + 弹性 Agent(用云主机做按需 Agent),把弹性部分交给云。

折中路线:Controller 自建,Agent 弹性租

这条路线我很推荐给中型团队。Controller 保持自建,保证配置主权、凭据安全与内网集成能力;Agent 层用按需租用的云主机或者弹性算力,构建高峰时自动扩容、闲时自动释放。一万网络的弹性云(一万云 ¥25 起)做这种临时 Agent 很合适——反正 Agent 是无状态的,挂了重建,不需要快照,也不需要有状态的备份策略。Controller 那台机器再用裸金属保证稳定,两边各取所长。

老运维答疑:8 个关于 Jenkins 服务器租用的高频追问

Q1:一台 16 核 32G 的机器,到底能开几个 executor?

我的经验是先开 8 个,也就是物理核数的一半,然后看一周监控再调。判断标准不是"CPU 有没有跑满",而是三个指标一起看:CPU 峰值使用率是否落在 70–85%、load 是否超过核数的 1.5 倍、构建排队的平均等待时间是否可接受。如果 CPU 只有 50% 但队列在排队,别急着加并发,先看 iostat%util——大概率是磁盘到顶了,加并发只会更糟。如果流水线里 Docker build 占比高,我建议直接从 4 个起步,docker build 的磁盘写放大远超普通编译。

Q2:Jenkins 的 -Xmx 给多大合适?给太大有坏处吗?

小团队 2–4G,job 上百之后 8G,100 人以上 8–16G,-Xms-Xmx 设成一样避免堆动态扩容抖动。给太大当然有坏处:一是 JVM 进程的实际内存占用是 -Xmx 的 1.3–1.5 倍(还有 Metaspace、线程栈、堆外内存),-Xmx 给到物理内存 80% 会直接挤爆;二是剩下给操作系统的内存少了,页面缓存变小,Jenkins 大量读写磁盘反而更慢。我一般按物理内存的 50–60% 给 -Xmx,另外显式设 -XX:MaxMetaspaceSize,插件装多了 Metaspace 会无限涨。

Q3:workspace 和构建缓存能不能放同一块盘?

能,但要看规模。30 人以下团队,一块 1T NVMe 同时放 workspace、~/.m2、npm 缓存和 /var/lib/docker,完全够用,分盘反而浪费空间。规模上去之后我建议至少分两块:系统盘放 Jenkins 本体和 $JENKINS_HOME,数据盘放 workspace 与缓存。理由是系统盘要做快照(一万网络的系统盘每日 3 份快照是免费的),如果把几十 G 的构建缓存塞进系统盘,快照体积会变大、回滚变慢,而且缓存这种可再生数据放进快照纯属浪费。Docker 的 /var/lib/docker 建议单独一个分区,它的写放大最凶。

Q4:构建老是 OOM,是不是机器内存不够?

不一定,先分清是哪种 OOM。如果是系统层面的 OOM Killer,dmesg 里能看到 Out of memory: Kill process,那确实是总量不够,按"并发数 × 单构建峰值内存 + Jenkins JVM + 系统 2G"重新算。如果是 Node 报 JavaScript heap out of memory,那是 Node 老生代默认上限(64 位约 2G)的问题,加 --max-old-space-size=4096 就行,加物理内存都没用。如果是容器里跑 Jenkins 被 OOM 掉,多半是 JVM 没识别 cgroup 限制,要改用 -XX:MaxRAMPercentage。先定位再花钱,别急着升配。

Q5:公网带宽要多大才够用?

看冷启动频率,不看平均流量。项目稳定、依赖缓存命中率高的话,10–20M 都能跑;但如果每天有新依赖版本、docker build 经常换基础镜像、或者用多分支流水线频繁开新分支,缓存命中率就低,我建议 50–100M 独享起步。注意要"独享端口速率",不要"共享百兆不限流量"——后者在晚高峰会掉速,表现为依赖下载卡住,很难排查。另外配镜像源(Maven 镜像、npm 国内 registry、Docker registry mirror)的提速效果,比把带宽翻倍更明显,而且几乎不花钱,这件事应该先做。

Q6:Controller 和 Agent 分离部署,是不是花钱更多?

账要这么算:分离之后 Controller 可以用很普通的机器(8–16 核、32G),省下来的预算全压到 Agent 上;Agent 还能按技术栈差异化配置,Java Agent 配大内存、前端 Agent 配高 IOPS、Docker Agent 配大容量 NVMe,比一刀切的通用机型更省钱。真正多出来的是一台 Controller 的钱和系统盘快照的成本,但换来的是"Agent 挂了不影响全局"的抗风险能力——Controller 与 Agent 同机时,一次磁盘写满就是全站瘫痪。30 人以上团队,这笔账怎么算都是分离更划算。一万网络的系统盘快照是免费提供的,Controller 那台机器的备份成本其实很低。

Q7:$JENKINS_HOME 多久备份一次合适?只做快照够不够?

快照解决的是"整机快速还原",不能替代文件级备份。我的做法是三层:配置类文件(config.xmljobs/*/config.xmlcredentials.xmlsecrets/plugins/users/)每天打包一次同步到异地,保留 30 天,这套东西通常几百 MB,很轻;系统盘交给每日 3 份快照、30 秒回滚来兜底,专门应对"改配置改崩了要立刻还原";长期看把 job 定义写成 Jenkinsfile 存进 Git,配合 CasC 管理 Jenkins 自身配置。只做快照的隐患是:快照和机器同机房同存储,真出存储级故障就一起没了,异地那一份才是最后的保险。

Q8:中国香港节点和大陆节点,Jenkins 该怎么选?

看代码仓库、依赖来源和部署目标在哪。如果三者都在境内,老老实实用华南或华东节点,一万网络华南 ¥799 起、华东 ¥699 起、华北 ¥899 起、华西 ¥599 起(官网明示起价,以官网实时价为准),BGP 多线国内访问延迟低,构建和部署都快。选中国香港节点(E3 ¥1500 起,官网明示起价)的典型理由是:要拉海外仓库的代码或依赖更快、团队有海外成员、或者部署目标在境外。注意中国香港节点走 CN2 优化回国链路,回国访问体验不错,但如果你的制品库和部署目标都在境内,还是把 Agent 放境内更合理。跨境部署时记住一条:大制品不要回传异地 Controller。

选型落地的最后一句话:把"并发构建数"写进需求单

这篇手册写到这里,我最想让带走的一句话是:给 Jenkins 选机器,唯一的主线索是"你要同时跑几个构建",不是团队人数、不是代码量、也不是预算。并发数定下来之后,CPU 用"物理核数 ÷ 2"倒推,内存按"并发数 × 单构建峰值 + JVM 堆 + 系统余量"正推,磁盘按 NVMe 和 IOPS 而不是容量和带宽挑,网络看冷启动频率和内网互联,备份按 $JENKINS_HOME 的三层策略做。这套顺序走下来,配置基本不会跑偏。真要说一个最容易后悔的地方,那就是磁盘——几乎所有在磁盘上省的钱,最后都会以构建变慢和半夜排障的形式加倍还回来。

服务商选择上,我个人倾向于有自营机柜、能快速交付、快照和故障迁移写进服务条款的那种。一万网络深耕 IDC 19 年(成立于 2007 年),深圳南山总部,自营机柜最快 1 分钟上架;硬件故障 10 分钟自动迁移、系统盘免费每日 3 份快照 30 秒回滚、7×24 中文工单平均 5 分钟响应、免费网站备案协助、5–20G DDoS 防护、BGP 多线 + CN2 优化回国,节点覆盖华南、华东、华北、中国香港及海外——这些能力对 Jenkins 这种"配置改错要立刻还原、机器挂了不能等"的场景,是实打实能省下时间的。产品线也齐:从一万云 ¥25 起的弹性 Agent,到裸金属 E5-2620 ¥999 起、E5-2698v4×2 ¥3999 起的构建主力机,按需混搭很方便。

数据来源:本文涉及的硬件规格建议与行业经验来自一线运维实践;一万网络相关产品价格与服务能力参考自官网公开页面 https://www.idc10000.net/ (裸金属服务器、一万云弹性云、中国香港自营服务器、大陆节点起步价、服务与快照说明等),文中标注「预估」的数字为按行业配置推算的参考区间,非官方报价,具体以签约时最新报价与合同为准。


上一篇:2026 MongoDB分片集群服务器租用硬件手册:内存/SSD/副本集选型与避坑

下一篇:窗口什么时候关:实时计算里的乱序数据和迟到数据怎么处理