---
title: "Auto-cleaning Docker Registry with a Scheduled Jenkins Pipeline"
description: "Walks through using a Jenkins Pipeline on a schedule to automatically clean up old images from a Docker Registry, solving the disk-space problem on a private registry."
canonical_url: "https://blog.markkulab.net/en/post/jenkins-clear-docker-registry"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2024-11-19 01:01:35 +0800"
category: "DevOps"
tags: ["jenkins", "docker", "registry", "pipeline", "automation", "cron", "devops"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Auto-cleaning Docker Registry with a Scheduled Jenkins Pipeline

## The Problem
After a private Docker Registry has been used for a while, it tends to run out of disk space. In the past I had to delete and rebuild it every once in a while, so I wrote a script to solve it.

## When running the registry container, add REGISTRY_STORAGE_DELETE_ENABLED = true

```
docker run -d -p 5000:5000 -e REGISTRY_STORAGE_DELETE_ENABLED=true --name registry registry:2

docker update --restart=always registry
```
## Build Triggers > Build periodically > Enter
If you want the Jenkins job to run at 3 AM every Sunday, use the following CRON expression:
```
0 3 * * 0  
```
0: minute (fixed at 0, no need to be precise to the second).  
3: hour, meaning 3 AM.  
*: every day (no day-of-month restriction).  
*: every month (no month restriction).  
0: Sunday.  

![build periodically](https://blog.markkulab.net/content/markku/posts/jenkins-clear-docker-registry/images/build-periodically.png)
P.S. Ask ChatGPT for whatever schedule you want.
## Install Plugin - Pipeline Utility Steps

## Create a Pipeline Job and write the Jenkins pipeline
```
pipeline {
    agent any
    environment {
        REGISTRY = "192.168.50.50:5000"
    }
    stages {
        stage('Clean Registry') {
            steps {
                script {
                    try {
                        // Fetch all repositories
                        def response = httpRequest url: "http://${env.REGISTRY}/v2/_catalog", validResponseCodes: '200'
                        def repositories = readJSON(text: response.content).repositories

                        for (repository in repositories) {
                            echo "Processing repository: $repository"

                            // Fetch tags for the repository
                            def tagsResponse = httpRequest url: "http://${env.REGISTRY}/v2/${repository}/tags/list", validResponseCodes: '200,404'
                            def tagsList = readJSON(text: tagsResponse.content).tags

                            // Handle case when tagsList is null
                            if (tagsList == null || tagsList instanceof net.sf.json.JSONNull) {
                                echo "No tags found for repository: $repository. Skipping..."
                                continue
                            }

                            // Ensure tagsList is a serializable list
                            tagsList = new ArrayList(tagsList)

                            for (tag in tagsList) {
                                echo "Processing tag: $tag for repository: $repository"

                                try {
                                    // Fetch manifest and digest
                                    def manifestResponse = httpRequest(
                                        url: "http://${env.REGISTRY}/v2/${repository}/manifests/${tag}",
                                        customHeaders: [[name: 'Accept', value: 'application/vnd.docker.distribution.manifest.v2+json']],
                                        validResponseCodes: '200,404',
                                        httpMode: 'HEAD'
                                    )

                                    // Retrieve digest from headers
                                    def digest = manifestResponse.headers['Docker-Content-Digest']?.first()

                                    if (digest) {
                                        // Delete the image by digest
                                        httpRequest(
                                            url: "http://${env.REGISTRY}/v2/${repository}/manifests/${digest}",
                                            httpMode: 'DELETE',
                                            validResponseCodes: '202'
                                        )
                                        echo "Deleted ${repository}:${tag} with digest: ${digest}"
                                    } else {
                                        echo "Digest for ${repository}:${tag} not found! Skipping..."
                                    }
                                } catch (Exception e) {
                                    echo "Failed to process tag: $tag for repository: $repository. Error: ${e.message}"
                                }
                            }
                        }
                    } catch (Exception e) {
                        echo "Failed to clean registry. Error: ${e.message}"
                        error("Pipeline terminated due to errors.")
                    }
                }
            }
        }
    }
}
```

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/jenkins-clear-docker-registry)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
