$ docker pull redis:alpine
$ docker tag redis:alpine myimage:1
$ docker run -d myimage:1
552ae8f1134235f9c7d41ec220c9978cb51fd387d4a2d2cd4215b108950ee7c1
$ docker container ls --format '{{.Image}}'
myimage:1
$ docker image rm myimage:1
Untagged: myimage:1
$ docker image rm redis:alpine
Error response from daemon: conflict: unable to remove repository reference "redis:alpine" (must force) - container 20c7d341f7f5 is using its referenced image d3117424aaee
$ docker container ls --format '{{.Image}}'
d3117424aaee
I don't know how you can say this isn't broken. It's fine to untag a reference that IS being used and referenced by a container, but it's not ok to remove a completely unreferenced tag?
If we have to keep a tag around, we should keep the tag that's actually being used.
for example:
tagging image with myimage-backup without removing the container and freeing up the reference to be used by the new container with an option to rollback to the old image
clearing up junk images that are duplicates of used ones
untagging myrepo:latest when you know that it is not up-to-date anymore. so that when new containers are created they would point to/pull a new image
prune should just be an automated version of image rm. That should be the only difference. Otherwise it's unnecessary confusion for the user.
I explained the differences 3 comments above. Prune is about removing unused images, rmi is not only about removing images but also about untagging a specific reference that user has picked out.
Those untagging rules are running before determining conflicts and documented just 10 lines before the conflicts documentation.
I don't know how you can say this isn't broken.
It isn't broken because this is what it was designed to do and how it is documented. That design idea/compromise was that container is not related to a reference but an actual image. Changing a reference after creating a container has no effect to the container after that, it is only a pointer for finding an image on creation time. rmi isn't only way to untag an image, you can do the same thing with tag and pull. Your example is much easier to understand than these cases. User explicitly asks to remove or untag the image. It is successfully untagged. It should not be a surprise at all that it can't be used in a completely new docker run. Container list shows a link to parent image so all the tools using that link still work(as well as restarting the container). The ref doesn't disappear from the container list because the reference was deleted but because the list code knows that references are mutable and always checks if whatever string user typed when starting a container would still be valid as a reference to that image. Inspect always shows image ID, and inspecting images shows all current refs as equal.
In case you have better ideas feel free to make proposals but finding a documented behavior that has weird edge cases does not make it a bug. rmi behaves like documented, prune does not behave like documented.
tagging image with myimage-backup without removing the container and freeing up the reference to be used by the new container with an option to rollback to the old image
This is still supported by my proposed behaviour because you can always build or image tag over an existing tag. You don't even need to delete the original tag. Why would you need to "free it" ?
clearing up junk images that are duplicates of used ones
Should still be supported as long as no container is using them. If a container is using them they aren't junk, right? Or if you really want to you can always -f.
untagging myrepo:latest when you know that it is not up-to-date anymore. so that when new containers are created they would point to/pull a new image
This is the only use case that isn't directly supported. However a more straighforward way of doing this would be to docker pull myrepo:latest. Why just rmi the thing instead of updating it directly?
It isn't broken because this is what it was designed to do and how it is documented
That's fair. Broken is the wrong word for it. I think it's unexpected behaviour that needs to be fixed, so you're correct that I should open a new issue for this. I have opened #36435.
I still maintain that image prune and image rm should behave the same way (with the exception of one being automated). Not because image rm should act like prune, but because consistent and expected behaviour are important qualities of an API. So I consider this issue (#36295) as a wont-fix, as it will be addressed by #36435.
Is there an option to delete old (tagged) docker image AUTOMATICALLY if they are not associated to container
caprover/caprover#234
We have images tagged with both :latest and :[version], and we use :[version] in our compose file. After pruning the images, restart the server/docker, the services then just refuse to work (without re-deploying).
This is certainly wrong.
copying from docker/cli#2247 (comment)
I agree that for docker image prune -a this is definitely confusing;
If an image is in use, and tagged under multiple names, then running docker image prune will remove tags for the image that is in used but will keep 1 tag. Not sure if the tags that are removed are "random" or explicitly include the tag that's actually in use, but in the example below, the tag that's actually used is removed, and tags that are unused are removed.
If possible, I think that that behaviour (at least for docker image prune) should be changed.
example
Pull the busybox:latest image, and tag the image under some other names:
docker image pull busybox:latest
docker image tag busybox:latest thajeztah/busybox:latest
docker image tag busybox:latest thajeztah/busybox2:latest
there's now three tags for the same image
docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
busybox latest 6d5fcfe5ff17 13 days ago 1.22MB
thajeztah/busybox2 latest 6d5fcfe5ff17 13 days ago 1.22MB
thajeztah/busybox latest 6d5fcfe5ff17 13 days ago 1.22MB
Now, run a container, using the busybox:latest tag
docker run -dit --name mycontainer busybox:latest
Prune images with the -a/--all option set
docker image prune -a
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: busybox:latest
untagged: busybox@sha256:6915be4043561d64e0ab0f8f098dc2ac48e077fe23f488ac24b665166898115a
untagged: thajeztah/busybox2:latest
Total reclaimed space: 0B
Notice that in this case, it removed the thajeztah/busybox2:latest and busybox:latest tags (even though the container was using that), but keeps one tag so that the image still is referenced.
Removing the container, and running docker image prune -a again will remove the remaining tag for the image, and will remove the image itself:
docker rm -f mycontainer
WARNING! This will remove all images without at least one container associated to them.
Are you sure you want to continue? [y/N] y
Deleted Images:
untagged: thajeztah/busybox:latest
deleted: sha256:6d5fcfe5ff170471fcc3c8b47631d6d71202a1fd44cf3c147e50c8de21cf0648
deleted: sha256:195be5f8be1df6709dafbba7ce48f2eee785ab7775b88e0c115d8205407265c5
Total reclaimed space: 1.22MB
To make the behavior less surprising, I think it should (for docker image prune) remove the unused tag(s), and keep the tags that are in use.
Maybe some helpful input:
This was working as expected in Docker API version 1.26 but currently not on version 1.39.
Tried to look into the source code but I'm far too inexperienced in Golang to be able to help more unfortunately. Hope it is solved soon since it's a great feature when working :)
Think I ran into this issue as well, I build and deploy images like so:
for dir in onfw fhwb fnwb nfwb jurwb
cd $dir/dockerapp
export APPNAME=$dir
docker build --build-arg EXISTADDONSVERSION=2.5-SNAPSHOT --secret id=adminpw,src=adminpw -t ${APPNAME}:${VERSION} .
docker stack rm $APPNAME
sleep 15
docker stack deploy --compose-file docker-compose.yml $APPNAME
cd ../..
image ls will now show 5 images
Regularly I run docker system prune -a
The 4 images last created are removed, athough in use.
The isSingleReference() is iterating through the references in the order of creation without checking if any container exists, since isSingleReference() returns a false we proceed to remove the references.
The above-mentioned behavior doesn't happen when using docker image prune [IMAGE_ID] since it relies on a different set of checks before deleting and moreover relies on imageDeleteHelper().
moby/daemon/images/image_delete.go
Lines 157 to 164
2f74fa5
Also while looking into this, found a small discrepancy in behavior between the 2 flow,
docker image rm [IMAGE_ID] gives the below error if a container attached with the same image is running. (doesn't allow to be forced)
root@a46e2988ae4f:/go/src/github.com/docker/docker# docker ps -a
DEBU[2021-08-22T21:31:20.412062382Z] Calling GET /_ping
DEBU[2021-08-22T21:31:20.412332961Z] Calling GET /v1.30/containers/json?all=1
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
19d35ebceb80 busybox:latest "sh" 12 minutes ago Up 1 second mycontainer
----------------------------------------------
Error response from daemon: conflict: unable to delete 42b97d3c2ae9 (cannot be forced) - image is being used by running container 19d35ebceb80
docker image rm [IMAGE_NAME] gives the below error in the same scenario, (allows to be forcibly removed successfully)
Error response from daemon: conflict: unable to remove repository reference "busybox" (must force) - container 19d35ebceb80 is using its referenced image 42b97d3c2ae9
To fix the issue at hand I'm thinking of having the check mentioned here, out into the if expression so as to give priority for running containers.
https://github.com/moby/moby/blob/master/daemon/images/image_delete.go#L89
Since the second discrepancy isn't documented anywhere (couldn't find one at least), assuming it's an issue I think we should re-use the same checks built across the two variations (by ID ref and repo ref).
Please let me know if this approach is valid, will push the bug fix after that.