How to delete images from a private docker registry?

Solution 1:

Currently you cannot use the Registry API for that task. It only allows you to delete a repository or a specific tag.

In general, deleting a repository means, that all the tags associated to this repo are deleted.

Deleting a tag means, that the association between an image and a tag is deleted.

None of the above will delete a single image. They are left on your disk.


Workaround

For this workaround you need to have your docker images stored locally.

A workaround for your solution would be to delete all but the latest tags and thereby potentially removing the reference to the associated images. Then you can run this script to remove all images, that are not referenced by any tag or the ancestry of any used image.

Terminology (images and tags)

Consider an image graph like this where the capital letters (A, B, ...) represent short image IDs and <- means that an image is based on another image:

 A <- B <- C <- D

Now we add tags to the picture:

 A <- B <- C <- D
           |    |
           |    <version2>
           <version1>

Here, the tag <version1> references the image C and the tag <version2> references the image D.

Refining your question

In your question you said that you wanted to remove

all images but the latest

. Now, this terminology is not quite correct. You've mixed images and tags. Looking at the graph I think you would agree that the tag <version2> represents the latest version. In fact, according to this question you can have a tag that represents the latest version:

 A <- B <- C <- D
           |    |
           |    <version2>
           |    <latest>
           <version1>

Since the <latest> tag references image D I ask you: do you really want to delete all but image D? Probably not!

What happens if you delete a tag?

If you delete the tag <version1> using the Docker REST API you will get this:

 A <- B <- C <- D
                |
                <version2>
                <latest>

Remember: Docker will never delete an image! Even if it did, in this case it cannot delete an image, since the image C is part of the ancestry for the image D which is tagged.

Even if you use this script, no image will be deleted.

When an image can be deleted

Under the condition that you can control when somebody can pull or push to your registry (e.g. by disabling the REST interface). You can delete an image from an image graph if no other image is based on it and no tag refers to it.

Notice that in the following graph, the image D is not based on C but on B. Therefore, D doesn't depend on C. If you delete tag <version1> in this graph, the image C will not be used by any image and this script can remove it.

 A <- B <--------- D
      \            |
       \           <version2>
        \          <latest>
         \ <- C
              |
              <version1>

After the cleanup your image graph looks like this:

 A <- B <- D
           |
           <version2>
           <latest>

Is this what you want?

Solution 2:

I've faced same problem with my registry then i tried the solution listed below from a blog page. It works.

Step 1: Listing catalogs

You can list your catalogs by calling this url:

http://YourPrivateRegistyIP:5000/v2/_catalog

Response will be in the following format:

{
  "repositories": [
    <name>,
    ...
  ]
}

Step 2: Listing tags for related catalog

You can list tags of your catalog by calling this url:

http://YourPrivateRegistyIP:5000/v2/<name>/tags/list

Response will be in the following format:

{
"name": <name>,
"tags": [
    <tag>,
    ...
]

}

Step 3: List manifest value for related tag

You can run this command in docker registry container:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/<name>/manifests/<tag> 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}'

Response will be in the following format:

sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Run the command given below with manifest value:

curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://127.0.0.1:5000/v2/<name>/manifests/sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073

Step 4: Delete marked manifests

Run this command in your docker registy container:

bin/registry garbage-collect  /etc/docker/registry/config.yml  

Here is my config.yml

root@c695814325f4:/etc# cat /etc/docker/registry/config.yml
version: 0.1
log:
  fields:
  service: registry
storage:
    cache:
        blobdescriptor: inmemory
    filesystem:
        rootdirectory: /var/lib/registry
    delete:
        enabled: true
http:
    addr: :5000
    headers:
        X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

Solution 3:

The current v2 registry now supports deleting via DELETE /v2/<name>/manifests/<reference>

See: https://github.com/docker/distribution/blob/master/docs/spec/api.md#deleting-an-image

Working usage: https://github.com/byrnedo/docker-reg-tool

Edit: The manifest <reference> above can be retrieved from requesting to

GET /v2/<name>/manifests/<tag>

and checking the Docker-Content-Digest header in the response.

Edit 2: You may have to run your registry with the following env set:

REGISTRY_STORAGE_DELETE_ENABLED="true"

Edit3: You may have to run garbage collection to free this disk space: https://docs.docker.com/registry/garbage-collection/