一、为什么Jenkins会磁盘空间不足?

Jenkins作为持续集成工具,每天都会产生大量的构建产物、工作空间文件和日志。如果不及时清理,这些文件会像滚雪球一样越积越多。想象一下你的电脑C盘变红的样子,Jenkins服务器也会遇到同样的问题。

常见占用空间的大户包括:

  1. 构建产物(比如编译生成的jar包、apk文件)
  2. 工作空间(每次构建时拉取的代码和生成的文件)
  3. 构建日志(特别是长时间运行的构建任务)

二、手动清理的局限性

很多团队最初会采用手动删除的方式:

# 进入Jenkins工作目录
cd /var/lib/jenkins/workspace/

# 删除30天前的构建目录
find . -type d -mtime +30 -exec rm -rf {} \;

但这种做法有三个明显问题:

  1. 容易误删重要文件
  2. 需要人工定期操作
  3. 无法针对不同项目设置不同策略

三、自动化清理方案设计

3.1 使用Jenkins内置功能

Jenkins其实已经提供了不错的清理机制,只是很多人没充分利用:

// Jenkinsfile示例 - 保留最近5次构建
pipeline {
    options {
        buildDiscarder(logRotator(numToKeepStr: '5'))
    }
    // 其他构建步骤...
}

这个配置会自动保留最近5次构建,删除更早的构建。但要注意:

  • 只适用于流水线项目
  • 不会清理工作空间
  • 对日志文件无效

3.2 使用Disk Clean插件

安装"Disk Clean"插件后可以这样配置:

// 在Jenkins全局配置中添加定期清理任务
node {
    // 删除超过30天的构建记录
    cleanWs(deleteDirs: true, patterns: [[pattern: '.gitignore', type: 'INCLUDE']])
    
    // 删除超过50次的旧构建
    buildDiscarder(logRotator(numToKeepStr: '50'))
}

这个插件更强大之处在于:

  1. 可以设置多种清理条件组合
  2. 支持正则表达式匹配文件
  3. 能生成清理报告

3.3 自定义Shell脚本方案

对于需要精细控制的场景,可以编写定时任务:

#!/bin/bash
# 清理脚本示例 - 技术栈:Linux Shell

# 配置变量
JENKINS_HOME="/var/lib/jenkins"
MAX_DAYS=30  # 保留最近30天
DRY_RUN=false  # 测试模式

# 主清理函数
clean_old_builds() {
    find "$JENKINS_HOME/jobs" -name "builds" -type d | while read build_dir; do
        echo "处理目录: $build_dir"
        find "$build_dir" -mindepth 1 -maxdepth 1 -type d -mtime +$MAX_DAYS | while read old_build; do
            if [ "$DRY_RUN" = true ]; then
                echo "[模拟] 将删除: $old_build"
            else
                echo "删除: $old_build"
                rm -rf "$old_build"
            fi
        done
    done
}

# 执行清理
clean_old_builds

这个脚本的特点:

  1. 支持模拟运行(dry run)模式
  2. 可以灵活调整保留天数
  3. 递归处理所有项目的构建目录

四、进阶清理策略

4.1 按项目重要性分级清理

重要的核心项目和生产环境构建应该保留更长时间:

// 分级清理策略示例
def cleanupStrategy = [
    'core-service': [buildsToKeep: 20, daysToKeep: 60],
    'test-project': [buildsToKeep: 5, daysToKeep: 7],
    'default': [buildsToKeep: 10, daysToKeep: 30]
]

pipeline {
    options {
        // 根据项目名称应用不同策略
        buildDiscarder(logRotator(
            artifactDaysToKeepStr: cleanupStrategy[env.JOB_NAME]?.daysToKeep ?: cleanupStrategy.default.daysToKeep,
            artifactNumToKeepStr: cleanupStrategy[env.JOB_NAME]?.buildsToKeep ?: cleanupStrategy.default.buildsToKeep
        ))
    }
    // 构建步骤...
}

4.2 日志文件单独处理

构建日志往往比构建产物占用更多空间:

#!/bin/bash
# 日志清理专用脚本

# 保留最近100MB的日志
LOG_DIR="/var/log/jenkins"
MAX_SIZE=100000  # 单位KB

# 计算当前日志大小
current_size=$(du -sk $LOG_DIR | awk '{print $1}')

if [ $current_size -gt $MAX_SIZE ]; then
    echo "当前日志大小: ${current_size}KB > ${MAX_SIZE}KB阈值"
    
    # 按修改时间排序,删除最旧的日志
    find $LOG_DIR -type f -name "*.log" -printf "%T@ %p\n" | sort -n | \
    while read -r line; do
        file=$(echo "$line" | awk '{print $2}')
        rm "$file"
        current_size=$(du -sk $LOG_DIR | awk '{print $1}')
        [ $current_size -le $MAX_SIZE ] && break
    done
fi

五、注意事项与最佳实践

  1. 清理前备份:设置自动清理前,确保关键构建产物有备份
  2. 监控效果:添加磁盘空间监控,验证清理策略是否有效
  3. 白名单机制:对特殊构建设置排除规则
  4. 清理频率:建议每天执行,避开构建高峰期
  5. 通知机制:清理重要文件前发送通知

六、完整方案示例

结合上述所有策略的完整方案:

// 完整清理方案 - 技术栈:Jenkins Pipeline

pipeline {
    agent any
    
    triggers {
        // 每天凌晨2点自动执行清理
        cron('0 2 * * *')
    }
    
    stages {
        stage('清理构建') {
            steps {
                script {
                    // 保留最近10次构建
                    buildDiscarder(logRotator(numToKeepStr: '10'))
                    
                    // 清理工作空间(排除.git目录)
                    cleanWs(
                        deleteDirs: true,
                        patterns: [
                            [pattern: '.git/**', type: 'EXCLUDE'],
                            [pattern: '*.log', type: 'INCLUDE']
                        ]
                    )
                }
            }
        }
        
        stage('清理日志') {
            steps {
                sh '''
                #!/bin/bash
                # 保留最近7天的Jenkins系统日志
                find /var/log/jenkins -name "*.log" -mtime +7 -exec rm -f {} \;
                
                # 但保留关键错误日志
                find /var/log/jenkins -name "ERROR*.log" -mtime +30 -exec rm -f {} \;
                '''
            }
        }
    }
    
    post {
        always {
            // 发送清理报告
            emailext body: "磁盘清理已完成,当前可用空间:${sh(returnStdout: true, script: 'df -h /var/lib/jenkins').trim()}", 
                   subject: "Jenkins磁盘清理报告",
                   to: 'devops@example.com'
        }
    }
}

七、方案评估与选择

方案对比表

方案 优点 缺点 适用场景
手动清理 简单直接 容易出错,效率低 临时应急
内置功能 无需额外插件 功能有限 基础需求
Disk Clean插件 功能全面 需要安装插件 大多数项目
自定义脚本 完全可控 维护成本高 特殊需求

推荐选择路径

  1. 中小团队:内置功能 + Disk Clean插件
  2. 大型集群:分级策略 + 自定义脚本
  3. 特殊环境:结合文件系统快照功能

八、总结

Jenkins磁盘空间管理就像整理你的电脑硬盘:

  • 定期"大扫除"比等到空间不足再处理更有效
  • 不同"房间"(构建、日志、工作空间)需要不同的整理策略
  • 设置好"自动保洁"规则后就能一劳永逸

记住三个关键数字:

  • 构建保留次数:5-20次(根据项目重要性)
  • 日志保留天数:7-30天
  • 检查频率:至少每周一次

通过合理的自动化策略,可以让Jenkins保持"轻盈"状态,避免因磁盘问题导致的构建失败,让CI/CD流程更加顺畅。