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

Posted

技术标签:

【中文标题】如何删除旧的和未使用的 Docker 镜像【英文标题】:How to remove old and unused Docker images 【发布时间】:2015-12-19 19:11:14 【问题描述】:

长期运行 Docker 时,系统中有很多镜像。如何安全地一次删除所有未使用的 Docker 映像以释放存储空间?

另外,我还想删除几个月前拉取的图片,其中有正确的TAG

所以,我不是要求只删除未标记的图像。我正在寻找一种方法来删除一般未使用的图像,其中包括未标记的图像和其他图像,例如几个月前使用正确的TAG 提取的图像。

【问题讨论】:

【参考方案1】:

2016 年 9 月更新:Docker 1.13:PR 26108 和 commit 86de7c0 引入了一些新命令,以帮助可视化 docker 守护程序数据在磁盘上占用了多少空间,并允许轻松清理“不需要”的多余空间。

docker system prune 将删除所有悬空数据(即按顺序:容器停止、没有容器的卷和没有容器的图像)。即使是未使用的数据,也可以使用 -a 选项。

你还有:

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

对于未使用图像,使用docker image prune -a(用于删除悬空未使用图像)。 警告:'unused' 表示“没有被任何容器引用的图像”:在使用 -a 之前要小心。

如A L 的answer 所示,docker system prune --all 将删除所有未使用 图像,而不仅仅是悬空的图像......这可能有点太多了。

docker xxx prune--filter option 结合是限制修剪的好方法 (docker SDK API 1.28 minimum, so docker 17.04+)

目前支持的过滤器有:

until (<timestamp>) - 仅删除在给定时间戳之前创建的容器、图像和网络 labellabel=<key>label=<key>=<value>label!=<key>label!=<key>=<value>) - 仅删除带有(或的容器、图像、网络和卷,以防label!=... 是使用)指定的标签。

请参阅“Prune images”作为示例。

原始答案(2016 年 9 月)

我通常这样做:

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

我有一个[删除那些dangling images的别名:drmi]13

dangling=true 过滤器查找未使用的图像

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

首先对exited processes (containers)做同样的事情

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

正如haridsv 指出的in the comments:

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


Jess Frazelle (jfrazelle) 有bashrc function:

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 容器和镜像垃圾回收脚本。

一个多小时前退出的容器将被移除。 删除后不属于任何剩余容器的图像。

【讨论】:

是否有关于 "dangling=true" 真正含义的文档? 此脚本无法删除几个月前提取的一些图像 dcleanup 太棒了! @herm 首先,docker system prune 删除的不仅仅是图像。请务必改用docker image prune。对于-a,请非常小心docker system prune -a 可能会产生破坏性影响(也可以删除卷)。最后,是的,-a 删除了未使用的图像,我将编辑答案。 @stom : 'unused' 表示“图像未被任何容器引用,但 dangling 表示根本没有标记(只是一个 id)。【参考方案2】:

更新第二个(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's answer,它使用了最近添加的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'

参考文献

docker ps -f docker rm docker images -f docker rmi Docker v1.9.0 release notes docker volume ls docker volume rm

【讨论】:

我会谨慎使用卷清理。自动创建的容器卷和当前未使用的命名卷都与 dangling=true 一起列出。 @BMitch,你是绝对正确的;我在docker volume rm 配方中添加了一个严厉的警告。我会欢迎你的任何建议。 我希望 docker 为命名卷提供不同的过滤器选项。如果我想出一个好的解决方法,我一定会分享。 是的,但不幸的是,它不会使用简单的标志将命名卷与匿名容器卷分开。我一直在使用的命令是docker volume ls -qf dangling=true | egrep '^[a-z0-9]64$' | xargs --no-run-if-empty docker volume rm,只要您从不使用类似于 guid 的名称命名您的卷,它就可以工作。我可能会针对新的过滤器语法进行调整。 删除未使用的(悬空)卷对我们很有帮助!【参考方案3】:

其他答案很好,特别是:

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

【讨论】:

非常被低估的答案!能够使用截止日期进行修剪非常有用。【参考方案4】:

要删除超过一个月的旧标记图像:

$ 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

【讨论】:

+1 用于删除旧 docker 镜像的命令。这有点老套,但解决方案是原创的,而且效果很好:) 这很好,但我认为这只会删除至少 4 个月 大的 docker 镜像。 .CreatedSince 使用周作为输出中的时间单位,即使在很多周前的图像上也是如此,例如12 weeks. 这对我有用,简单又好用:docker images | grep ' months' | awk ' print $3 ' | xargs --no-run-if-empty docker rmi -f【参考方案5】:

根据doc,下面的命令会删除超过48小时的图片。

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

【讨论】:

使用过滤器也可以列出指定版本之前的每个版本: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)【参考方案6】:

假设您拥有Docker 1.13 或更高版本,您可以使用 prune 命令。对于您专门针对删除旧图像的问题,您需要第一个。

# 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 命令。

【讨论】:

您不想修剪未使用的网络吗?比如,如果所有容器都停止了,并且我删除了这些网络,那么如果我启动它们,它们的容器将如何工作。网络是与 docker run 一起创建的吗? @meffect 我完全同意,我已经离开网络修剪了。我已将其包括在内,并在最后添加了一部分,说明我不建议使用docker system prune,但建议使用单个修剪。【参考方案7】:

直到现在(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

【讨论】:

【参考方案8】:

这对我有用:

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

【讨论】:

【参考方案9】:

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

#!/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 ':' '$2print $1":"$2!$2print $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 镜像占用空间,也不会影响您的系统,因为它会使用其他挂载位置。

原帖: Manage Docker images on local disk

【讨论】:

【参考方案11】:

我正在使用这个命令:

export BEFORE_DATETIME=$(date --date='10 weeks ago' +"%Y-%m-%dT%H:%M:%S.%NZ")
docker images -q | while read IMAGE_ID; do
    export IMAGE_CTIME=$(docker inspect --format='.Created' --type=image $IMAGE_ID)
    if [[ "$BEFORE_DATETIME" > "$IMAGE_CTIME" ]]; then
        echo "Removing $IMAGE_ID, $BEFORE_DATETIME is earlier then $IMAGE_CTIME"
        docker rmi -f $IMAGE_ID;
    fi;
done

这将删除所有创建时间超过 10 周的图像。

【讨论】:

我认为你在 echo 命令中交换了 IMAGE_CTIMEBEFORE_DATETIME【参考方案12】:

如果您想删除 X 个月前提取的图像,您可以尝试以下示例,该示例删除三个月前创建的图像:

three_months_old_images=`docker images | grep -vi "<none>" | tr -s ' ' | cut -d" " -f3,4,5,6 | grep "3 months ago" | cut -d" " -f1`
docker rmi $three_months_old_images

【讨论】:

这是不正确的。这会删除 3 个月前创建的图像,而不是 3 个月前拉取的图像(如果您从远程来源拉取它们,它们可能已经 3 个月大了)。 这帮助我根据不同的标准创建了更多过滤器【参考方案13】:

同时修剪所有图像和卷docker system prune -af --volumes

【讨论】:

【参考方案14】:

docker system prune -a

(系统会要求您确认命令。如果您知道自己在做什么,请使用-f 强制运行。)

【讨论】:

这很危险,请参阅其他有关 docker system prune 删除带有 -a 的命名卷的 cmets。【参考方案15】:

@VonC 已经给出了一个非常好的答案,但为了完整起见,这里是我一直在使用的一个小脚本——如果你有一些差事 Docker 进程,它也会破坏任何差事:

#!/bin/bash

imgs=$(docker images | awk '/<none>/  print $3 ')
if [ "$imgs" != "" ]; then
   echo docker rmi $imgs
   docker rmi $imgs
else
   echo "No images to remove"
fi

procs=$(docker ps -a -q --no-trunc)
if [ "$procs" != "" ]; then
   echo docker rm $procs
   docker rm $procs
else
   echo "No processes to purge"
fi

【讨论】:

效果很好,但仍然可以获得Error response from daemon: You cannot remove a running container。在第 3 行之前添加docker kill $(docker ps -q) 地址 为什么不用$(docker images -q) 而不是$(docker images | awk '/&lt;none&gt;/ print $3 ') @SeF:如果我这样做docker images -q,我会得到一个图像 id 的向量,仅此而已。如果我做我所做的,我会得到更多——允许我像在这里一样过滤&lt;none&gt;。有意义吗?【参考方案16】:

要删除没有容器运行的标记图像,您必须使用一个小脚本:

#!/bin/bash

# remove not running containers
docker rm $(docker ps -f "status=exited" -q)

declare -A used_images

# collect images which has running container
for image in $(docker ps | awk 'NR>1 print $2;'); do
    id=$(docker inspect --format=".Id" $image);
    used_images[$id]=$image;
done

# loop over images, delete those without a container
for id in $(docker images --no-trunc -q); do
    if [ -z $used_images[$id] ]; then
        echo "images is NOT in use: $id"
        docker rmi $id
    else
        echo "images is in use:     $used_images[$id]"
    fi
done

【讨论】:

【参考方案17】:

几周前移除旧容器。

docker rm $(docker ps -a | grep "weeks" | awk ' print $1; ')

删除几周前的旧图片。当心。这将删除几周前创建但您的新图像可能正在使用的基本图像。

docker rmi $(docker images | grep 'weeks' | awk ' print $3; ')

【讨论】:

【参考方案18】:

如何删除标记的图像

    docker rmi 先标记

    docker rmi 镜像。

    # 可以在一个 docker rmi 调用中完成,例如:# docker rmi

(2016 年 11 月有效,Docker 版本 1.12.2)

例如

$ docker images 
REPOSITORY              TAG                 IMAGE ID            CREATED             SIZE
usrxx/the-application   16112805            011fd5bf45a2        12 hours ago        5.753 GB
usryy/the-application   vx.xx.xx            5af809583b9c        3 days ago          5.743 GB
usrzz/the-application   vx.xx.xx            eef00ce9b81f        10 days ago         5.747 GB
usrAA/the-application   vx.xx.xx            422ba91c71bb        3 weeks ago         5.722 GB
usrBB/the-application   v1.00.18            a877aec95006        3 months ago        5.589 GB

$ docker rmi usrxx/the-application:16112805 && docker rmi 011fd5bf45a2
$ docker rmi usryy/the-application:vx.xx.xx && docker rmi 5af809583b9c
$ docker rmi usrzz/the-application:vx.xx.xx eef00ce9b81f
$ docker rmi usrAA/the-application:vx.xx.xx 422ba91c71bb
$ docker rmi usrBB/the-application:v1.00.18 a877aec95006

例如脚本删除任何超过 2 周的内容。

IMAGESINFO=$(docker images --no-trunc --format '.ID .Repository .Tag .CreatedSince' |grep -E " (weeks|months|years)")
TAGS=$(echo "$IMAGESINFO" | awk ' print $2 ":" $3 ' )
IDS=$(echo "$IMAGESINFO" | awk ' print $1 ' )
echo remove old images TAGS=$TAGS IDS=$IDS
for t in $TAGS; do docker rmi $t; done
for i in $IDS; do docker rmi $i; done

【讨论】:

【参考方案19】:
docker rm $(docker ps -faq)
docker rmi $(docker ps -faq)

-f 力

-全部

-q 在模式中

【讨论】:

【参考方案20】:

有时我会遇到 Docker 分配并继续使用磁盘空间的问题,即使该空间未分配给任何特定映像或现有容器。我意外生成此问题的最新方法是在 RHEL 7.1 中使用“docker-engine”centos build 而不是“docker”。似乎发生的情况是有时容器清理未成功完成,然后空间从未被重用。当我分配为 / 的 80GB 驱动器被 /var/lib/docker 文件填满时,我必须想出一个创造性的方法来解决这个问题。

这是我想出的。首先解决磁盘已满错误:

    停止泊坞窗:systemctl stop docker

    分配了一个新的驱动器,例如/mnt/docker

    /var/lib/docker 中的所有文件移动到 /mnt/docker 。我使用了命令:

    rsync -aPHSx --remove-source-files /var/lib/docker/ /mnt/docker/
    

    将新驱动器安装到/var/lib/docker

此时我不再遇到磁盘已满错误,但我仍在浪费大量空间。接下来的步骤是解决这个问题。

    启动 Docker:systemctl start docker

    保存所有图片:

    docker save $(docker images |sed -e '/^<none>/d' -e '/^REPOSITORY/d' -e 's,[ ][ ]*,:,' -e 's,[ ].*,,') > /root/docker.img
    

    卸载 docker。

    擦除/var/lib/docker中的所有内容:

    rm -rf /var/lib/docker/[cdintv]*
    

    重新安装docker

    启用泊坞窗:systemctl enable docker

    启动泊坞窗:systemctl start docker

    恢复图片:

    docker load < /root/docker.img
    

    启动您需要运行的任何持久性容器。

这将我的磁盘使用量从 docker 的 67 GB 降低到了 docker 的 6 GB。

我不建议将其用于日常使用。但是当 docker 似乎丢失了对软件错误或意外重启的已用磁盘空间的跟踪时,运行它很有用。

【讨论】:

你不是忘了提卸载/mnt/docker吗?【参考方案21】:
docker rm `docker ps -aq`

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

【讨论】:

我认为这个答案很危险,因为这些命令会删除容器。首先,OP 询问如何删除图像,而不是容器。更重要的是,这些命令可能会导致数据丢失,因为人们可能在退出的容器中有一些有价值的数据。 您应该描述在生产服务器上应用这些命令可能产生的有害结果。 这会删除容器,而不是图像。【参考方案22】:

如果您希望自动/定期清理退出的容器并删除正在运行的容器未使用的映像和卷,您可以下载映像 meltwater/docker-cleanup

只要运行:

docker run -d -v /var/run/docker.sock:/var/run/docker.sock:rw  -v /var/lib/docker:/var/lib/docker:rw --restart=unless-stopped meltwater/docker-cleanup:latest

默认情况下每 30 分钟运行一次。但是,您可以使用此标志以秒为单位设置延迟时间(DELAY_TIME=1800 选项)。

更多详情:https://github.com/meltwater/docker-cleanup/blob/master/README.md

【讨论】:

【参考方案23】:

首先,运行docker images 以查看图像列表并将IMAGE HASH ID 复制到剪贴板。

运行docker rmi -f &lt;Image&gt;

记住选项-f 是强制删除。

【讨论】:

【参考方案24】:

如果您自己构建这些修剪过的镜像(来自其他一些较旧的基础镜像),请注意上面基于docker image prune 接受的解决方案,因为该命令很生硬,并且还会尝试删除您最新所需的所有依赖项图像(该命令可能应该重命名为docker image*s* prune)。

我为我的 docker 映像构建管道(其中有每日构建并且标签=日期采用 YYYYMMDD 格式)提出的解决方案是这样的:

# carefully narrow down the image to be deleted (to avoid removing useful static stuff like base images)
my_deleted_image=mirekphd/ml-cpu-py37-vsc-cust

# define the monitored image (tested for obsolescence), which will be usually the same as deleted one, unless deleting some very infrequently built image which requires a separate "clock"
monitored_image=mirekphd/ml-cache

# calculate the oldest acceptable tag (date)
date_week_ago=$(date -d "last week" '+%Y%m%d')

# get the IDs of obsolete tags of our deleted image
# note we use monitored_image to test for obsolescence
my_deleted_image_obsolete_tag_ids=$(docker images --filter="before=$monitored_image:$date_week_ago" | grep $my_deleted_image | awk 'print $3')

# remove the obsolete tags of the deleted image
# (note it typically has to be forced using -f switch)
docker rmi -f $my_deleted_image_obsolete_tag_ids

【讨论】:

【参考方案25】:

有 sparrow 插件docker-remove-dangling-images 可以用来清理停止的容器和未使用的(悬空)图像:

$ sparrow plg run docker-remove-dangling-images

它适用于 Linux 和 Windows 操作系统。

【讨论】:

【参考方案26】:

如果您有很多,删除它们可能真的很乏味,但幸运的是,Docker 有一些命令可以帮助我们消除悬空图像。在旧版本的 Docker 中(今天仍然有效),您可以通过运行 docker rmi -f $(docker images -f "dangling=true" -q) 自行删除悬空图像。

【讨论】:

【参考方案27】:

我通常使用docker rm -f $(docker ps -a -q)docker system prune 清除所有悬空的容器。

【讨论】:

以上是关于如何删除旧的和未使用的 Docker 镜像的主要内容,如果未能解决你的问题,请参考以下文章

Docker:如何删除所有本地 Docker 镜像

如何删除docker images下的镜像

如何删除运行的docker镜像

docker镜像删除还是历史版本

docker常用操作

如何通过命令行从docker hub删除docker镜像?