如何自动清理Jenkins旧构建及关联Docker镜像?仅保留30天内数据
Hey there! Let's tackle this Jenkins old build cleanup issue—those Docker images hogging storage are definitely a pain. I've got several reliable alternatives to that problematic "Jenkins: remove old builds" plugin you mentioned:
Jenkins has a native feature to discard old builds that's often overlooked, and you can pair it with a quick script to wipe associated Docker images:
- Go to your job's configuration, scroll to the Build History section, and check "Discard old builds".
- Set "Days to keep builds" to 30, and adjust any other limits (like max number of builds to keep) as needed.
- Add a Post-build Action > "Execute shell" step that cleans up the Docker image tied to the build. If you tagged your image with
${JOB_NAME}:${BUILD_NUMBER}during the build, use this script:# Only run if the build is marked for deletion (triggered by the retention policy) if [ "$BUILD_IS_KEEPT" = "false" ]; then IMAGE_TAG="${JOB_NAME}:${BUILD_NUMBER}" docker images | grep "$IMAGE_TAG" && docker rmi "$IMAGE_TAG" || echo "Image $IMAGE_TAG not found, skipping" fi
If you use Jenkins Pipelines, this plugin lets you build a flexible, scheduled cleanup workflow that handles both builds and Docker images:
First, install the "Pipeline Utility Steps" plugin, then create a dedicated cleanup pipeline with this script (tweak it for your jobs):
pipeline { agent any triggers { cron('0 2 * * *') // Run daily at 2 AM } stages { stage('Cleanup Old Builds & Docker Images') { steps { script { def targetJobs = ['Backend-Build', 'Frontend-Build'] // List your jobs here def retentionDays = 30 def cutoffDate = new Date() - retentionDays targetJobs.each { jobName -> def job = Jenkins.instance.getItem(jobName) if (!job) { println "Job ${jobName} doesn't exist, skipping" return } job.builds.each { build -> // Skip builds marked as "Keep forever" if (build.time < cutoffDate && !build.isKeepLog()) { def imageTag = "${jobName}:${build.number}" // Delete the Docker image sh "docker images | grep ${imageTag} && docker rmi ${imageTag} || echo 'Image ${imageTag} not found'" // Delete the build itself build.delete() println "Deleted build #${build.number} of ${jobName} and its Docker image" } } } } } } } }
Note: Make sure your Jenkins user has permissions to delete builds and run Docker commands, and test this in a staging environment first!
This plugin is built specifically to clean up Docker images tied to Jenkins builds:
- Install the "Docker Cleanup Plugin" from the Jenkins plugin manager.
- Head to Manage Jenkins > Configure System, find the "Docker Cleanup" section.
- Set rules like:
- "Keep images used by builds younger than 30 days"
- "Keep at most X images per job"
- Pair this with Jenkins' native build retention policy to delete old builds first, then let the plugin clean up the orphaned images.
If you prefer to avoid plugins entirely, a script using the Jenkins API gives you total flexibility. Here's a bash example (requires jq for JSON parsing):
#!/bin/bash JENKINS_URL="http://your-jenkins-server" USER="your-jenkins-username" API_TOKEN="your-api-token" RETENTION_DAYS=30 CUTOFF_TIMESTAMP=$(date -d "-${RETENTION_DAYS} days" +%s) # Get all job names JOBS=$(curl -s -u "${USER}:${API_TOKEN}" "${JENKINS_URL}/api/json?tree=jobs[name]" | jq -r '.jobs[].name') for JOB in $JOBS; do # Get builds older than the cutoff OLD_BUILDS=$(curl -s -u "${USER}:${API_TOKEN}" "${JENKINS_URL}/job/${JOB}/api/json?tree=builds[number,timestamp]" | jq -r ".builds[] | select(.timestamp/1000 < ${CUTOFF_TIMESTAMP}) | .number") for BUILD in $OLD_BUILDS; do IMAGE_TAG="${JOB}:${BUILD}" # Delete the Docker image docker rmi "${IMAGE_TAG}" 2>/dev/null || echo "Image ${IMAGE_TAG} not found" # Delete the build via API curl -X POST -u "${USER}:${API_TOKEN}" "${JENKINS_URL}/job/${JOB}/${BUILD}/doDelete" echo "Cleaned up build #${BUILD} of ${JOB}" done done
Schedule this script with cron to run automatically.
Quick Tips to Avoid Mistakes
- Always test cleanup workflows in a non-production environment first.
- Skip builds marked with "Keep this build forever" (the examples above handle this, but double-check).
- For Docker images, verify no other services are using them before deletion (you can use
docker ps --filter ancestor=IMAGE_TAGto check).
内容的提问来源于stack exchange,提问作者Jayadeep KM

