乐趣区

Docker镜像仓库清理的探索之路

用友云开发者中心是基于 Docker 容器进行微服务架构应用的落地与管理。相信各位同学在使用的过程中,会发现随着 Docker 镜像的增多,占用磁盘空间也约来越多。这时我们需要清理私有镜像仓库中不需要的镜像。但在实际操作时,才会发现这本以为很简单的任务中却暗藏玄机,遇到了不少的麻烦。在这里我们分享一下清理镜像仓库时遇到的坑点。想要直接寻求解决方案的同学可以直接看第二部分。一、那些年,我们在清理镜像仓库时走过的坑坑点 1:官方提供的接口并不能真正的删除镜像这着实是最大的坑点。很多同学查资料发现,官方已经提供了删除镜像仓库的 API,所以可能相当然的以为直接使用就好,殊不知掉入了官方埋下的最大的坑点,也是本文要着手解决的核心问题:官方提供的删除镜像仓库中镜像的接口,仅仅是把 manifest 删除了,真正的镜像文件还存在!官方并没有提供删除镜像层的接口!这也就是说,当我们调用删除镜像的接口之后,仅仅是查看镜像的列表时看不到原镜像了,然而原有镜像仍然在磁盘中,占用着宝贵的文件存储空间。坑点 2:直接调用官方的删除镜像 API,会返回 405 的错误码直接调用删除镜像的接口,可能会遇到以下错误提示:405,意味着方法不被允许。实际上,官方可能是处于安全性的考虑,在默认的情况下禁止了直接删除镜像的功能。若要开启删除镜像功能,需要修改镜像仓库的配置文件。具体操作为修改 /etc/docker/registry/config.yml 文件,在 storage 下添加 delete 的许可之后,重启镜像仓库服务。坑点 3:使用官方提供的 garbage-collect 工具,会有无用的文件残留官方为 registry 提供了 garbage-collect(gc)工具清理镜像的物理存储,将没有引用的 layer 删除。gc 的清理过程分为两部分:1)mark:扫描所有的 manifest,列出引用的 layer;2)sweep:扫描所有的 layer,不在 mark 里的 layer 将被清理删除。gc 可以在 dry-run 的模式下运行(添加参数 -d),只输出 gc 信息,不进行实际操作。我们可以通过这种方式来确认哪些镜像会被清除。使用 gc 工具清理镜像的一个问题就是文件清理得不够干净,无法清理已经没有 tag 的镜像目录,并且还残存少部分文件,从十 KB 到几十 KB 不等。久而久之,垃圾文件和目录的数量会越来越多。坑点 4:garbage-collect 不是事务操作,清理镜像时可能会产生误操作 gc 不是事务操作,当 gc 过程中刚好有 push 操作时,则可能会误删数据。一个可行的解决办法是手动更改镜像仓库的配置,暂时禁止镜像的 push 操作。在镜像仓库的配置文件中可以配置 read-only 模式。当启用 read-only 之后,再 push 镜像时会得到 405 的错误。gc 完成后取消 read-only 模式,再 push 镜像即可。坑点 5:使用 garbage-collect 工具后,必须重启镜像仓库才能正常使用如果不重启镜像仓库,则再次 push 该镜像时可能会得到 layer already exists 错误:其可能的原因是镜像被删除后,仓库的缓存中还存有已经删除的镜像信息,所以再次 push 会报层存在的错误。二、两种清理镜像仓库的方案方案一:使用官方 API + GC 使用官方提供的方法可以较为简便的清理镜像仓库。整个清理过程可能需要几百毫秒到几秒的时间。此操作有一定的危险性,因此清理镜像不宜过于频繁。官方在 git 上也有类似描述。点击查看:https://github.com/docker/doc… 具体操作过程如下:1、准备工作在配置中许可删除操作。修改镜像仓库的配置文件,一般在如下路径:/etc/docker/registry/config.yml 在 storage 下添加 delete 的许可之后,重启镜像仓库。用 docker 方式启动的镜像仓库也可以添加环境变量:REGISTRY_STORAGE_DELETE_ENABLED=true2、获取待删镜像的 digest 获取镜像 digest 的 API 为:GET /v2/<name>/manifests/<reference> 其中,name 是仓库名,reference 是标签,此时需要注意,调用时需要加上 header 内容:Accept:application/vnd.docker.distribution.manifest.v2+json 其中 Docker-Content-Digest 的值就是镜像的 digest3、调用官方的 HTTP API V2 删除镜像删除镜像的 API 为:DELETE /v2/<name>/manifests/<reference> 其中,name 是仓库名称,reference 是包含“sha256:”的 digest。4、调用 GC 清理镜像文件使用 gc 工具的方式为:bin/registry garbage-collect /etc/docker/registry/config.ymlgc 清理需要时间,如果在 gc 过程中刚好有 push 操作,可能会产生未知的问题,建议设置 read-only 模式之后再进行 gc,然后再改回来。5、重启 docker registry 注意,如果不重启会导致 push 相同镜像时产生 layer already exists 错误。方案二:使用第三方脚本在清理镜像仓库这件事上,业内已经有很多人进行过各种各样的尝试。本文挑选一种比较好的方式推荐使用。1、宿主机安装 delete-docker-registry-image 可参考此命令的安装和使用方式。参考链接:https://github.com/burnettk/d…2、执行 delete-docker-registry-image 命令可以删除某个仓库(sb)或者某个具体的镜像(如 alpine:3.2)如果删除某镜像后该仓库为空,可以用删除仓库的方式删除此空仓。该工具也提供了 dry-run 的方式,只输出待删除的信息不执行删除操作。在命令后加上——dry-run 即可。3、重启 docker registry 跟 gc 方式一样,删除镜像之后要重启 docker registry,不然还是会出现相同镜像 push 不成功的问题。以上就是本文推荐的两种清理镜像仓库的两种方案。第一种方案更多的使用了官方提供的工具,使用时相对更加安全,且无需额外安装其他内容。第二种方案使用了第三方工具或脚本,使用时更加灵活且简便,且清理的更加彻底。具体操作时可根据自己的需求选择方案。

退出移动版