数据点: Jenkins 官方节点管理文档明确把磁盘空间和临时目录空间列为 Agent 监控项。
症状 → 最快解法: 节点因磁盘告警离线,删掉一个 Workspace 后空间仍未恢复 → 先分别盘点 Workspace、用户 Library、临时目录、归档和依赖缓存,再决定清理、限并发或扩容。

不要直接清空整个工作目录。你应先按“是否可重建、是否正在使用、是否承载发布证据”分层,再做受控删除。清理后如果磁盘仍持续逼近禁止接单阈值,就减少单机并发、拆分签名节点,并增加固定或按需的远程 Mac 容量。

这篇文章适合负责 Jenkins Mac Agent 日常运维、磁盘告警和节点恢复的企业 IT 人员。
也适合维护 iOS CI/CD、缓存策略和构建稳定性的研发效能团队,以及需要根据增长和排队数据做扩容决策的技术负责人。

先定位磁盘增长来源,不要把 Workspace 当成唯一答案

一个常见失败场景是:监控发现 Agent 空间不足,值班人员删除某个项目的 Workspace,df 显示的可用空间却变化不大。原因可能是文件仍被进程打开、真正增长点在用户目录,或者删除的是当前构建仍在使用的目录。

Jenkins Pipeline 会为任务分配 Workspace;自定义 Workspace、并发构建和多分支任务还可能让同一个项目出现多个实际目录。Pipeline 官方语法同时提供了 customWorkspacedisableConcurrentBuilds() 等控制项。你必须先确认:

  • 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 阶段,也可以配置为构建前清理。插件官方页面还列出了 deleteDirsdisableDeferredWipeoutnotFailBuild 等参数。

适合自动清理的通常是:

  • 可从 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 管理文档记录了该安全维护能力。

建议按以下顺序操作:

  1. 查看队列、执行器和当前构建,确认没有活动任务。
  2. 将节点设置为暂不接收新任务,并记录原因、时间和操作者。
  3. 记录待删除路径、目录大小、占用进程和回滚位置。
  4. 先处理已确认可重建的 Workspace 与缓存,不触碰 Keychain 和发布归档。
  5. 清理 Simulator Runtime、平台组件前,核对目标 Xcode 和测试矩阵。
  6. 恢复节点连接,执行源码检出、依赖恢复和普通构建。
  7. 执行测试、Archive、签名导出,并检查制品上传和 dSYM 关联。
  8. 确认节点重启后仍能接单,磁盘监控、日志和告警恢复正常。

Apple 官方的分发流程要求先创建 Xcode archive,再从 archive 导出签名后的应用。分发与发布文档所以“释放了多少空间”不是验收标准。真正的放量证据是:真实流水线成功、签名发布成功、归档可追溯、节点重启后状态正常。

当前 Mac 构建机反复磁盘满,是清理策略还是容量不足?

如果你每周都要人工删除 Workspace,说明问题可能已经从“偶发垃圾数据”变成了容量治理问题。继续清理的缺点是维护窗口不可预测、缓存重建会增加排队、误删风险会集中到值班人员;如果普通构建和生产签名共用节点,还会把缓存、测试设备和发布凭证的责任边界混在一起。

更稳妥的做法是把普通构建、模拟器测试和生产签名拆成不同节点。对于短期项目、临时发布高峰或需要快速增加 Apple Silicon 构建容量的团队,按需租赁远程 Mac 可以避免先采购实机、预留闲置容量和承担硬件维护;你可以先查看 MACCOME 的远程 Mac 服务入口,再用真实构建峰值填写容量表,通过 MACCOME 的 Mac 计算资源方案评估新增节点。

如果团队需要的是长期稳定的高负载、物理 USB 设备或本地网络专线,自购 Mac 仍可能更合适。若你的主要问题是 Jenkins Agent 磁盘告警、临时扩容和签名节点隔离,先用一台远程 Mac 做小范围生产准入测试,再决定是否扩展到固定节点,通常比继续反复删除目录更容易控制风险。