如何删除旧的和未使用的Docker镜像

1091

当Docker运行一段时间后,系统中会有很多镜像。我该如何安全地一次性删除所有未使用的Docker镜像以释放存储空间?

此外,我还想删除几个月前拉取的具有正确标签的镜像。

因此,我不仅要求删除未标记的镜像,还要寻找一种方法来删除通用的未使用镜像,包括未标记的镜像和几个月前拉取的具有正确标签的其他镜像。

32个回答

1894

(请见下面的原始答案)


2016年9月更新:Docker 1.13版本:PR 26108commit 86de7c0 引入了一些新命令,以帮助可视化Docker守护进程数据占用了多少磁盘空间,并允许轻松清理“不必要”的多余数据。 docker system prune 将删除所有未使用的数据(容器、网络和镜像)。您可以使用--volumes选项删除所有未使用的卷,并使用-a选项删除所有未使用的图像(不仅是悬空的)。
此外,您还有:

对于未使用的镜像,请使用docker image prune -a(用于删除悬空和未使用的镜像)。
警告:“未使用的”意味着“任何容器都没有引用的镜像”:在使用-a之前要小心。

A L回答所示,docker system prune --all将删除所有未使用的镜像,而不仅仅是悬空的镜像...这可能有点过头了。

docker xxx prune--filter选项结合使用可以是限制修剪(docker SDK API 1.28最低版本,因此需要docker 17.04+)的好方法。

当前支持的筛选器包括:

  • until (<timestamp>) - 只删除在给定时间戳之前创建的容器、镜像和网络
  • label (label=<key>, label=<key>=<value>, label!=<key>, 或 label!=<key>=<value>) - 只删除具有指定标签(或者在使用label!=...时不包含指定标签)的容器、镜像、网络和卷。

请参见 "清理镜像" 的示例。


警告:对于那些 docker xxx prune 命令,没有“预览”或“--dry-run”选项。

自2017年以来,这个要求已经在moby/moby问题30623中提出,但似乎难以实现(2022年8月)。

获取更具代表性的修剪概述将会非常复杂,原因有很多;
竞态条件(可以通过记录限制来解决);容器/镜像/卷/网络可能在使用“干运行”时没有被使用,但在实际修剪执行时可能正在使用(反之亦然),因此干运行将始终是对将要被修剪的内容的“近似”。
更困难的部分是由于对象(容器、镜像、网络等)如何相互依赖。例如,如果一个镜像不再有引用(没有标签,没有使用它的容器),则可以删除该镜像;这就是为什么docker系统修剪按特定顺序删除对象的原因(首先删除所有未使用的容器,然后删除未使用的镜像)。为了复制“干运行”的相同流程,需要临时构建所有对象及其引用的表示形式(基本上是复制所有引用计数器,然后从该“阴影”表示中删除引用)。
最后,随着集成containerd快照程序(图像和层存储)的工作进行,情况可能会更改;例如,现在可以使用多个架构的图像,并且(待讨论)“修剪”可以从图像中删除未使用的变体(架构)以清理空间,这为计算“可以删除什么”带来了另一个维度。

原始答案(2016年9月)

我通常会这样做:

docker rmi $(docker images --filter "dangling=true" -q --no-trunc)

我有一个[用于删除这些悬空图片的别名:drmi]13

dangling=true过滤器可以找到未使用的图像

这样,任何不再被标记图像引用的中间图像都将被删除。

我首先对已退出的进程(容器)执行相同的操作

alias drmae='docker rm $(docker ps -qa --no-trunc --filter "status=exited")'

haridsv评论中指出:

从技术上讲,你应该先清理容器再清理镜像,因为这样可以捕获更多的悬空镜像并减少错误


Jess Frazelle (jfrazelle)有一个bashrc函数:

dcleanup(){
    docker rm -v $(docker ps --filter status=exited -q 2>/dev/null) 2>/dev/null
    docker rmi $(docker images --filter dangling=true -q 2>/dev/null) 2>/dev/null
}

为了删除旧的镜像,而不仅仅是“未引用-悬空”镜像,您可以考虑使用docker-gc


一个简单的Docker容器和镜像垃圾收集脚本。
  • 超过一小时未运行的容器将被删除。
  • 在此之后,不属于任何剩余容器的镜像将被移除。

38
有关于"dangling=true"的说明文档吗? - CivFan
4
首先,docker system prune 不仅仅会移除镜像,请确保使用 docker image prune。而且要非常小心使用 -a 标志:docker system prune -a 可能会产生毁灭性的影响(也会删除卷)。最后,是的,-a 会移除未使用的镜像,我会编辑答案。 - VonC
3
“未使用”指的是“任何容器都没有引用的图像”,而“悬空”则表示根本没有标记(只有一个ID)。 - VonC
1
“--filter”文档中没有关于可用过滤器标签的信息,所以你很棒能够发现“dangling”是一个有效的过滤器标签。我需要能够按“镜像ID”进行过滤,但是我尝试的任何内容都是无效的过滤器标签。 - cowlinator
1
@garryp 并不是格式化驱动器,但至少删除 /var/lib/docker,就像我在这里提到的 https://dev59.com/EVgQ5IYBdhLWcg3wxGpP#42265926:不过请考虑答案中的警告。那个操作*真的会删除所有东西*。 - VonC
显示剩余28条评论

190

更新第二版(2017-07-08)

再次参考VonC,使用更新的system prune命令。不耐烦的人可以使用-f, --force选项跳过提示:

docker system prune -f

使用-a, --all选项,急躁和鲁莽的人可以进一步删除"不仅是悬空的图像,还有未使用的图像":

docker system prune -af

https://docs.docker.com/engine/reference/commandline/system_prune/

更新

请参阅VonC的答案,该答案使用了最近添加的prune命令。以下是相应的shell别名方便使用:

alias docker-clean=' \
  docker container prune -f ; \
  docker image prune -f ; \
  docker network prune -f ; \
  docker volume prune -f '

旧回答

删除已停止(退出)的容器:

$ docker ps --no-trunc -aqf "status=exited" | xargs docker rm

删除未使用的(悬空)图片:

$ docker images --no-trunc -aqf "dangling=true" | xargs docker rmi

如果您对不可撤销的数据丢失采取了极度谨慎的措施,那么您可以删除未使用(悬挂)卷(v1.9及更高版本):

$ docker volume ls -qf "dangling=true" | xargs docker volume rm

这里是一个方便的shell别名:

alias docker-clean=' \
  docker ps --no-trunc -aqf "status=exited" | xargs docker rm ; \
  docker images --no-trunc -aqf "dangling=true" | xargs docker rmi ; \
  docker volume ls -qf "dangling=true" | xargs docker volume rm'

参考文献


5
在清理容器卷的时候,我建议您要谨慎行事。无论是自动创建的容器卷还是未被使用的命名卷,都会与"挂起=true"一起列出。请注意不要误删。 - BMitch
1
@BMitch,你说得完全正确;我已经在“docker volume rm”配方中添加了一个严厉的警告。欢迎您提出任何建议。 - rubicks
1
我希望Docker能够为命名卷提供不同的过滤选项。如果我想到一个好的解决方法,我一定会分享的。 - BMitch
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - BMitch
1
@sudo,有时候宇宙会给你一个礼物。 :-) - rubicks
显示剩余6条评论

136
其他答案都很棒,特别是:
docker system prune # doesn't clean out old images
docker system prune --all # cleans out too much

但是我需要在这两个命令之间加入一些内容,所以我需要使用filter选项:

docker image prune --all --filter "until=4320h" # delete images older than 6 months ago; 4320h = 24 hour/day * 30 days/month * 6 months

参考文献:https://docs.docker.com/config/pruning/#prune-images

本文介绍如何使用Docker命令行界面中的docker image prune命令来清理未使用的镜像。该命令将删除所有没有被任何容器或其他镜像依赖的镜像。

这是一个可以提高系统性能和节省存储空间的重要步骤,因为无用的镜像可能会占据大量磁盘空间并影响Docker的速度和效率。


20
非常被低估的答案!能够使用截止日期进行修剪非常有用。 - Nik Reiman
3
我也使用这种语法来使它更易读,例如 --filter "until=$((30*24))h" 或者在这种情况下像 --filter "until=$((24*30*6))h" - Rodrigo
1
非常有用的选项,我以前不知道:filter让我感到非常开心!非常感谢你! - Raffi

70

为了删除一个月以上的旧标记图片:

$ docker images --no-trunc --format '{{.ID}} {{.CreatedSince}}' \
    | grep ' months' | awk '{ print $1 }' \
    | xargs --no-run-if-empty docker rmi

请注意,它将无法删除被容器使用、在存储库中引用、具有依赖子图像的图像...这可能是您想要的。否则只需添加-f标志。

/etc/cron.daily/docker-gc脚本示例:

#!/bin/sh -e

# Delete all stopped containers (including data-only containers).
docker ps -a -q --no-trunc --filter "status=exited" | xargs --no-run-if-empty docker rm -v

# Delete all tagged images more than a month old
# (will fail to remove images still used).
docker images --no-trunc --format '{{.ID}} {{.CreatedSince}}' | grep ' months' | awk '{ print $1 }' | xargs --no-run-if-empty docker rmi || true

# Delete all 'untagged/dangling' (<none>) images
# Those are used for Docker caching mechanism.
docker images -q --no-trunc --filter dangling=true | xargs --no-run-if-empty docker rmi

# Delete all dangling volumes.
docker volume ls -qf dangling=true | xargs --no-run-if-empty docker volume rm

3
对于删除旧的Docker镜像的命令,点赞+1。解决方案有些技巧性,但是非常原创并且完美地发挥了作用 :) - Rick
4
这很好,但我认为这只会删除至少4个月旧的Docker镜像。.CreatedSince在输出中使用以周为单位的时间,即使是很多周之前的镜像,例如“12周”。 - joelittlejohn
3
这个命令对我很有用,而且简单易行:docker images | grep ' months' | awk '{ print $3 }' | xargs --no-run-if-empty docker rmi -f - Kent Bull

46

根据文档,以下命令将删除48小时以上的镜像。

$ docker image prune --all --filter until=48h

2
使用过滤器也可以列出指定版本之前的所有版本:docker image ls --all --filter reference=monolito --filter before=monolito:0.1.8,然后应用rmi命令进行删除。docker rmi $(docker image ls -q --all --filter reference=monolito --filter before=monolito:0.1.8) - rodvlopes

38

假设你已经安装了Docker 1.13或更高版本,你可以直接使用清理命令。对于你特别提到的删除旧镜像这个问题,你需要使用第一个命令。

# Remove unused images
docker image prune

# Remove stopped containers.
docker container prune

# Remove unused volumes
docker volume prune

# Remove unused networks
docker network prune

# Command to run all prunes:
docker system prune

我建议不要习惯使用docker system prune命令。我认为用户会意外删除他们不打算删除的东西。个人而言,我主要会使用docker image prunedocker container prune命令。


5
你不想修剪未使用的网络,对吗? 比如,如果所有容器都已停止,并且我删除那些网络,如果我启动它们,它们将如何工作。网络是否会随着docker run一起创建? - Northstrider
@meffect 我完全同意,很好发现我漏掉了网络修剪。我已经加入了它,并在最后添加了一部分说明我不建议使用 docker system prune,而是单独修剪。 - Programster

20

直到现在(Docker版本1.12),我们使用以下命令来删除所有正在运行的容器。此外,如果我们想手动删除卷,则可以使用以下命令中的其相应标记 -v。

删除所有已退出的容器

docker rm $(docker ps -q -f status=exited)

删除所有已停止的容器

docker rm $(docker ps -a -q)

删除所有正在运行和已停止的容器

docker stop $(docker ps -a -q)
docker rm $(docker ps -a -q)

移除所有容器,不带任何条件

docker container rm $(docker container ps -aq)

但是在版本1.13及以上,为了完整的系统清理,我们可以直接使用以下命令:

docker system prune

所有未使用的容器、镜像、网络和卷都将被删除。我们还可以使用以下命令清理各个组件:

docker container prune
docker image prune
docker network prune
docker volume prune

18

这个方法对我有用:

docker rmi $(docker images | grep "^<none>" | awk "{print $3}")

13

最近我在我的一台服务器上编写了一个脚本来解决这个问题:

#!/bin/bash

# Remove all the dangling images
DANGLING_IMAGES=$(docker images -qf "dangling=true")
if [[ -n $DANGLING_IMAGES ]]; then
    docker rmi "$DANGLING_IMAGES"
fi

# Get all the images currently in use
USED_IMAGES=($( \
    docker ps -a --format '{{.Image}}' | \
    sort -u | \
    uniq | \
    awk -F ':' '$2{print $1":"$2}!$2{print $1":latest"}' \
))

# Get all the images currently available
ALL_IMAGES=($( \
    docker images --format '{{.Repository}}:{{.Tag}}' | \
    sort -u \
))

# Remove the unused images
for i in "${ALL_IMAGES[@]}"; do
    UNUSED=true
    for j in "${USED_IMAGES[@]}"; do
        if [[ "$i" == "$j" ]]; then
            UNUSED=false
        fi
    done
    if [[ "$UNUSED" == true ]]; then
        docker rmi "$i"
    fi
done

10
这里是一个清理Docker镜像并回收空间的脚本。
#!/bin/bash -x
## Removing stopped container
docker ps -a | grep Exited | awk '{print $1}' | xargs docker rm

## If you do not want to remove all container you can have filter for days and weeks old like below
#docker ps -a | grep Exited | grep "days ago" | awk '{print $1}' | xargs docker rm
#docker ps -a | grep Exited | grep "weeks ago" | awk '{print $1}' | xargs docker rm

## Removing Dangling images
## There are the layers images which are being created during building a Docker image. This is a great way to recover the spaces used by old and unused layers.

docker rmi $(docker images -f "dangling=true" -q)

## Removing images of perticular pattern For example
## Here I am removing images which has a SNAPSHOT with it.

docker rmi $(docker images | grep SNAPSHOT | awk '{print $3}')

## Removing weeks old images

docker images | grep "weeks ago" | awk '{print $3}' | xargs docker rmi

## Similarly you can remove days, months old images too.

原始脚本

https://github.com/vishalvsh1/docker-image-cleanup

通常情况下,Docker会将与镜像构建和层相关的所有临时文件保存在/var/lib/docker路径下。这个路径是本地系统的一个位置,通常位于根分区"/"

您可以挂载更大的磁盘空间,将/var/lib/docker的内容移动到新的挂载位置,并创建一个符号链接。

这样,即使Docker镜像占用空间,也不会影响您的系统,因为它将使用其他挂载位置。

原始发布:管理本地磁盘上的Docker镜像


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接