数据点: Jenkins 官方节点管理文档明确把磁盘空间和临时目录空间列为 Agent 监控项。
症状 → 最快解法: 节点因磁盘告警离线,删掉一个 Workspace 后空间仍未恢复 → 先分别盘点 Workspace、用户 Library、临时目录、归档和依赖缓存,再决定清理、限并发或扩容。
不要直接清空整个工作目录。你应先按“是否可重建、是否正在使用、是否承载发布证据”分层,再做受控删除。清理后如果磁盘仍持续逼近禁止接单阈值,就减少单机并发、拆分签名节点,并增加固定或按需的远程 Mac 容量。
这篇文章适合负责 Jenkins Mac Agent 日常运维、磁盘告警和节点恢复的企业 IT 人员。
也适合维护 iOS CI/CD、缓存策略和构建稳定性的研发效能团队,以及需要根据增长和排队数据做扩容决策的技术负责人。
先定位磁盘增长来源,不要把 Workspace 当成唯一答案
一个常见失败场景是:监控发现 Agent 空间不足,值班人员删除某个项目的 Workspace,df 显示的可用空间却变化不大。原因可能是文件仍被进程打开、真正增长点在用户目录,或者删除的是当前构建仍在使用的目录。
Jenkins Pipeline 会为任务分配 Workspace;自定义 Workspace、并发构建和多分支任务还可能让同一个项目出现多个实际目录。Pipeline 官方语法同时提供了 customWorkspace 和 disableConcurrentBuilds() 等控制项。你必须先确认:
- Jenkins Remote FS 实际指向哪个卷;
- Job 是否使用了自定义 Workspace;
- 并发构建是否产生带后缀的目录;
- 目录是否仍被当前进程、测试模拟器或
xcodebuild占用; - Jenkins Controller、Agent 和制品存储是否保存了重复副本。
APFS 的“可用空间”、目录逻辑大小和真正可回收空间不一定相同。不要只看 Finder 的分类结果,也不要只运行一次 du 就开始删除。建议先记录卷级空间、一级目录占用、最近增长目录和删除前快照。
df -h /
du -xhd 1 "$WORKSPACE" 2>/dev/null | sort -h
du -xhd 1 "$HOME/Library" 2>/dev/null | sort -h
lsof +L1 2>/dev/null
lsof +L1 只能帮助你发现已删除但仍被进程持有的文件,不能替代 Jenkins 状态检查。盘点结果应至少分成四类:Jenkins Remote FS、用户 Library、临时目录、归档与制品目录。
第一步:判断遗留 Workspace 能不能自动删除
Jenkins Workspace 可以在构建结束后自动删除,但“构建结束”不等于“所有相关数据都可以删除”。Workspace Cleanup Plugin 提供 cleanWs,可放在 Pipeline 的 post 阶段,也可以配置为构建前清理。插件官方页面还列出了 deleteDirs、disableDeferredWipeout 和 notFailBuild 等参数。
适合自动清理的通常是:
- 可从 Git、镜像仓库或依赖仓库重新获取的源码副本;
- 已经完成并通过验收的普通构建目录;
- 不承担归档、签名凭证或故障复盘职责的临时输出。
不适合直接自动删除的包括:
- 正在运行的构建目录;
- 仍被并发任务共享的自定义 Workspace;
- 尚未上传到制品库的
.ipa、.xcarchive、测试报告; - 团队排查失败构建所需的中间日志;
- 包含 Keychain、证书或临时签名材料的目录。
建议先限制任务生命周期,再使用 cleanWs。例如:
post {
always {
cleanWs(
deleteDirs: true,
disableDeferredWipeout: true,
notFailBuild: true
)
}
}
这段配置不能证明它适合你的所有 Job。对生产签名流水线,应先确认归档、符号文件和日志已经进入受控制品存储,再决定是否清理 Workspace。Jenkins 官方也提醒,Pipeline 的 Workspace 在某些配置下不会因长期不活动而自动清理。Pipeline 文档因此不能替代人工审计。
第二步:把 Xcode 数据按可重建性分级
Xcode 相关数据不能用一条“全部删除”脚本处理。你至少要把 DerivedData、模拟器设备数据、Simulator Runtime、平台组件和 Archives 分开。
| 数据类型 | 通常承担的职责 | 删除后的代价 | 推荐策略 |
|---|---|---|---|
| DerivedData | 编译中间文件、索引和派生输出 | 需要重新编译,首次构建可能重新生成 | 按项目、分支或闲置时间清理 |
| 模拟器设备数据 | 模拟器状态、测试数据和设备内容 | 测试环境需重新初始化 | 只清理已废弃设备和孤立数据 |
| Simulator Runtime | 特定系统版本的模拟环境 | 可能需要重新下载或导入 | 先核对测试矩阵和恢复来源 |
| 平台组件 | iOS、watchOS 等开发支持文件 | 对应平台构建可能无法启动 | 保留生产流水线必需组件 |
| Xcode Archives | 发布包、二进制和调试符号 | 影响发布追踪与崩溃分析 | 按发布责任人确认保留周期 |
Apple 文档说明,Xcode 的 Components 设置会显示可删除或关闭组件能够回收的存储空间,并支持管理 Simulator Runtime 与平台支持文件。Xcode 组件管理文档这意味着 Runtime 和平台组件应通过 Xcode 或对应命令管理,不应把它们当作普通缓存目录递归删除。
DerivedData 通常比归档更接近“可重建缓存”,但你的 CI 依赖、网络条件和构建时长决定了清理成本。Archives 则不能套用缓存规则。Apple 明确说明,归档包含应用二进制和 dSYM,发布后应保留对应归档,否则可能无法对崩溃报告完成符号化。调试信息与 dSYM 文档
第三步:用资产表处理依赖缓存和重复制品
磁盘持续增长,常常不是单一目录失控,而是同一份数据被保存了多次:Workspace 一份,用户 Library 一份,Jenkins 制品目录一份,外部制品库又保存一份。
| 资产 | 数据所有者 | 能否重建 | 清理触发条件 |
|---|---|---|---|
| Swift Package Manager 缓存 | 构建平台或项目团队 | 通常可通过依赖源恢复,但要验证网络 | 版本切换、缓存失效或维护窗口 |
| CocoaPods 缓存 | 项目构建环境 | 取决于 Pod 源和锁定版本 | 已确认制品源可用后 |
| Homebrew 下载与安装缓存 | 节点维护人员 | 需确认工具版本可复现 | 工具链升级完成后 |
| Git LFS 对象 | 代码库或发布团队 | 不应只按文件大小判断 | 仓库策略和保留规则确认后 |
构建产物与 .ipa |
发布团队 | 可能无法从相同环境重建 | 已上传并完成验收后 |
把这张表落实到每个目录。不要把所有缓存都设置为永久保留,也不要让每次构建都无条件删除。重点是确认“谁负责恢复、恢复需要什么来源、恢复失败会不会阻断发布”。
Jenkins 的构建记录还可能保存控制台输出、归档制品和其他元数据。多分支构建丢弃策略文档说明,构建保留可以按时间或数量控制,制品还可以使用独立规则处理。你可以在 Pipeline 中配置 buildDiscarder,但不要只看 Agent 磁盘;Controller 的构建记录目录同样可能成为增长点。
第四步:按条件决定清理、限并发还是扩容
不要用一个固定百分比作为所有企业的磁盘阈值。单次构建峰值、Xcode 组件安装需求、依赖恢复时间、发布回滚余量和并发数量不同,阈值就应不同。
可以使用下面的决策条件列表:
- 若主要增长来自已完成构建的 Workspace,且源码、依赖和制品都能恢复,则优先启用受控的 Job 生命周期清理。
- 若主要增长来自多个并发 Workspace,且同一 Agent 的 I/O、排队和磁盘峰值同步上升,则先减少 executor 或启用
disableConcurrentBuilds(),再观察构建排队。 - 若主要增长来自 DerivedData,且清理后只是重新编译,则按项目和分支设置缓存保留策略。
- 若主要增长来自 Simulator Runtime 或平台组件,且测试矩阵仍需要它们,则禁止清理,改为增加节点容量或拆分测试节点。
- 若主要增长来自 Archives、
dSYM或发布日志,则先迁移到受控制品存储,再按发布责任人批准清理。 - 若清理频率不断上升,维护窗口已经影响交付,或者节点经常进入离线状态,则不要继续靠脚本补洞,应评估新增固定节点或按需远程 Mac。
Jenkins 官方建议谨慎设置 Agent executor;一台节点使用一个 executor 是更安全的起点,多 executor 需要持续观察 I/O、CPU、内存和吞吐。节点管理文档这不是所有任务的最终配置,但能帮助你判断问题究竟是容量不足,还是并发把磁盘峰值推高。
第五步:清理前摘除节点,清理后验证签名流水线
清理活动目录、Keychain、归档、日志或正在使用的模拟器数据,可能造成三类生产影响:
- 构建重新检出失败,导致流水线长时间占用队列;
- 证书、描述文件或签名环境被破坏,发布阶段才暴露错误;
- 归档和
dSYM丢失,后续无法复盘崩溃或确认已发布版本。
清理前先让 Agent 不再接收新任务。Jenkins 的“Prepare for Shutdown”机制会阻止新构建启动,适合维护窗口使用;节点级别也应根据你的调度方式执行暂时摘除。Jenkins 管理文档记录了该安全维护能力。
建议按以下顺序操作:
- 查看队列、执行器和当前构建,确认没有活动任务。
- 将节点设置为暂不接收新任务,并记录原因、时间和操作者。
- 记录待删除路径、目录大小、占用进程和回滚位置。
- 先处理已确认可重建的 Workspace 与缓存,不触碰 Keychain 和发布归档。
- 清理 Simulator Runtime、平台组件前,核对目标 Xcode 和测试矩阵。
- 恢复节点连接,执行源码检出、依赖恢复和普通构建。
- 执行测试、Archive、签名导出,并检查制品上传和
dSYM关联。 - 确认节点重启后仍能接单,磁盘监控、日志和告警恢复正常。
Apple 官方的分发流程要求先创建 Xcode archive,再从 archive 导出签名后的应用。分发与发布文档所以“释放了多少空间”不是验收标准。真正的放量证据是:真实流水线成功、签名发布成功、归档可追溯、节点重启后状态正常。
当前 Mac 构建机反复磁盘满,是清理策略还是容量不足?
如果你每周都要人工删除 Workspace,说明问题可能已经从“偶发垃圾数据”变成了容量治理问题。继续清理的缺点是维护窗口不可预测、缓存重建会增加排队、误删风险会集中到值班人员;如果普通构建和生产签名共用节点,还会把缓存、测试设备和发布凭证的责任边界混在一起。
更稳妥的做法是把普通构建、模拟器测试和生产签名拆成不同节点。对于短期项目、临时发布高峰或需要快速增加 Apple Silicon 构建容量的团队,按需租赁远程 Mac 可以避免先采购实机、预留闲置容量和承担硬件维护;你可以先查看 MACCOME 的远程 Mac 服务入口,再用真实构建峰值填写容量表,通过 MACCOME 的 Mac 计算资源方案评估新增节点。
如果团队需要的是长期稳定的高负载、物理 USB 设备或本地网络专线,自购 Mac 仍可能更合适。若你的主要问题是 Jenkins Agent 磁盘告警、临时扩容和签名节点隔离,先用一台远程 Mac 做小范围生产准入测试,再决定是否扩展到固定节点,通常比继续反复删除目录更容易控制风险。