Docker registry仓库历史镜像批量清理

前言

在jenkins CI/CD流水线中以自动打包并push镜像的方式运行了一段时间之后,docker registry中堆积的历史镜像数量极多,磁盘空间告急,为此,有必要定期做镜像的清理,并释放镜像占用的存储空间

清除原理

Docker registry提供有restful api进行镜像管理,参考官方文档:
https://docs.docker.com/registry/spec/api/

Docker存储使用的aufs文件系统分层存储结构,将容器文件以读写分层的形式存储在宿主机中.在registry容器中,存放镜像的分层数据在宿主机上的挂载路径为:/var/lib/docker/volumes/{container_id}/_data/docker/registry/v2/blobs
关于docker aufs的存储模式,这篇文章写得非常通俗易懂,可以参考:
https://www.cnblogs.com/sammyliu/p/5931383.html

一图简介上层镜像生成及删除过程中的分层文件处理原理:
在这里插入图片描述
如图中文字解释,仅仅是调用api删除镜像是不够的,在删除了镜像之后,镜像的非共享分层文件还是会存放在磁盘中继续占用存储空间,因此,需要在删除镜像之后,使用docker registry自带的GC工具来进行垃圾分层(即无绑定镜像的分层)数据清除.

镜像分析

在了解以上前提后,开始排查哪些registry repo的历史镜像较多(分层数量多)
1.从宿主机进入docker registry容器内部,使用registry GC分析命令查看分层情况:

# --dry-run选项为layer层级分析,并不实际进行GC
registry garbage-collect --dry-run /etc/docker/registry/config.yml  

2.可以便捷使用以下命令对分层数较多的镜像做一个排序:

registry garbage-collect --dry-run /etc/docker/registry/config.yml  >> res.txt
6ac03183e197:~# cat res.txt | awk -F : '{print $1}' | sort | uniq -c | sort -rn -k1 | head -10 | grep -v "redis\|jdk\|php\|mysql\|nginx\|apache\|zk\|elastic"
 134161 zdtest
  56101 ordertest
  42691 bjdev
  35881 zhqtest
  13801 systemtest
   9601 zddev
   9361 bjtest
   7411 dsystemtest
    505 tooltest

可以看到,如上10个repo历史镜像数量大,需要清理

删除镜像

注意:

无论是delete方法调用restful接口,还是registry 自带工具的GC清理,都需要registry的配置文件中开启允许删除功能:
/etc/docker/registry/config.yml

storage:
  delete:
    enabled: true

由于数量较多,因此使用python多线程来调用registry restful api进行删除操作,脚本内容如下,可根据自己的场景修改registry url:

import requests
from concurrent.futures import ThreadPoolExecutor


class DockerHub(object):
    def __init__(self, hub, repos):
        self.hub = hub
        self.repos = repos

    @staticmethod
    def get_tag_list(hub, repo):
        # 获取这个repo的所有tags
        tag_list_url = '%s/v2/%s/tags/list' % (hub, repo)
        r1 = requests.get(url=tag_list_url)
        tag_list = r1.json().get('tags')
        return tag_list

    def main(self):
        thpool = ThreadPoolExecutor(10)
        for repo in self.repos:
            thpool.submit(self.delete_images, repo)

        thpool.shutdown(wait=True)

    def delete_images(self, repo):
        hub = self.hub
        tag_list = self.get_tag_list(hub=hub, repo=repo)
        num = 0
        try:
            # 保留最后两个版本的镜像
            for tag in tag_list[:-2]:
                # 获取image digest摘要信息
                get_info_url = '{}/v2/{}/manifests/{}'.format(hub, repo, tag)
                header = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"}
                r2 = requests.get(url=get_info_url, headers=header, timeout=10)
                digest = r2.headers.get('Docker-Content-Digest')

                # 删除镜像
                delete_url = '%s/v2/%s/manifests/%s' % (hub, repo, digest)
                r3 = requests.delete(url=delete_url)
                if r3.status_code == 202:
                    num += 1

        except Exception as e:
            print(str(e))

        print('仓库%s 共删除了%i个历史镜像' % (repo, num))


if __name__ == '__main__':
    hub = 'http://registry.xxx.com:5000'
    repos = ['zdtest', 'ordertest', 'bjdev', 'zhqtest', 'systemtest', 'zddev', 'bjtest', 'dsystemtest', 'tooltest']
    d = DockerHub(hub=hub, repos=repos)
    d.main()

运行结果:

仓库tooltest 共删除了17个历史镜像
仓库dsystemtest 共删除了245个历史镜像
仓库bjtest 共删除了310个历史镜像
仓库zddev 共删除了318个历史镜像
仓库systemtest 共删除了463个历史镜像
仓库zdtest 共删除了1574个历史镜像
仓库zhqtest 共删除了300个历史镜像
仓库bjdev 共删除了1421个历史镜像
仓库ordertest 共删除了1868个历史镜像

空间清理

回到docker registry容器内,直接运行GC命令,这次不再加 --dry-run选项

 registry garbage-collect /etc/docker/registry/config.yml

查看磁盘,可以发现磁盘容量已经空闲出许多了,镜像清理及存储空间释放完成!

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值