I run a private docker registry, and I want to delete all images but the latest
from a repository. I don't want to delete the entire repository, just some of the images inside it. The API docs don't mention a way to do this, but surely it's possible?
-
7Accepted answer is not correct anymore (though definitely very good). You can remove images using DELETE /v2/
/manifests/ – Michael Zelensky Jun 05 '20 at 07:02: https://docs.docker.com/registry/spec/api/#deleting-an-image -
@MichaelZelensky i tried a 'tag' for
but that didn't work for me. which – Houtman Oct 23 '20 at 07:37should i use/how to obtain it? (using this registry: https://registry.hub.docker.com/_/registry/ from October 2020 ) -
1using: GET -m DELETE -C
https://:81/v2/ – Houtman Oct 23 '20 at 07:43/manifests/latest response: {"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]} -
1@Houtman, have a look here: https://stackoverflow.com/questions/62211899/what-is-docker-image-reference – Michael Zelensky Oct 24 '20 at 12:56
-
@MichaelZelensky That link does not explain the unsupported error, does it for you? if yes, could you summarize it please? – Melardev Dec 10 '21 at 20:09
-
2@Melardev _api.md#delete-manifest_ `Note that a manifest can only be deleted by digest` _api.md#digest-parameter_ `sha256:6c3c624b58dbbcd3c0dd82b4c53f04194d1247c6eebdaab7c610cf7d66709b3b` and env required for deletion in registry: `REGISTRY_STORAGE_DELETE_ENABLED=TRUE` – Dek4nice Mar 14 '22 at 13:43
17 Answers
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?

- 1
- 1

- 4,275
- 3
- 27
- 35
-
You're right--deleting the tags didn't actually delete the associated images. Is there any way to delete the images given ssh access to the box, then? – Leo Aug 28 '14 at 20:19
-
2I've edited my answer with a workaround that does the job for me. I hope it helps. – Konrad Kleine Aug 29 '14 at 11:52
-
That's exactly it--I understand that images are built incrementally, but I need a way to prune those dead branches. Thanks! – Leo Aug 29 '14 at 20:56
-
@KonradKleine how do you make the images graph out of the list of images you get from the registry? – Rafael Barros Dec 15 '14 at 22:46
-
@RafaelBarros The image "graph" is nothing more than a simple list of image IDs. Take a look at this script https://gist.github.com/kwk/c5443f2a1abcf0eb1eaa . It operates not on the Registry API but on the file system. It's just a matter of collecting all image IDs we have in a list and removing those from the list that are part of another image's ancestry. The remainder are those images that can be deleted. (I quite often use the term image and layer interchangeably.) – Konrad Kleine Dec 16 '14 at 08:25
-
13Garbage collecting has finally arrived to the Registry v2.4.0 https://docs.docker.com/registry/garbage-collection/ – Markus Rexhepi-Lindberg Apr 14 '16 at 07:32
-
I check your script ... why go all through these hassle? I know the uuid value of the tag, and I know the repo name. I also know, that my image has no ancestry, (except the base ubuntu). So I can just login and 'rm -rf' the corresponding folders. And by the way, /var/lib/* is not always the location, so the script felt risky. – daparic Aug 01 '16 at 06:18
-
@daixtr I know that the script isn't perfect but it it gives a start. If you have the knowledge that you have regarding ancestry of your image you can go in an delete whatever you like but for a more systematic approach you need to go through all the hassle or upgrade to registry 2.4.0 at least as markus-lindberg pointed out. – Konrad Kleine Aug 02 '16 at 06:14
-
one doubt, even if I am restarting the raspi where registry server is setup with some images in the private repo, all the images are lost. I tried passing restart = always. – stackjohnny Dec 21 '18 at 18:30
-
I've faced the same problem with my registry, then I tried the solution listed below from a blog page. It works.
Do note, the deletion must be enabled for it to work. You can do it by providing a custom config, or by setting REGISTRY_STORAGE_DELETE_ENABLED=true
.
Step 1: List the repositories
$ curl -sS <domain-on-ip>:5000/v2/_catalog
The response will be in the following format:
{
"repositories": [
<repo>,
...
]
}
Step 2: List the repository tags
$ curl -sS <domain-on-ip>:5000/v2/<repo>/tags/list
The response will be in the following format:
{
"name": <repo>,
"tags": [
<tag>,
...
]
}
Step 3: Determine the digest of the target tag
$ curl -sS -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \
-o /dev/null \
-w '%header{Docker-Content-Digest}' \
<domain-or-ip>:5000/v2/<repo>/manifests/<tag>
Do note, the Accept
header is needed here. Without it you'll get a different value and the deletion will fail.
The response will be in the following format:
sha256:6de813fb93debd551ea6781e90b02f1f93efab9d882a6cd06bbd96a07188b073
Step 4: Delete the manifest
$ curl -sS -X DELETE <domain-or-ip>:5000/v2/<repo>/manifests/<digest>
Step 5: Garbage collect the image
Run this command in your docker registry container:
$ registry garbage-collect /etc/docker/registry/config.yml
Here is my 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

- 16,722
- 15
- 114
- 161

- 2,387
- 2
- 13
- 26
-
1The commands succeeded, including messages about "`Deleteing blob: /docker/...`" but it didn't change the disk space used. Using _bin/registry github.com/docker/distribution v2.4.1_. – JamesThomasMoon May 18 '17 at 00:26
-
5to delete an image, you should run the registry container with REGISTRY_STORAGE_DELETE_ENABLED=true parameter. – Adil Nov 06 '17 at 08:05
-
3I set "delete: enabled" value to true in /etc/docker/registry/config.yml file. For this configuration no need to set REGISTRY_STORAGE_DELETE_ENABLED variable @AdilIlhan – Yavuz Sert Nov 15 '17 at 07:31
-
re: step 3, the "Docker-Content-Digest" must be in the header? (not seeing it in the curl output). Should I be able to see the results of marking a manifest before deleting the marked manifest(s) to know I successfully marked it? It seems to give me a 202 response no matter what I send it. – SteveW Nov 19 '18 at 21:26
-
the `Docker-Content-Digest` part should be in lowercase (tested on docker engine v18.09.2) i.e. `curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://localhost:5000/v2/
/manifests/ – Muhammad Abdurrahman May 30 '19 at 10:152>&1 | grep docker-content-digest | awk '{print ($3)}'` -
In the step 3 the part with `awk` must be in that way `awk '{print $2}'` and add the option `-I` to the `curl` command !! – Felipe Pereira Aug 02 '19 at 15:18
-
3Thank you, this is the first answer that worked for me. I was missing `Accept: application/vnd.docker.distribution.manifest.v2+json` header and kept on getting `MANIFEST_UNKNOWN` error. Even though it's somewhere in their documentation(https://docs.docker.com/registry/spec/api/) it's very confusing. – Tomasz W Nov 27 '19 at 14:10
-
2Steps 3 doesn't return any output (not even an errors !!), any suggestions ! – McLan Jun 16 '21 at 08:34
-
@TomaszW Good you thing you pointed out the header. Somehow I overlooked this every time I was reading around. Saved me. – Blaisem Jul 14 '23 at 02:56
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
The <reference>
can be taken from the Docker-Content-Digest
header of a GET /v2/<name>/manifests/<tag>
request (do note that the Accept: application/vnd.docker.distribution.manifest.v2+json
header is needed for this request).
A script that makes use of it: https://github.com/byrnedo/docker-reg-tool
For it to work deletion must be enabled (REGISTRY_STORAGE_DELETE_ENABLED=true
).
And to really free the disk space you need to run garbage collection.
-
3Some other answers here show how to extract manifest reference hash. This is necessary to translate a tag into something to pass to `DELETE`. – JamesThomasMoon May 18 '17 at 00:24
-
Getting unsupported error. I have given proper digest value as the reference. – Winster Feb 22 '18 at 06:36
-
-
v2. My disk image size has grown to 65GB mostly contributed by deleted registry containers and finally I had to reset to factory. – Winster Feb 22 '18 at 11:14
-
1@JamesThomasMoon1979 updated with instructions about getting the reference hash. – byrnedo Aug 09 '18 at 11:23
-
17on V2 too and getting error `{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}` – Gadelkareem Oct 31 '18 at 21:30
-
1```{"errors":[{"code":"UNSUPPORTED","message":"The operation is unsupported."}]}``` any suggestion ? – Kumaresan P Feb 13 '20 at 13:20
This is really ugly but it works, text is tested on registry:2.5.1. I did not manage to get delete working smoothly even after updating configuration to enable delete. The ID was really difficult to retrieve, had to login to get it, maybe some misunderstanding. Anyway, the following works:
Enter the container
docker exec -it registry sh
Define variables matching your container and container version:
export NAME="google/cadvisor" export VERSION="v0.24.1"
Move to the the registry directory:
cd /var/lib/registry/docker/registry/v2
Delete files related to your hash:
find . | grep `ls ./repositories/$NAME/_manifests/tags/$VERSION/index/sha256`| xargs rm -rf $1
Delete manifests:
rm -rf ./repositories/$NAME/_manifests/tags/$VERSION
Logout
exit
Run the GC:
docker exec -it registry bin/registry garbage-collect /etc/docker/registry/config.yml
If all was done properly some information about deleted blobs is shown.
-
i followed the same steps mentioned above, but when i checked the docker registry {container} disk usage it was showing same as before doing the steps... any idea why? – Savio Mathew Apr 26 '18 at 10:28
-
doesn't work. Easy to check. When you do the following steps and push the repo again it says "064794e955a6: Layer already exists " – Oduvan Jul 23 '19 at 10:38
-
Problem 1
You mentioned it was your private docker registry, so you probably need to check Registry API instead of Hub registry API doc, which is the link you provided.
Problem 2
docker registry API is a client/server protocol, it is up to the server's implementation on whether to remove the images in the back-end. (I guess)
DELETE /v1/repositories/(namespace)/(repository)/tags/(tag*)
Detailed explanation
Below I demo how it works now from your description as my understanding for your questions.
I run a private docker registry.
I use the default one, and listen on port 5000
.
docker run -d -p 5000:5000 registry
Then I tag the local image and push into it.
$ docker tag ubuntu localhost:5000/ubuntu
$ docker push localhost:5000/ubuntu
The push refers to a repository [localhost:5000/ubuntu] (len: 1)
Sending image list
Pushing repository localhost:5000/ubuntu (1 tags)
511136ea3c5a: Image successfully pushed
d7ac5e4f1812: Image successfully pushed
2f4b4d6a4a06: Image successfully pushed
83ff768040a0: Image successfully pushed
6c37f792ddac: Image successfully pushed
e54ca5efa2e9: Image successfully pushed
Pushing tag for rev [e54ca5efa2e9] on {http://localhost:5000/v1/repositories/ubuntu/tags/latest}
After that I can use Registry API to check it exists in your private docker registry
$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags
{"latest": "e54ca5efa2e962582a223ca9810f7f1b62ea9b5c3975d14a5da79d3bf6020f37"}
Now I can delete the tag using that API !!
$ curl -X DELETE localhost:5000/v1/repositories/ubuntu/tags/latest
true
Check again, the tag doesn't exist in my private registry server
$ curl -X GET localhost:5000/v1/repositories/ubuntu/tags/latest
{"error": "Tag not found"}
-
4Please, see my answer below for an explanation why this command doesn't help. – Konrad Kleine Aug 28 '14 at 14:21
-
3You delete tags but not the image data. The latter is done by the script I reference after you have deleted a tag. I also use the registry API to delete a tag. – Konrad Kleine Aug 31 '14 at 14:53
-
3it is upto each registry API server's implementation, from protocol's point of view, it doesn't exist. – Larry Cai Aug 31 '14 at 14:57
-
You're right that it's up to the implementation--but I was/am looking for a way to delete image data from the canonical `registry` image. SSHing in and running a script works, even if it's not ideal. As a side note I still think it's an incomplete API--you can delete tags, but if you GET `/images` you still see all the leftover image data. – Leo Sep 05 '14 at 08:24
-
Thanks for mentioning Registry API, was looking for a way to DELETE an image in private registry. This method is good enough for me even if it's just 'untagging' without actually free up disk space. – Howard Lee Nov 11 '14 at 18:10
-
-
This 'curl' method to delete tags is very helpful. Thank you good sir. – daparic Aug 01 '16 at 06:19
-
@KonradKleine you focus so much about the tag<->image difference in your answer that you actually forgot to answer what was asked. This is what LarryCai did better – Daniel Alder Dec 12 '17 at 13:00
-
-
There are some clients (in Python, Ruby, etc) which do exactly that. For my taste, it isn't sustainable to install a runtime (e.g. Python) on my registry server, just to housekeep my registry!
So deckschrubber
is my solution:
go install github.com/fraunhoferfokus/deckschrubber@latest
$GOPATH/bin/deckschrubber
images older than a given age are automatically deleted. Age can be specified using -year
, -month
, -day
, or a combination of them:
$GOPATH/bin/deckschrubber -month 2 -day 13 -registry http://registry:5000
UPDATE: here's a short introduction on deckschrubber.
-
1`deckschrubber` is pretty good - very easy to install (single binary), and lets you delete images by name (with regex match) as well as age. – RichVel Sep 05 '17 at 13:23
-
-
-
-
Unfortunately, it will not remove images which don't have tags. So if you keep pushing images on a single tag, it will only check the one which is tagged, not the other ones. – Krystian Mar 25 '19 at 10:06
-
-
-
It depends. If you start your comment with "unfortunately", I'd assume that it's an issue in your specific use case, which we might be able to address. right? – Yan Foto Mar 25 '19 at 13:54
The requirement to delete all tags except latest
gets complicated because the same image manifest can be pointed to by multiple tags, so when you delete a manifest for one tag, you may effectively delete multiple tags.
There are a few options to make that workable. One is to track the digest for the latest tag and only delete manifests for other digests, or you can use some different API calls to delete the tags themselves.
Regardless of how you implement this, first your registry needs to be configured to allow the delete API's. With the minimal registry:2
image, that involves starting it with an environment variable REGISTRY_STORAGE_DELETE_ENABLED=true
(or the equivalent yaml config).
Then for a simple script to loop through the tags and delete, there's:
#!/bin/sh
repo="localhost:5000/repo/to/prune"
for tag in $(regctl tag ls $repo); do
if [ "$tag" != "latest" ]; then
echo "Deleting: $(regctl image digest --list "${repo}:${tag}") [$tag]"
regctl tag rm "${repo}:${tag}"
fi
done
The regctl
command used here comes from regclient and the regctl tag rm
logic first attempts to perform the tag delete API added recently to the distribution-spec. Since most registries haven't implemented that spec, it falls back to the manifest delete API, but it first creates a dummy manifest to overwrite the tag, and then deletes that new digest. In doing so, if the old manifest was in use by other tags, it doesn't delete those other tags.
An alternative version of the script that deletes manifests except those pointing to the latest
digest looks like:
#!/bin/sh
repo="localhost:5000/repo/to/prune"
save="$(regctl image digest --list "${repo}:latest")"
for tag in $(regctl tag ls $repo); do
digest="$(regctl image digest --list "${repo}:${tag}")"
if [ "$digest" != "$save" ]; then
echo "Deleting: $digest [$tag]"
regctl manifest rm "${repo}@${digest}"
fi
done
If you find yourself needing to create a deletion policy to automate the deleting of lots of images, I'd recommend looking at regclient/regbot
from the same repo which allows you to define that policy and leave it running to continuously prune your registry.
Once the images have been deleted, you'll need to garbage collect your registry in most use cases. For example with the registry:2
image that looks like:
docker exec registry /bin/registry garbage-collect \
/etc/docker/registry/config.yml --delete-untagged
Caution: there is an open issue with the garbage-collect utility that will delete untagged child manifests of a multi-platform image. If you are using multi-platform images, you'll need to ensure every platform specific image is tagged or avoid using the above GC command until the issue has been resolved in your deployed version.

- 231,797
- 42
- 475
- 450
I am usually all for doing things with scripts, but if you are already running a registry UI container built from Joxit/docker-registry-ui, I found it easier to just opt-click the delete button in the UI and delete a page of images at a time, then garbage collect after.

- 5,099
- 4
- 53
- 73
Briefly;
1) You must typed following command for RepoDigests of a docker repo;
## docker inspect <registry-host>:<registry-port>/<image-name>:<tag>
> docker inspect 174.24.100.50:8448/example-image:latest
[
{
"Id": "sha256:16c5af74ed970b1671fe095e063e255e0160900a0e12e1f8a93d75afe2fb860c",
"RepoTags": [
"174.24.100.50:8448/example-image:latest",
"example-image:latest"
],
"RepoDigests": [
"174.24.100.50:8448/example-image@sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6"
],
...
...
${digest} = sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6
2) Use registry REST API
##curl -u username:password -vk -X DELETE registry-host>:<registry-port>/v2/<image-name>/manifests/${digest}
>curl -u example-user:example-password -vk -X DELETE http://174.24.100.50:8448/v2/example-image/manifests/sha256:5580b2110c65a1f2567eeacae18a3aec0a31d88d2504aa257a2fecf4f47695e6
You should get a 202 Accepted for a successful invocation.
3-) Run Garbage Collector
docker exec registry bin/registry garbage-collect --dry-run /etc/docker/registry/config.yml
registry — registry container name.
For more detail explanation enter link description here

- 5,763
- 2
- 46
- 32
Another tool you can use is registry-cli. For example, this command:
registry.py -l "login:password" -r https://your-registry.example.com --delete
will delete all but the last 10 images.

- 1,973
- 16
- 20
There is also a way you can remove some old images from repository just based on the date when it was created.
To do that enter your docker registry container and get the list of manifest's revisions for some specific repository:
ls -latr /var/lib/registry/docker/registry/v2/repositories/YOUR_REPO/_manifests/revisions/sha256/
The output then may be used within the request (with sha256 prefix):
curl -v --silent -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE http://DOCKER_REGISTRY_HOST:5000/v2/YOUR_REPO/manifests/sha256:OUTPUT_LINE
And of course do not forget to execute 'garbage-collect' command after that:
bin/registry garbage-collect /etc/docker/registry/config.yml

- 43
- 4
This docker image includes a bash script that can be used to remove images from a remote v2 registry : https://hub.docker.com/r/vidarl/remove_image_from_registry/

- 11
- 2
Below Bash Script Deletes all the tags located in registry except the latest.
for D in /registry-data/docker/registry/v2/repositories/*; do
if [ -d "${D}" ]; then
if [ -z "$(ls -A ${D}/_manifests/tags/)" ]; then
echo ''
else
for R in $(ls -t ${D}/_manifests/tags/ | tail -n +2); do
digest=$(curl -k -I -s -H -X GET http://xx.xx.xx.xx:5000/v2/$(basename ${D})/manifests/${R} -H 'accept: application/vnd.docker.distribution.manifest.v2+json' | grep Docker-Content-Digest | awk '{print $2}' )
url="http://xx.xx.xx.xx:5000/v2/$(basename ${D})/manifests/$digest"
url=${url%$'\r'}
curl -X DELETE -k -I -s $url -H 'accept: application/vnd.docker.distribution.manifest.v2+json'
done
fi
fi
done
After this Run
docker exec $(docker ps | grep registry | awk '{print $1}') /bin/registry garbage-collect /etc/docker/registry/config.yml

- 673
- 6
- 17
-
1Could you elaborate a bit more on how to use this fine script? – Khalil Gharbaoui Oct 03 '19 at 16:29
Simple ruby script based on this answer: registry_cleaner.
You can run it on local machine:
./registry_cleaner.rb --host=https://registry.exmpl.com --repository=name --tags_count=4
And then on the registry machine remove blobs with /bin/registry garbage-collect /etc/docker/registry/config.yml
.

- 271
- 2
- 16
Here is a script based on Yavuz Sert's answer. It deletes all tags that are not the latest version, and their tag is greater than 950.
#!/usr/bin/env bash
CheckTag(){
Name=$1
Tag=$2
Skip=0
if [[ "${Tag}" == "latest" ]]; then
Skip=1
fi
if [[ "${Tag}" -ge "950" ]]; then
Skip=1
fi
if [[ "${Skip}" == "1" ]]; then
echo "skip ${Name} ${Tag}"
else
echo "delete ${Name} ${Tag}"
Sha=$(curl -v -s -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X GET http://127.0.0.1:5000/v2/${Name}/manifests/${Tag} 2>&1 | grep Docker-Content-Digest | awk '{print ($3)}')
Sha="${Sha/$'\r'/}"
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" -X DELETE "http://127.0.0.1:5000/v2/${Name}/manifests/${Sha}"
fi
}
ScanRepository(){
Name=$1
echo "Repository ${Name}"
curl -s http://127.0.0.1:5000/v2/${Name}/tags/list | jq '.tags[]' |
while IFS=$"\n" read -r line; do
line="${line%\"}"
line="${line#\"}"
CheckTag $Name $line
done
}
JqPath=$(which jq)
if [[ "x${JqPath}" == "x" ]]; then
echo "Couldn't find jq executable."
exit 2
fi
curl -s http://127.0.0.1:5000/v2/_catalog | jq '.repositories[]' |
while IFS=$"\n" read -r line; do
line="${line%\"}"
line="${line#\"}"
ScanRepository $line
done

- 171
- 2
- 12
A script to remove all but the latest
tag from an insecure registry (private, no auth):
#!/bin/sh -eu
repo=$1
registry=${2-localhost:5000}
tags=`curl -sS "$registry/v2/$repo/tags/list" | jq -r .tags[]`
tag2digest() {
local tag=$1
curl -sS -H 'Accept: application/vnd.docker.distribution.manifest.v2+json' \
-o /dev/null \
-w '%header{Docker-Content-Digest}' \
"$registry/v2/$repo/manifests/$tag"
}
latest_digest=`tag2digest latest`
digests=`echo "$tags" \
| while IFS= read -r tag; do
tag2digest "$tag"
echo
done \
| sort \
| uniq`
digests=`echo "$digests" \
| grep -Fvx "$latest_digest"`
echo "$digests" \
| while IFS= read -r digest; do
curl -sS -X DELETE "$registry/v2/$repo/manifests/$digest"
done
Usage:
$ ./rm-tags.sh <image> [<registry>]
After removing tags (or manifests to be more precise) run garbage collection:
$ registry garbage-collect /etc/docker/registry/config.yml

- 16,722
- 15
- 114
- 161
This is the simplest solution that worked for my setup, using a private registry in a swarm cluster
Experimenting with whatever filter you need
docker images | grep 'your_own_filter'
tail -n +4
: keep the last 3 images that got built
awk '{print $3}'
: will extract the 3rd column, which is the 'IMAGE ID'
Example:
docker rmi $(docker images | grep 'your_own_filter' | tail -n +4 | awk '{print $3}')

- 8,374
- 8
- 39
- 50
-
How does this delete the images from the docker registry? The `docker rmi` command only deletes images from your local docker engine. – BMitch Jul 25 '23 at 14:03