1. 程式人生 > >Docker registry倉庫歷史映象批量清理

Docker registry倉庫歷史映象批量清理

前言

Docker registry在以jenkins CI/CD流水線自動打包並push映象的方式運行了一段時間之後,堆積的歷史映象數量極多,磁碟空間告急,為此,有必要定期做映象的清理,並釋放映象佔用的儲存空間

清除原理

Docker儲存使用的aufs檔案系統分層儲存結構,將容器檔案以讀寫分層的形式儲存在宿主機中,在宿主機存放的分層資料路徑為:/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分析命令檢視分層情況:

registry garbage-collect --dry-run /etc/docker/registry/config.yml  # --dry-run選項為layer層級分析,並不實際進行GC

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
 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 Docker(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.youkeshu.com:5000'
    repos = ['zdtest', 'ordertest', 'bjdev', 'zhqtest', 'systemtest', 'zddev', 'bjtest', 'dsystemtest', 'tooltest']
    d = Docker(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

檢視磁碟,可以發現磁碟容量已經空閒出許多了,映象清理及儲存空間釋放完成!