「Docker」- 删除镜像

  CREATED BY JENKINSBOT

本笔记的内容包含:如何删除本地 Docker 镜像;如何删除远程 Docker 镜像;在删除过程中出现的常见问题的处理;还涉及了一些 Docker 镜像存储方式方面的内容。

删除远程镜像

在镜像仓库(如 Docker Hub 中)中的镜像,目前不能通过命令删除,要在镜像仓库中删除。通过单击按钮来完成删除操作,不涉及特别复杂的内容,所以简单略过。

# 08/08/2019 今天在 Docker v19.03 (current) 看到了 docker registry rmi 命令,可以从Registry中移除镜像,目前出于实验性质。

删除本地镜像

删除单个或多个镜像

使用 docker rmidocker image rm 命令来删除本地镜像(只能删除本地镜像,不能删除在镜像仓库中的镜像):

# 通过 Image ID 删除
docker rmi fd484f19954f

# 下面这两个是等价的,因为 latest 是默认的标签
docker rmi test1:latest
docker rmi test1

# 还可以通过 DIGEST 来删除。在 REPOSITORY 与 DIGEST之间,使用 @ 分隔。
# 因为使用 DIGEST 拉取的镜像是没有 TAG 的,所以会用到这种方法。
docker rmi test/busybox@sha256:cbbf2f9a99b47fc460d422812b6a5adff7dfee951d8fa2e4a98caa0382cfbdbf

1)如果镜像具有多个标签,并且将标签作为删除参数,则命令仅删除标签;
2)如果镜像具有唯一标签,命令将删除标签,然后删除镜像;

删除被容器使用的镜像

如果镜像具有正在使用的容器,则无法删除,需要使用 -f 选项,将删除容器与镜像:

docker image rm --force "REPOSITORY:TAG"

删除所有镜像

如果要删除所有镜像可以使用如下命令(可以使用 docker images--filter 选项进行高级过滤):

# 下面的两个命令是等价的
docker image rm $(docker image ls -a -q)
docker rmi $(docker images -a -q)

# 删除有容器的镜像
docker image rm -f $(docker image ls -a -q)

删除 IMAGE ID 相同的所有镜像

当镜像具有多个标签时,如果使用 IMAGE ID 删除(docker rmi fd484f19954f),会产生如下错误:

Error: Conflict, cannot delete image fd484f19954f because it is tagged in multiple repositories, use -f to force 2013/12/11 05:47:16 Error: failed to remove one or more images

方法一、此时可以使用 -f 选项时,这将删除所有标签并删除镜像:

docker rmi --force fd484f19954f

方法二、使用命令 grep 进行过滤,将结果作为 docker rmi 参数以进行删除。

方法三、使用 docker inspect 命令,命令输出的 RepoTags 字段将显示相关标签,以用于删除。

常见错误处理

# image has dependent child images

Find the dependent child images on Docker

问题描述:
在删除某个镜像(docker rmi a990d6e2b083)的时候,提示如下错误:

Error response from daemon: conflict: unable to delete d86795370e7b (cannot be forced) - image has dependent child images

问题原因:
该错误提示删除的镜像有依赖的子镜像。

解决办法:

################################################################################
# 一个简单的做法
################################################################################
docker image inspect --format='{{.Id}} {{.Parent}}' \
    $(docker image ls --all --filter since=a990d6e2b083 -q) | grep a990d6e2b083

# 上述命令:
#1 (docker image ls)找到a990d6e2b083之后的镜像
#2 (docker image inspect)然后获取这些镜像的父镜像
#3 (grep)通过过滤父镜像,找到的就是引用该镜像的子镜像。

################################################################################
# 然而,问题从来就不是这么简单的
################################################################################
# 最大的问题在于:子镜像还有子镜像,慢慢找???
# 其实你要做的事情很简单。通常这个问题是由于有悬空镜像引用了该镜像,所以删除所有“悬空”的镜像即可。
# 「悬空镜像」可以放心的删除
docker rmi $(docker images --filter "dangling=true" -q --no-trunc)

################################################################################
# 但是,真正正确的做法是这样的
# 找到要删除镜像的子镜像的子镜像的子镜像…………(不多删,也不少删除)
# https://stackoverflow.com/questions/38118791/can-t-delete-docker-image-with-dependent-child-images/38119847#38119847#answer-53037893
################################################################################
recursive_remove_image() {
  for image in $(docker images --quiet --filter "since=${1}") # 找到这个镜像之后的镜像。因为子镜像是在这之后的。
  do
    if [ $(docker history --quiet ${image} | grep ${1}) ] # 查看这个子镜像的构建历史,是否包含了这镜像。如果是,那就应该删除。
    then
      recursive_remove_image "${image}" # 进行递归,删除应用这个镜像的子镜像。
    fi
  done
  # 执行删除
  echo "Removing: ${1}"
  docker rmi -f ${1}
}
recursive_remove_image "<image-id>"

参考文献

Find the dependent child images on Docker
docker image rm
docker rmi
docker images
Can’t delete image with children
Can’t delete docker image with dependent child images
How To Remove Docker Images, Containers, and Volumes
How to remove multiple docker images with the same imageID?