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


762

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

另外,我还想删除几个月前拉出的具有正确图像TAG

因此,我并不是要仅删除未标记的图像。我正在寻找一种方法来删除一般未使用的图像,其中包括未标记的图像和其他图像,例如几个月前使用正确的拉出的图像TAG

Answers:


1402

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

docker system prune将删除所有悬空数据(即,顺序:容器停止,无容器的卷和无容器的映像)。甚至带有-a选项的未使用数据。

您还有:

对于未使用的图像,请使用docker image prune -a(用于删除悬空使用的图像)。
警告:“ 未使用 ”的意思是“任何容器都未引用图像”:使用之前请小心-a

AL答案所示docker system prune --all将删除所有未使用的图像,而不仅仅是悬空的图像,这可能有点过多。

docker xxx prune与该--filter选项结合使用可能是一种限制修剪的好方法(docker SDK API 1.28最低,因此docker 17.04+

当前支持的过滤器是:

  • until (<timestamp>) -仅删除在给定时间戳记之前创建的容器,图像和网络
  • labellabel=<key>label=<key>=<value>label!=<key>,或label!=<key>=<value>) -仅与除去容器,图像,网络,和卷(或没有,如果label!=...被使用)指定的标签。

有关示例,请参见“ 修剪图像 ”。


原始答案(2016年9月)

我通常这样做:

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

我有一个别名来删除那些[悬挂的图像] 13drmi

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

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

28
是否有"dangling=true"真正含义的文档?
CivFan 2015年

1
此脚本无法删除几个月前提取的某些图像
Quanlong

2
dcleanup太棒了!
Quanlong 2015年

4
@herm首先,docker system prune删除的不仅仅是图像。确保使用docker image prune代替。并非常小心-a:一个docker system prune -a可以有破坏性的影响(删除卷为好)。最后,是的,-a删除未使用的图像,我将编辑答案。
VonC

2
@stom:“未使用”的意思是“任何容器都未引用图像,但晃来晃去则意味着根本没有标签(只是一个ID)
。– VonC

124

更新第二个(2017-07-08):

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

docker system prune -f

不耐烦和鲁ck的用户还可以使用以下-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'

参考文献:


3
对于卷清理,我要格外小心。自动创建的容器卷和当前未使用的命名卷都与dangling = true一起列出。
BMitch

1
@BMitch,你是绝对正确的;我在docker volume rm配方中添加了严厉警告。我会欢迎您的任何建议。
rubicks

1
我希望docker为命名卷提供不同的过滤器选项。如果我想出一个好的解决方法,我一定会分享。
BMitch

2
是的,但是不幸的是,它没有使用简单的标志将命名卷与匿名容器卷分开。docker volume ls -qf dangling=true | egrep '^[a-z0-9]{64}$' | xargs --no-run-if-empty docker volume rm只要您从未使用类似于GUID的名称命名卷,我一直在使用的命令将一直有效。我可能会针对新的过滤器语法进行调整。
BMitch

1
删除未使用的(悬挂的)卷确实对我们有帮助!
凯恩

61

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

$ 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

2
+1对于删除旧docker映像的命令。这有点hacky,但是解决方案是原始的并且可以完美地工作:)
Rick

3
很好,但是我认为这只会删除至少4个月大的Docker映像。.CreatedSince即使在使用了几周的图像上,也使用周作为时间单位,例如12 weeks
joelittlejohn

2
这对我来说很简单又有效:docker images | grep ' months' | awk '{ print $3 }' | xargs --no-run-if-empty docker rmi -f
肯特·布尔

32

其他答案很好,特别是:

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


24

假设您具有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 pruneand docker container prune命令。


4
您不想修剪未使用的网络吗?例如,如果所有容器都已停止,并且我删除了这些网络,则启动它们后它们将如何工作。网络是否与docker run一起创建?
meffect

@meffect我完全同意,我发现我已经离开了网络,这很糟糕。我已经包括了这一点,并在最后添加了一部分,指出我不建议使用docker system prune单个梅子。
Programster

15

到目前为止(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


13

以下命令将删除48小时之前的图像。

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

1
也可以使用过滤器在指定版本之前列出每个版本: 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

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 ':' '$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

8

这是一个清理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映像


6

我正在使用以下命令:

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周的图像。


我想你交换IMAGE_CTIME,并BEFORE_DATETIME在该echo命令
尤杜摹

5

如果要删除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

1
这是不正确的。这会删除3个月前创建的图像,而不是3个月前提取的图像(如果从远程来源提取它们,它们可能已经3个月了)。
安德鲁·费里尔

这帮助我根据不同的标准创建了更多过滤器
david.sansay


3

docker system prune -a

(将要求您确认命令。-f如果您知道自己在做什么,则使用它来强制运行。)


5
这很危险,请参阅有关使用docker system prune删除甚至命名卷的其他注释-a
RichVel

3

@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 containerdocker kill $(docker ps -q)在第3行之前添加到地址
Vincent

为什么不使用$(docker images -q)代替$(docker images | awk '/<none>/ { print $3 }')
SeF

1
@SeF:如果我docker images -q得到图像ID的向量,别无其他。如果我做我能做的事情,我会得到更多-让我<none>像在这里一样继续进行过滤。说得通?
Dirk Eddelbuettel

2

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

#!/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

2

几周前取出旧容器。

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

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

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


2

如何删除标记的图像

  1. docker rmi标签首先

  2. docker rmi图片。

    #可以在一个docker rmi调用中完成,例如:#docker rmi <repo:tag> <imageid>

(这适用于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


1
docker rm `docker ps -aq`

要么

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

3
我认为这个答案很危险,因为这些命令会删除容器。首先,OP正在询问如何删除图像,而不是容器。更重要的是,由于人们可能在退出的容器中拥有一些有价值的数据,这些命令可能会导致数据丢失。
u.unver34 '17

您应该描述在生产服务器上应用这些命令的潜在有害结果。
丹尼尔(Daniel)

这将删除容器,而不是图像。
SeF

1

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

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

  1. 停止docker:systemctl停止docker
  2. 分配了一个新的驱动器,例如/ mnt / docker。
  3. 将/ var / lib / docker中的所有文件移动到/ mnt / docker中。我使用了以下命令:rsync -aPHSx --remove-source-files / var / lib / docker / / mnt / docker /
  4. 将新驱动器安装到/ var / lib / docker。

此时,我不再有磁盘已满错误,但是我仍在浪费大量空间。下一步就是解决这个问题。

  1. 启动Docker:systemctl启动docker

  2. 保存所有图像:docker save $(docker images | sed -e'/ ^ / d'-e'/ ^ REPOSITORY / d'-e's,[] [] ,:,'-e's,[ ]。 ,,')> /root/docker.img

  3. 卸载docker。

  4. 擦除/ var / lib / docker中的所有内容:rm -rf / var / lib / docker / [cdintv] *

  5. 重新安装docker

  6. 启用docker:systemctl启用docker

  7. 启动docker:systemctl启动docker

  8. 恢复映像:docker load </root/docker.img

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

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

我不建议将其日常使用。但当docker失去对软件错误或意外重启的使用磁盘空间的跟踪时,运行该命令很有用。


1

如果您希望自动/定期清理已退出的容器并删除正在运行的容器未使用的映像和卷,则可以下载映像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


1

如果您自己(从其他一些较旧的基础映像中)构建这些修剪的映像,请谨慎使用上述基于的解决方案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


0

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

docker rmi -f <Image>

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.