背景
项目在持续部署过程中会push镜像到registry中,随着时间推移,registry中会保存大量镜像,造成磁盘空间不足,所以需要定期清理历史镜像,保证registry服务正常运行。
删除镜像流程
registry默认是不允许删除镜像的,需要修改/etc/docker/registry/config.yml配置文件来开启删除操作,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| version: 0.1 log: fields: service: registry storage: delete: enabled: true cache: blobdescriptor: inmemory filesystem: rootdirectory: /var/lib/registry http: addr: :5000 headers: X-Content-Type-Options: [nosniff] health: storagedriver: enabled: true interval: 10s threshold: 3
|
调用registry API删除镜像
1 2 3 4
| # 查询digest curl -I -H "Accept: application/vnd.docker.distribution.manifest.v2+json" localhost:5000/v2/nginx/manifests/latest # 根据digest删除镜像 curl -i -X DELETE localhost:5000/v2/nginx/manifests/sha256:89a42c3ba15f09a3fbe39856bddacdf9e94cd03df7403cad4fc105088e268fc9
|
registry容器内执行garbage-collect命令删除未被引用的layer
1
| registry garbage-collect /etc/docker/registry/config.yml
|
重启registry容器(不重启的话,会导致刚清理的同名同tag镜像无法push)
使用python脚本清理镜像(保留每个镜像的最新版本)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| import os import requests
class RegistryHandler(object): get_repos_url = '/v2/_catalog' get_tags_url = '/v2/{repo}/tags/list' get_digests_url = '/v2/{repo}/manifests/{tag}' delete_digest_url = '/v2/{repo}/manifests/{digest}'
def __init__(self, host): self.host = host
def get_repos(self): url = f'{self.host}{self.get_repos_url}' res = requests.get(url).json() return res['repositories']
def get_tags(self, repo): url = f'{self.host}{self.get_tags_url.format(repo=repo)}' res = requests.get(url).json() return res['tags']
def get_digest(self, repo, tag): headers = {"Accept": "application/vnd.docker.distribution.manifest.v2+json"} url = f'{self.host}{self.get_digests_url.format(repo=repo, tag=tag)}' resp = requests.get(url, headers=headers) return resp.headers['Docker-Content-Digest']
def delete_digest(self, repo, digest): url = f'{self.host}{self.delete_digest_url.format(repo=repo, digest=digest)}' requests.delete(url)
if __name__ == '__main__': rh = RegistryHandler('http://localhost:5000') repos = rh.get_repos() for repo in repos: tags = rh.get_tags(repo) if not tags: continue
delete_tags = sorted( filter(lambda tag: '.' in tag, tags), key=lambda tag: ''.join([f'{int(n):04d}' for n in tag.split('.')]) )[:-1] for tag in delete_tags: try: digest = rh.get_digest(repo, tag) rh.delete_digest(repo, digest) except Exception as e: print(f'{repo}:{tag} delete fail: {e}')
os.system("docker exec `docker ps | grep registry | awk '{print $1}'` registry garbage-collect /etc/docker/registry/config.yml") os.system("docker restart `docker ps | grep registry | awk '{print $1}'`")
|
配置定期清理
crontab配置如下:
1
| 0 0 * * * /usr/bin/python ~/registry_clear.py
|