python清理docker-harbor的多余镜像
# coding: utf-8 from operator import itemgetter
from urllib import parse
import requests import datetime as dt
# import maya import logging
logging.basicConfig(filename='harbor_clean.txt', filemode="w", level=logging.INFO) logger = logging.getLogger(__name__) """
清理 Harbor 仓库的老镜像
""" class HarborCleaner(object):
delete_status = {
200: "Delete tag successfully.",
400: "Invalid repo_name.",
401: "Unauthorized.",
403: "Forbidden.",
404: "Repository or tag not found.",
} def __init__(self, user: str, password: str, hostname: str, port: int, use_https=True):
scheme = "https" if use_https else "http"
api_base = f"{scheme}://{hostname}:{port}/api"
self.search_api = api_base + "/search?q={key_word}"
self.projects_api = api_base + "/projects"
self.repository_query_api = api_base + "/repositories?project_id={project_id}"
# repo_name 一般为 "project_name/repo_name" 格式,必须做转义处理(因为中间有斜杠)
self.repository_tags_api = api_base + "/repositories/{repo_name}/tags"
self.repository_tag_api = self.repository_tags_api + "/{tag}" self.session = requests.Session()
self.session.verify = False # 如果公司是使用自签名证书,不能通过 SSL 验证,就需要设置这个
self.session.headers = {
"Accept": "application/json"
} self.session.auth = (user, password) def get_all_projects(self):
resp = self.session.get(self.projects_api) success = resp.status_code == 200
return {
"success": success,
"data": resp.json() if success else resp.text
} def get_all_repos(self, project: dict):
url = self.repository_query_api.format(project_id=project['project_id'])
resp = self.session.get(url) success = resp.status_code == 200
return {
"success": success,
"data": resp.json() if success else resp.text
} def get_all_tags(self, repo: dict):
"""repo_name 需要做转义"""
repo_name = parse.quote(repo['name'], safe="")
url = self.repository_tags_api.format(repo_name=repo_name)
resp = self.session.get(url) success = resp.status_code == 200
return {
"success": success,
"data": resp.json() if success else resp.text
} def get_tags_except_lastest_n(self, repo: dict, n: int):
"""获取除了最新的 n 个 tag 之外的所有 tags""" # 如果 镜像 tags 数小于 n+1,说明该镜像很干净,不需要做清理。
if repo['tags_count'] <= n+1: # +1 是因为 latest 是重复的 tag
return [] result = self.get_all_tags(repo)
tags: list = result['data']
for tag in tags:
# tag['time'] = maya.MayaDT.from_iso8601(tag['created']) # '2019-04-09T11:33:49.296960745Z'
# # python 自带的解析函数,只能处理 6 位小数,下面截去多余的三位
timestamp = tag['created'][:-4] + 'Z'
tag['time'] = dt.datetime.strptime(timestamp, r'%Y-%m-%dT%H:%M:%S.%fZ') tags.sort(key=itemgetter('time')) # 使用 time 键进行原地排序
return tags[:-n-1] # expect the latest n tags, -1 是因为 latest 是重复的 tag def soft_delete_tag(self, repo: dict, tag: dict):
"""repo_name 需要做转义
这里删除后,还需要进行一次 GC,才能真正地清理出可用空间。
"""
repo_name = parse.quote(repo['name'], safe="")
url = self.repository_tag_api.format(repo_name=repo_name, tag=tag['name'])
resp = self.session.delete(url) return {
"success": resp.status_code == 200,
"message": self.delete_status.get(resp.status_code)
} def soft_delete_all_tags_except_latest_n(self, n):
"""从每个仓库中,删除所有的 tags,只有最新的 n 个 tag 外的所有 tags 除外"""
res_projects = self.get_all_projects()
if not res_projects['success']:
logger.warning("faild to get all projects, message: {}".format(res_projects['data'])) logger.info("we have {} projects".format(len(res_projects['data'])))
for p in res_projects['data']:
res_repos = self.get_all_repos(p)
if not res_projects['success']:
logger.warning("faild to get all repos in project: {}, message: {}".format(p['name'], res_repos['data'])) logger.info("we have {} repos in project:{}".format(len(res_repos['data']), p['name']))
for repo in res_repos['data']:
logger.info("deal with repo: {}".format(repo['name'])) old_tags = self.get_tags_except_lastest_n(repo, n)
logger.info("we have {} tags to delete in repo: {}".format(len(old_tags), repo['name']))
for tag in old_tags:
logger.info("try to delete repo:{}, tag: {}, create_time: {}".format(repo['name'], tag['name'], tag['created']))
result = self.soft_delete_tag(repo, tag)
if result['success']:
logger.info("success delete it.")
else:
logger.warning("delete failed!, message: {}".format(result['message'])) if __name__ == "__main__":
# 1. 通过 harbor 的 restful api 进行软删除
harbor_cleaner = HarborCleaner(
user="admin",
password="Admin123",
hostname="reg.harbor.com",
port=8321
)
harbor_cleaner.soft_delete_all_tags_except_latest_n(10) # 每个镜像只保留最新的十个 tag # 2. 进行一次 GC,清除掉所有已软删除的 images
# 2.1 harbor 1.7 之前的版本,需要停机才能 GC """
cd /volume1/docker/harbor/harbor
docker-compose stop # 停机
# 下面的 tag 'v2.6.2-v1.4.0' 需要换成当前使用的 registry-photon 镜像的版本号
# --dry-run 表示尝试进行 GC,输出 log 与正式 gc 一致,可用于提前发现问题
docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.4.0 garbage-collect --dry-run /etc/registry/config.yml
# 正式 gc,这个才会真正的 gc 掉已经软删除的镜像
docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.4.0 garbage-collect /etc/registry/config.yml
""" # 2.2 harbor 1.7+ 可以通过 restful api 进行在线 GC 或定期自动 GC。
Harbor删除镜像后且GC清理后,磁盘空间没有释放的问题
1、原因 Harbor删除镜像后且GC清理后,磁盘空间没有释放。因为我们push大量相同标签的镜像,Docker 镜像由标签引用,并由唯一的摘要标识。这意味着如果myImage使用标记推送两个图像,在DR内部他们显示的不同,它们将由两个不同的digests标识。最后推送的Images是当前的。Docker 镜像由layers组成,每个layers都关联一个blob。该blob是最占用存储的文件; 这些文件将由GC清理。正由上面的描述每个镜像都会存储一个引用,因为,我们重复提交10次,那一个标签在DR中会有10个引用,标签只能获取tag。而其他9个只能用digest获取了。 简单的来说就是因为相同的标签的镜像重复提交次数过多导致。
2、解决方法
1、编辑 common/config/registry/config.yml文件 此文件在harbor安装目录下,关闭的目的是为了禁止身份验证 2、修改 docker-compose.yml 文件 此文件在harbor安装目录下,修改此文件的目的是把registry port端口暴露出来,添加红框出的配置,注意格式。 3、重新配置harbor,使其配置生效
执行下面的命令
docker-compose down
docker-compose up -d 4、 清理已删除未使用的清单
执行下面的命令
docker run --network="host" -it -v /data/registry:/registry -e REGISTRY_URL=http://127.0.0.1:5000 mortensrasmussen/docker-registry-manifest-cleanup
5、清理以删除现在不再与清单关联的blob
查看哪些镜像会删除: --dry-run 参数
docker run -it --name gc --rm --volumes-from registry vmware/registry:2.6.-photon garbage-collect --dry-run /etc/registry/config.yml
删除执行下面的命令
docker run -it --name gc --rm --volumes-from registry vmware/registry-photon:v2.6.2-v1.4.0 garbage-collect /etc/registry/config.yml
6、把步骤1和步骤2的配置修改回初始状态,并重启harbor。
python清理docker-harbor的多余镜像的更多相关文章
- [Docker]Harbor部署私有镜像仓库
Harbor部署私有镜像仓库 认识: Harbor 是一个用于存储和分发 Docker 镜像的企业级 Registry 服务器. 部署环境: CentOS7 Python2.7.5 Docker CE ...
- docker harbor 清理释放存储空间
0.harbor界面端清理镜像 1.停止docker harbor docker-compose stop 2.预览运行效果 docker run -it --name gc --rm --volum ...
- 搭建docker镜像仓库(二):使用harbor搭建本地镜像仓库
目录 一.系统环境 二.前言 三.Harbor 四.使用harbor搭建私有镜像仓库 4.1 环境介绍 4.2 k8smaster节点安装配置harbor 4.2.1 安装harbor离线包 4.2. ...
- Python Docker 查看私有仓库镜像【转】
文章来源:python Docker 查看私有仓库镜像 pip 安装: # 首先安装epel扩展源: yum -y install epel-release # 更新完成之后,就可安装pip: yum ...
- 定时清理docker私服镜像
定时清理docker私服镜像 使用CI构建docker镜像进行发布极大促进了大家的版本发布效率,于是镜像仓库也就急速膨胀.为了缓解磁盘压力,我们需要设置一些清理策略. 对于不同docker镜像的清理策 ...
- [python](Docker SDK)上传镜像到私有仓库(tls、身份认证)
(Docker SDK)上传镜像到私有仓库(tls.身份认证) API:https://docker-py.readthedocs.io/en/stable/ 环境:python:3.7.3 配置参数 ...
- Docker | 使用dockerfile生成镜像,清理docker空间
用dockerfile生成镜像并挂载数据卷 编写dockerfile文件 创建dockerfile01 文件 # 基础镜像 FROM centos VOLUME ["volume01&quo ...
- .NET遇上Docker - Harbor的安装与基本使用
Harbor是一个开源企业级Docker注册中心,可以用于搭建私有的Docker Image仓库.可以实现权限控制等. 安装Harbor 首先,需要安装Docker和Docker Compose,参考 ...
- 微服务架构 - 基于Harbor构建本地镜像仓库
之前写过<搭建docker本地镜像仓库并提供权限校验及UI界面>文章,然后有同仁评论道这样做太复杂了,如果Harbor来搭建会更简单同时功能也更强大.于是抽时间研究了基于Harbor构建本 ...
随机推荐
- 使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()
java编程里有关约定:如果两个对象根据equals方法比较是相等的,那么调用这两个对象的任意一个hashcode方法都必须产生相同的结果. hashcode()和equals()都继承于object ...
- SoC的设计变的如此复杂和高成本
当一些硬件IP变成了标准的螺丝钉和螺母的时候,硬件设计的未来就没有了吗? 由于太过于复杂,而整体的毛利率又不高,无法迅速迭代,产生边际效应,也无法迅速扩张. 就成了一个传统行业,从业者也逐渐被时代遗忘 ...
- node+express 搭建本地服务
首先,得有node环境,其次建个项目 目录例如 酱紫! 再次 写server.js,当然你可以换个名字a.js .b.js.why.js随你喜欢 var express = require('exp ...
- java基础(8)---接口和lambda
一.接口 接口定义: 接口抽象方法定义: 二.接口实现类的定义.创建.调用 接口需要一个实现类. 接口实现类的定义: 接口实现类的创建和调用: 接口的好处: 不好的写法: 推荐的写法: 接口实 ...
- 《你们都是魔鬼吗》第八次团队作业 第二天Alpha
<你们都是魔鬼吗>第八次团队作业:Alpha冲刺 项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 你们都是魔鬼吗 作业学习目标 完成最 ...
- 解决jdbc向数据库存入数据出现乱码的情况
解决办法 1.修改项目的编码,建议统一使用utf-8来实现,这样整个项目就是utf-8. 2.jdbc:mysql://locathost:3306/数据库名称?useUnicode=true& ...
- 用Visio画流程图
一:基本流程图 主要用于创建流程图.顺序图.信息跟踪图.流程规划图和结构预测图,包含了形状.连接线和链接. 步骤: (1)打开Visio,单击"类别"->"流程图& ...
- Spring Jpa
一对多 1.application.properties 2.Dao层 3.Controller 3.1级联添加数据 3.2查询数据 3.3删除数据 多对多 1.查询 2.添加
- Canvas 总结,到第4章 canvas图形变换
canvas 必须认识到的大坑 <!-- 重点: 在js/canvas标签中定义的宽和高是画布实际的宽和高. 在样式表中定义的宽和高是画布缩放后的宽和高. 即:把js/canvas实际大小缩放到 ...
- java如何连接数据库并对其操作(以PostgreSQL为例)
java如何连接数据库并对其操作(以PostgreSQL为例) 相关概念 JDBC(Java Data Base Connectivity)是一种用于执行SQL语句的Java API,可以为多种关系数 ...