Jenkins 构建历史管理与磁盘清理全攻略:5步根治服务器磁盘爆满
-
-
- 📈 构建历史管理全景流程图
- 一、核心概念:构建历史到底占用了哪些空间?
-
- 1. 构建历史的存储结构
- 2. 磁盘空间占用分析
- 二、策略一:全局自动清理配置(最基础)
-
- 操作步骤
- 三、策略二:Job 级别的丢弃策略(最常用)
-
- 操作步骤
- 四、策略三:Pipeline 中主动清理(最灵活)
-
- 1. 清理工作空间
- 2. 归档产物按需清理
- 3. 使用 buildDiscarder 属性(脚本式Pipeline)
- 五、策略四:脚本批量清理(应急救火)
-
- 1. Groovy脚本(在Jenkins Script Console中执行)
- 2. Shell脚本(直接在服务器执行)
- 六、监控体系:从被动清理到主动预警
-
- 1. 安装磁盘监控插件
- 2. 配置磁盘阈值告警
- 3. 定期巡检Pipeline
- 📊 四种清理策略对比
- 📚 常见问题排查
- 💎 总结
-
|
🌺The Begin🌺点点关注,收藏不迷路🌺 ⬇ ⬇ 底部 ⬇ ⬇ |
你是否遇到过这样的场景:Jenkins运行了半年后,服务器磁盘突然告警,登录一看,jobs 目录占用了上百GB空间——几万次的历史构建、几百G的归档产物,让服务器不堪重负。构建历史管理就是解决这一问题的系统性方案。
📈 构建历史管理全景流程图
先通过一张图理解构建历史从产生到清理的完整生命周期:
#mermaid-svg-SBQ1dQEmwhU2Zhl5{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .error-icon{fill:#552222;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .marker.cross{stroke:#333333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 p{margin:0;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .cluster-label text{fill:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .cluster-label span{color:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .cluster-label span p{background-color:transparent;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .label text,#mermaid-svg-SBQ1dQEmwhU2Zhl5 span{fill:#333;color:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node rect,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node circle,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node ellipse,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node polygon,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .rough-node .label text,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node .label text,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .image-shape .label,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .icon-shape .label{text-anchor:middle;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .rough-node .label,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node .label,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .image-shape .label,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .icon-shape .label{text-align:center;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node.clickable{cursor:pointer;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .arrowheadPath{fill:#333333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .cluster text{fill:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .cluster span{color:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 rect.text{fill:none;stroke-width:0;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .icon-shape,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .icon-shape p,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .icon-shape .label rect,#mermaid-svg-SBQ1dQEmwhU2Zhl5 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-SBQ1dQEmwhU2Zhl5 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
定期执行
⚙️ 每次Pipeline执行
📦 生成构建记录
存储内容
📋 构建日志log文件
📦 归档产物artifacts
📊 JUnit测试报告
💾 工作空间快照
存储于 $JENKINS_HOME/jobs/
管理策略
策略1: 全局自动清理配置
策略2: Job级别丢弃策略
策略3: Pipeline中清理
策略4: 脚本批量删除
🗑️ 清理过期构建
✅ 释放磁盘空间
📊 监控 + 告警
核心逻辑: 构建历史管理是一个闭环——清理不是目的,建立自动化的清理策略 + 监控告警才是根本。
一、核心概念:构建历史到底占用了哪些空间?
在动手清理之前,必须搞清楚Jenkins到底把数据存在哪里、存了什么。
1. 构建历史的存储结构
Jenkins构建数据存储路径:
$JENKINS_HOME/jobs/
├── project-A/
│ ├── builds/
│ │ ├── 1/ # 第1次构建
│ │ │ ├── log # 构建日志
│ │ │ ├── archive/ # 归档产物(jar包等)
│ │ │ ├── junitResult.xml # 测试报告
│ │ │ └── build.xml # 构建元数据
│ │ ├── 2/ # 第2次构建
│ │ └── ...
│ ├── workspace/ # 工作空间(可能很大)
│ └── config.xml # Job配置
└── project-B/
└── ...
2. 磁盘空间占用分析
| 归档产物(Artifacts) | 40-60% | ⭐⭐⭐⭐⭐ 最高 |
| 工作空间(Workspace) | 20-30% | ⭐⭐⭐⭐ |
| 构建日志(Logs) | 10-15% | ⭐⭐⭐ |
| 测试报告(Reports) | 5-10% | ⭐⭐ |
| 构建元数据(XML) | 1-5% | ⭐(不建议清理) |
关键认知: 归档产物(Artifacts)和工作空间(Workspace)是最大的磁盘消耗者,应作为清理的重点目标。
二、策略一:全局自动清理配置(最基础)
这是Jenkins内置的**全局兜底策略**,对所有Job生效。
操作步骤
推荐配置:
策略类型:Log Rotation
保留天数:30天
保留最大构建数:50
注意:
- 这个配置是全局默认值,每个Job可以独立覆盖。
- 建议设置得宽松一些(如保留30天),然后在个别高频Job上单独收紧。
三、策略二:Job 级别的丢弃策略(最常用)
对于每天构建几十次的高频项目,需要在Job级别设置更激进的清理策略。
操作步骤
策略配置说明:
| Days to keep builds | 7天 | 30天 | 按时间保留 |
| Max # of builds to keep | 20次 | 50次 | 按数量保留 |
| Days to keep artifacts | 3天 | 14天 | 产物保留时长(可短于构建保留) |
| Max # of builds with artifacts | 5次 | 20次 | 只保留最近N次的产物 |
工作机制: 两个条件以**先满足者为准**。例如同时设置"保留7天"和"保留20次",某天第21次构建成功时,即使它只过了1天,最老的第1次也会被清理。
最佳实践:
- 归档产物(Artifacts)的保留时长应短于构建记录。
- 生产发布Job的构建历史建议永久保留(不设置丢弃策略)。
- 特性分支Job建议保留5次以内。
四、策略三:Pipeline 中主动清理(最灵活)
在Pipeline脚本中,可以精确控制构建结束后清理哪些内容。
1. 清理工作空间
声明式Pipeline示例:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package'
}
}
}
post {
always {
// 方法1:使用cleanWs插件清理工作空间
cleanWs(
cleanWhenAborted: true,
cleanWhenFailure: true,
cleanWhenNotBuilt: true,
cleanWhenUnstable: true,
deleteDirs: true,
patterns: [
[pattern: 'target/', type: 'INCLUDE'],
[pattern: 'node_modules/', type: 'INCLUDE']
]
)
// 方法2:直接删除目录
// deleteDir()
}
}
}
2. 归档产物按需清理
pipeline {
agent any
stages {
stage('Archive') {
steps {
// 仅归档重要产物
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
}
post {
always {
// 清理构建过程中产生的临时文件
sh '''
rm -rf target/tmp/
rm -rf target/*-sources.jar
'''
}
}
}
3. 使用 buildDiscarder 属性(脚本式Pipeline)
properties([
buildDiscarder(
logRotator(
artifactDaysToKeepStr: '3',
artifactNumToKeepStr: '10',
daysToKeepStr: '7',
numToKeepStr: '30'
)
)
])
node {
stage('Build') {
// 构建逻辑
}
}
优势: 将清理策略代码化,随Jenkinsfile版本控制,团队成员都能看到和修改。
五、策略四:脚本批量清理(应急救火)
当磁盘已经爆满,需要**立即释放空间**时,使用脚本批量操作。
1. Groovy脚本(在Jenkins Script Console中执行)
进入 Manage Jenkins → Script Console,执行以下脚本:
批量删除所有Job的旧构建(保留最近10次):
// 遍历所有Job
Jenkins.instance.allItems.findAll { it instanceof hudson.model.Job }.each { job ->
println "清理Job: ${job.fullName}"
// 获取所有构建记录,按编号倒序排列
def builds = job.builds.sort { it.number }.reverse()
// 保留最近10次构建
def buildsToKeep = 10
if (builds.size() > buildsToKeep) {
builds.drop(buildsToKeep).each { build ->
println " 删除构建 #${build.number}"
build.delete()
}
}
}
println "清理完成!"
仅清理构建产物,保留构建日志:
Jenkins.instance.allItems.findAll { it instanceof hudson.model.Job }.each { job ->
println "清理产物: ${job.fullName}"
job.builds.each { build ->
// 获取归档产物目录
def artifactsDir = new File(build.rootDir, 'archive')
if (artifactsDir.exists()) {
def size = artifactsDir.directorySize()
println " 构建 #${build.number} 产物大小: ${size / 1024 / 1024} MB"
// 删除产物(保留构建记录和日志)
artifactsDir.deleteDir()
println " 已删除构建 #${build.number} 的产物"
}
}
}
查找并清理大文件构建:
// 查找所有构建,按磁盘占用排序
def buildSizes = []
Jenkins.instance.allItems.findAll { it instanceof hudson.model.Job }.each { job ->
job.builds.each { build ->
def size = build.rootDir.directorySize()
buildSizes << [job: job.fullName, number: build.number, sizeMB: size / 1024 / 1024]
}
}
// 按大小降序排列,输出前20个
buildSizes.sort { –it.sizeMB }.take(20).each {
println "${it.job} – Build #${it.number}: ${it.sizeMB.round(2)} MB"
}
2. Shell脚本(直接在服务器执行)
查找占用最大的Job目录:
#!/bin/bash
JENKINS_HOME="/var/lib/jenkins"
echo "=== Jenkins 磁盘占用 Top 20 ==="
du -sh $JENKINS_HOME/jobs/*/ | sort -rh | head -20
echo ""
echo "=== Workspace 占用 Top 10 ==="
du -sh $JENKINS_HOME/jobs/*/workspace/ | sort -rh | head -10
删除所有超过30天的构建产物:
#!/bin/bash
JENKINS_HOME="/var/lib/jenkins"
DAYS_OLD=30
echo "清理超过 ${DAYS_OLD} 天的构建产物…"
find $JENKINS_HOME/jobs/*/builds/ -maxdepth 3 -type d -name "archive" -mtime +$DAYS_OLD | while read dir; do
echo "删除: $dir (大小: $(du -sh $dir | cut -f1))"
rm -rf "$dir"
done
echo "清理完成!"
⚠️ 安全警告: 使用Shell脚本前务必:
六、监控体系:从被动清理到主动预警
清理只是治标,监控才是治本。
1. 安装磁盘监控插件
安装 Disk Usage Plugin:
- 进入 Manage Jenkins → Plugins,搜索安装 Disk Usage。
- 安装后在 Manage Jenkins 页面看到 Disk Usage 链接。
- 可视化管理每个Job的磁盘占用。
2. 配置磁盘阈值告警
在 Manage Jenkins → System 中设置:
磁盘空闲空间告警阈值:10GB
当低于阈值时:发送邮件通知管理员
3. 定期巡检Pipeline
创建一个专门的Jenkins Job,每周执行一次磁盘巡检:
pipeline {
agent any
triggers {
cron('0 8 * * 1') // 每周一早上8点执行
}
stages {
stage('Check Disk Usage') {
steps {
script {
def jenkinsHome = new File('/var/lib/jenkins')
def freeSpace = jenkinsHome.freeSpace / 1024 / 1024 / 1024
def totalSpace = jenkinsHome.totalSpace / 1024 / 1024 / 1024
echo "Jenkins磁盘总空间: ${totalSpace.round(2)} GB"
echo "Jenkins磁盘剩余空间: ${freeSpace.round(2)} GB"
if (freeSpace < 10) {
emailext(
subject: "🚨 Jenkins磁盘空间不足告警",
body: "剩余空间: ${freeSpace.round(2)} GB,请立即清理!",
to: 'admin@company.com'
)
error "磁盘空间不足,巡检失败!"
}
}
}
}
stage('Clean Old Workspaces') {
steps {
sh '''
find /var/lib/jenkins/jobs/*/workspace/ \\
-maxdepth 0 \\
-type d \\
-mtime +14 \\
-exec rm -rf {} \\\\;
'''
}
}
}
}
📊 四种清理策略对比
| 全局配置 | 兜底策略 | 全局 | 简单、一劳永逸 | 无法差异化处理 |
| Job级别 | 日常管理 | Job级 | 灵活、精细 | 需逐个配置 |
| Pipeline中 | 代码化团队协作 | 构建级 | 可版本控制、精确 | 需要编码能力 |
| 脚本批量 | 应急救火 | 无限制 | 快速、强力 | 风险高、不可逆 |
📚 常见问题排查
| 设置了丢弃策略但没生效 | 旧策略与新策略冲突 | 手动删除一次旧构建,后续自动策略生效 |
| Pipeline脚本清理失败 | Jenkins用户无删除权限 | 确认Jenkins进程用户对 jobs/ 目录有写权限 |
| 清理后磁盘空间未释放 | 删除的文件仍被进程占用 | 重启Jenkins服务或使用 lsof 检查占用 |
| 构建历史被误删 | 脚本参数过大 | 提前备份,使用更保守的保留数量 |
💎 总结
通过本文,你已建立完整的Jenkins构建历史管理知识体系:
黄金法则: 不要把Jenkins当仓库——构建产物的归宿是Nexus/Artifactory,构建历史的归宿是定期归档,工作空间永远是临时的。做好这三点,你的Jenkins服务器就能长期保持健康状态。

|
🌺The End🌺点点关注,收藏不迷路🌺 ⬆ ⬆ 顶部 ⬆ ⬆ |
网硕互联帮助中心




![99Ai4.2.4源码包完整部署指南[特殊字符]支持宝塔本地与服务器安装|可二次开发|可商用-网硕互联帮助中心](https://www.wsisp.com/helps/wp-content/uploads/2026/07/20260724172143-6a639f2708a8f-220x150.jpg)

评论前必须登录!
注册