October 18th, 2017

Cobe.io: Pruning a Private Docker Registry

Programing, Python, by admin.

Why do we need a private Docker registry?

We currently use Jenkins to run our build and test process and we
currently have two slaves running on our Jenkins cluster. When a
pull request is created/updated, our process builds the Docker files
that are stored within the code repository. Once a slave has built a Docker
image it’s ideal that the other slave can access the newly built image.
One way to achieve this is to have a centrally accessible registry.

How to run a Docker registry

This is relatively easy step as there is a Docker registry image available
on Docker Hub. Currently our registry is running on our Jenkins master server.
Execute this command to run it:

docker run -d -p 5000:5000 --name registry \
 --restart=unless-stopped -e REGISTRY_STORAGE_DELETE_ENABLED=true registry

I’ll go through each command option briefly:

docker run
Uses Docker to run a container based on an image.
Run in detatched mode.
-p 5000:5000
Expose port 5000 from the current host into the registry container.
--name registry
Names the container to make it easier to reference.
Tells Docker to keep this container running unless manually stopped.
Configures the registry to allow DELETE requests.
The image to run from Docker Hub.

This will run a Docker registry that allows delete requests on port 5000.

Persisting the registry

When the image is restarted it loses its images that it stores. This
is solved by using a Docker volume to store the images.

docker volume create registry-vol

And adding the following argument to the Docker run command above:

-v registry-vol:/var/lib/registry:rw

So the full command is now:

docker run -d -p 5000:5000 --name registry \
 --restart=unless-stopped \
 -v registry-vol:/var/lib/registry:rw registry

Clearing out unused images

As all of the images that Jenkins pushes are tagged as latest our
goal is to search through all of the repositories in the registry and
delete all of the images tagged as latest.

To do this we first get all of the repositories using this method.

REGISTRY_URL = "https://registry:5000/v2/"

def get_repositories():
 resp = requests.get(REGISTRY_URL + "_catalog")
 return resp.json()['repositories']

For each of our repositories we get a list of tags.

def get_tags(repository):
 resp = requests.get(REGISTRY_URL + repository + "/tags/list")
 return resp.json()['tags'] if json_resp['tags'] else []

In order to delete an image we need its digest.

def get_digest(repository, tag):
 url = "{}{}/manifests/{}".format(JENKINS_REGISTRY_URL, repository, tag)
 headers = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"}
 resp = requests.get(url, headers=headers)
 return resp.headers.get("Docker-Content-Digest")

And we use this method to submit a delete request.

def delete_digest(repository, digest):
 requests.delete(REGISTRY_URL + repo + "/manifests/" + digest)

So to tie all of this together we use this method.

def clear_registry_tag(tag="latest"):
 for repository in get_repositories():
 for found_tag in get_tags(repository):
 if found_tag == tag:
 digest = get_digest(repository, found_tag)
 delete_digest(repository, digest)

For brevity error handling and printing have been removed but a full
version of the Python script can be downloaded pruning-docker-registry.py.

Back Top

Leave a Reply