如何在缓存失效后删除已缓存/中间的Docker镜像?

25

我有一个CI流水线,每次运行流水线时都会构建我的应用程序的Docker镜像(并且流水线是通过代码推送到git存储库触发的)。

Docker镜像由多个中间层组成,这些层逐渐变得非常大。 大多数中间图像对每次运行而言都是相同的,因此Docker的缓存机制被充分利用。

然而,问题在于最终的两个层对于每次运行都是不同的,因为它们源于Dockerfile中的COPY语句,其中内置的应用程序工件被复制到镜像中。 由于每次运行都会修改工件,已经缓存的底部镜像将始终无效。 这些图像每个大小为800mb。

有什么Docker命令可以识别(和删除)被新图像替换的这些镜像,即当它们变得无效时?

我想让我的CI流水线在运行结束时将它们删除,以便它们不会悬挂在CI服务器上并浪费大量磁盘空间。

1个回答

26
如果我理解正确:每次代码推送时,CI流水线会创建新的映像,其中部署了应用程序的新版本。因此,以前创建的映像变得过时,所以您想要将其删除。要做到这一点,您必须:
  1. 摆脱所有过时的容器,这些容器是从过时的映像创建的
  • 使用命令docker ps -a显示所有容器
  • 如果仍在运行,请使用命令docker stop [containerID]停止过时的容器
  • 使用命令docker rm [containerID]删除它们
  1. 使用命令docker rmi [imageID]删除过时的映像

总之,为什么需要这个过程:您无法删除任何图片,直到它被任何现有容器使用(即使已停止的容器仍需要它们的图片)。因此,您应该首先停止和删除旧容器,然后再删除旧图片。

检测部分和删除进程的自动化应基于CI流水线生成的图像版本和容器名称。

编辑1

要列出与任何已标记的图像没有关系的所有图像,您可以使用命令:docker images -f dangling=true。您可以使用命令docker image purge删除它们。

这里要记住的一件事:如果构建一个没有标记的映像,则该映像将出现在“悬空”映像列表中。您可以通过提供标记来避免这种情况,从而构建它。

编辑2

图像清理的命令已更改。现在正确的命令是:

docker image prune

这里有一个带有文档的链接


感谢您的回复!这里的问题不在于存在使用图像的容器。事实上,管道成功地在运行结束时删除了所有容器(使用docker-compose down)。挑战在于识别哪些图像层已经从缓存中使用,哪些已经因新构建而失效。 - Omar Ilyas
例如,假设我有一张图片 myrepo.com/myapp:1。现在,这是使用包含多个docker命令的dockerfile构建的,因此每个命令都会产生一个中间图像。当我第二次构建相同的图像时,它将重用缓存中的所有未修改图像。在我的情况下,除了最底部的两个图像之外,所有图像都是如此。那么,我该如何确保管道从上一次运行中删除这两个图像呢? - Omar Ilyas
1
我认为这完美地回答了我的问题 :)关键在于:“没有与任何标记图像相关联”。但是为了确认: 如果我有图像X,Y和Z,其中Z基于Y,而Y基于X,并且仅图像Z被标记。然后出现了图像Y2和Z2,其中Y2基于X(缓存),Z2基于Y2,现在图像Z和Z2都被标记。所以:X -> Y -> Z* X -> Y2 -> Z2**已打标签当我运行“docker images purge”时,根据我的理解,唯一将被删除的图像是Y。这正确吗?如果是这样,那么这正是期望的行为。 - Omar Ilyas
非常感谢 :) 我应该彻底阅读关于“悬挂”图像的相关内容。 - Omar Ilyas
1
看起来现在我们应该使用 docker image prune 而不是 docker images purge - Dzianis
总结一下为什么需要这个过程:在任何现有的容器使用图像之前,您都不能删除它。 - Rafael

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