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

另外,我还想删除几个月前拉的图片,这些图片有正确的TAG。

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


当前回答

假设你有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系统的prune命令。我认为用户会不小心删除他们不想删除的内容。就我个人而言,我将主要使用docker映像修剪和docker容器修剪命令。

其他回答

请参阅docker系统修剪的官方参考

Docker系统修剪将删除:

所有停止的集装箱 所有网络不被至少一个容器使用 所有悬挂的图像 所有构建缓存

Docker系统prune -a也会做同样的事情,但是除了删除所有悬浮图像之外,它还会更广泛地删除:

没有至少一个与之关联的容器的所有映像

什么是悬空图像?

Docker映像由多个层组成,当从Dockerfile生成整个容器映像时,这些层被包装在父“容器层”中。悬浮图像是与任何其他标记图像没有关系的层,因此在任何构建的新容器中都不会有任何用途。它们不再起作用,而是消耗磁盘空间。

例如,悬浮图像可以通过以下过程创建:

从Dockerfile中构建一个命名image my-image,不指定任何标签:

FROM ubuntu:latest
CMD ["echo", "Hello World"]

docker build -t my-image

docker images

REPOSITORY   TAG       IMAGE ID
my-image     latest    7ed6e7202eca   <--- created, not dangling
ubuntu       latest    825d55fb6340

更新Dockerfile:

FROM ubuntu:latest
CMD ["echo", "Hello, World!"]

使用以前的名称重新构建映像,不指定任何标记:

docker build -t my-image

docker images

REPOSITORY   TAG       IMAGE ID
my-image     latest    da6e74196f66   <--- replacement layer
<none>       <none>    7ed6e7202eca   <--- previous layer, now dangling
ubuntu       latest    825d55fb6340

构建创建了一个新的my-image层。正如我们所看到的,最初创建的层仍然在那里,但它的名称和标签被设置为<none>:<none>。这个层永远不可能与任何docker容器层相关联,这意味着它是“悬空的”。

没有至少一个关联容器的图像是什么?

未使用的映像意味着它没有被分配或在容器中使用。例如,docker ps -a将列出所有运行和停止的容器。这些容器使用的任何映像都是“已用映像”。

当运行docker系统prune -a时,它将删除未使用和悬挂的图像。与至少一个容器相关联的任何映像都不会受到影响。

我正在使用这个命令:

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周的所有映像。

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

参考(再次)VonC,使用更近期的系统修剪。不耐烦的人可以使用-f,——force选项跳过提示符:

docker system prune -f

没有耐心和鲁莽的人还可以使用-a,——all选项删除“未使用的图像,而不仅仅是悬垂的图像”:

docker system prune -af

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

更新

参考VonC的答案,它使用了最近添加的修剪命令。下面是对应的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 码头工人rm Docker images -f 码头工人rmi Docker v1.9.0版本说明 Docker卷ls Docker卷rm

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

运行docker-remove-dangling-images

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

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

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

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

/etc/cron.示例每日/ 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