skip to Main Content

I am a new docker user, trying to learn something about docker.
I have a private docker registry. Inside it I have some images (example: I1,I2,I3,I4,I5). A lot of those images have tags inside it. Lets consider the following ones:

Image I1 - Tags: T11, T12, T13
Image I2 - Tags: T21, T22, T23, T24
Image I3 - Tags: T31, T32
Image I4 - Tags: T41, T42, T43, vT44
Image I5 - Tags: T51, T52

I want to delete, lets say, only Tags: T12, T22 and T52, from docker registry.

How can I achieve it?

I´ve been reading a lot of posts but I still haven´t figure this out.
This ones seem to have some valuable content:
https://docs.docker.com/registry/spec/api/#deleting-an-image
Way to delete the images from Private Docker Registry
Although after even reading it I still could not figure out the way to do it.

If anyone can point me in the right direction I would appreciate it.

3

Answers


  1. This is a bit more complex than it seems on the surface if you want to delete a tag and not an image manifest. First a prerequisite, your registry needs to permit deleting images which isn’t turned on by default in the registry:2 image. The easy way to enable that is setting the environment variable REGISTRY_STORAGE_DELETE_ENABLED=true on the container.

    Next, realize the difference between a tag and an image manifest. The manifest is represented by a digest, and is the json data that points to the image config and layers. A tag points to a manifest, but multiple tags may point to the same manifest, and a manifest may not have any tags pointing to it. If you delete a manifest, that also removes all tags that point to the manifest, so you need to be careful when deleting tags that you don’t accidentally delete a manifest referenced by tags you want to keep.

    Therefore, the normal way to do this has issues. That normal way is to query the registry for the digest of the manifest you want to delete, and then delete that digest. You can get that digest from the headers:

    acceptM="application/vnd.docker.distribution.manifest.v2+json"
    acceptML="application/vnd.docker.distribution.manifest.list.v2+json"
    curl -H "Accept: ${acceptM}" 
         -H "Accept: ${acceptML}" 
         -I -s "https://registry.example.org/v2/${repo}/manifests/${tag}" 
    

    And then a delete request on that digest would delete the manifest, along with all tags that also point to it:

    curl -H "Accept: ${acceptM}" 
         -H "Accept: ${acceptML}" 
         -X DELETE -s "https://registry.example.org/v2/${repo}/manifests/${digest}" 
    

    However, if you want to delete just the tag, there is a delete tag API in distribution-spec, but few registries have implemented it. That delete would look like:

    curl -H "Accept: ${acceptM}" 
         -H "Accept: ${acceptML}" 
         -X DELETE -s "https://registry.example.org/v2/${repo}/manifests/${tag}" 
    

    For registries that don’t support this, the best solution I’ve found is to push a dummy manifest that replaces the tag, and then delete that dummy manifest. That gets to be a bit much to handle with curl, there’s more media type headers I haven’t been including, and this doesn’t talk about authentication. For all of those challenges, I turn to writing it in Go. My own tool for that is regclient, and others like skopeo and crane also exist. From regclient, the regctl command to do this looks like:

    regctl tag rm registry.example.org/image1:T12
    regctl tag rm registry.example.org/image2:T22
    regctl tag rm registry.example.org/image5:T22
    

    Once the image is deleted, you likely want to clean the storage that is used, and for that you need to run a garbage collection while no other pushes are in progress (some will disable the registry or wait until a time they know uploads will not run). With the registry:2 image, a GC command looks like:

    docker exec registry /bin/registry garbage-collect 
      /etc/docker/registry/config.yml --delete-untagged
    

    which will delete all untagged manifests, along with any unreferenced blobs.

    Caution: untagged manifests in the distribution registry currently includes all child manifests of a multi-platform image. This means deleting untagged manifests will likely lead to data-loss if you have multi-platform images in your registry. There’s issue 3178 to track when this will be resolved.

    Login or Signup to reply.
  2. While accepted answer is a good end solution, there is a simpler way to achieve this, without using the API: just delete the tag dirs manually from registry storage and then run the garbage-collect.

    First identify where your registry stores the data. By default it goes to /var/lib/registry dir inside the container, but its probably binded to your host one way or the other. I am using docker-compose with data volume so in my case its located at: /var/lib/docker/volumes/registry_data/_data/registry.

    You’ll find dirs named as your project tags in there, relative to above path:
    v2/repositories/<repo_name>/_manifests/tags

    Just delete the dirs which tag you dont want anymore. For example:

    rm -rf /var/lib/docker/volumes/registry_data/_data/registry/v2/repositories/I5/_manifests/tags/T12
    

    Once you are done with that, run the garbage-collect:

    docker exec <registry_container_name> registry garbage-collect /etc/docker/registry/config.yml --delete-untagged
    

    Your registry config file may be in some other path, but this is the default. Read more about the garbage collector from docs, but the gist is: the registry binary inside the container includes a garbage-collect command, but you have to run it yourself. Of course you can always let the crontab run it for you.

    Login or Signup to reply.
  3. There are 2 steps required:

    • Deleting the tags
    • Running Garbage Collection to free up space

    Tag Deletion

    There are cleaner ways of doing this with the HTTP/REST API but you can execute a controlled deletion of old tags (>30days) with this command:

    find /var/lib/registry/docker/registry/v2/repositories/*/_manifests/tags -type d -mtime +30 -maxdepth 1 -exec rm -rf {} ;
    

    This will effectively "untag" the images. I highly recommend you run the find command without -exec rm first to be sure of what you’re deleting!

    find /var/lib/registry/docker/registry/v2/repositories/*/_manifests/tags -type d -mtime +30 -maxdepth 1
    

    Kubernetes example (run from host machine):

    kubectl exec -it deploy/registry-docker-registry --   
      sh -c 'find /var/lib/registry/docker/registry/v2/repositories/*/_manifests/tags -type d -mtime +30 -maxdepth 1 -exec rm -rf {} ;'
    

    Garbage Collection

    Finally, run the garbage-collection -m executable.

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

    Or, from the host machine you can run it inside the container as follows (Kubernetes Example:

    kubectl exec -it deploy/registry-docker-registry --   
      /bin/registry garbage-collect -m /etc/docker/registry/config.yml
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search