

搭建docker镜像仓库(一):使用registry搭建本地镜像仓库 - 人生的哲理
source link: https://www.cnblogs.com/renshengdezheli/p/16646969.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

一.系统环境
服务器版本 | docker软件版本 | CPU架构 |
---|---|---|
CentOS Linux release 7.4.1708 (Core) | Docker version 20.10.12 | x86_64 |
在使用Docker拉取镜像时,Docker首先默认从Docker Hub官方下载镜像,很多时候我们的镜像都是使用Dockerfile自定义私有镜像,不对外公开,而且为了安全起见,docker可能在内网环境下运行,所以我们有必要搭建一套docker本地私有镜像仓库,以供整个内网集群环境使用。
搭建镜像仓库主流的有两种方法,一种是使用docker官方提供的registry镜像搭建仓库,简单快捷,但是功能有限;另一种是使用harbor搭建本地镜像仓库,harbor功能更强,使用范围更广,这里介绍使用registry搭建本地镜像仓库。
使用harbor搭建本地镜像仓库请查看博客《》。
三.使用registry搭建私有镜像仓库
3.1 环境介绍
架构:k8smaster作为私有仓库,k8sworker1作为docker客户端
服务器 | 操作系统版本 | CPU架构 | 进程 | 功能描述 |
---|---|---|---|---|
k8smaster/192.168.110.137 | CentOS Linux release 7.4.1708 (Core) | x86_64 | registry | registry镜像仓库 |
k8sworker1/192.168.110.138 | CentOS Linux release 7.4.1708 (Core) | x86_64 | docker | docker客户端 |
3.2 k8smaster节点配置镜像仓库
拉取registry镜像
[root@k8smaster ~]# docker pull hub.c.163.com/library/registry:latest
latest: Pulling from library/registry
25728a036091: Pull complete
0da5d1919042: Pull complete
e27a85fd6357: Pull complete
d9253dc430fe: Pull complete
916886b856db: Pull complete
Digest: sha256:fce8e7e1569d2f9193f75e9b42efb07a7557fc1e9d2c7154b23da591e324f3d1
Status: Downloaded newer image for hub.c.163.com/library/registry:latest
hub.c.163.com/library/registry:latest
#registry镜像已经拉取下来
[root@k8smaster ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hub.c.163.com/library/registry latest 751f286bc25e 4 years ago 33.2MB
查看registry镜像的端口:EXPOSE 5000/tcp 数据卷:VOLUME [/var/lib/registry]
[root@k8smaster ~]# docker history hub.c.163.com/library/registry:latest
IMAGE CREATED CREATED BY SIZE COMMENT
751f286bc25e 4 years ago /bin/sh -c #(nop) CMD ["/etc/docker/registr… 0B
<missing> 4 years ago /bin/sh -c #(nop) ENTRYPOINT ["/entrypoint.… 0B
<missing> 4 years ago /bin/sh -c #(nop) COPY file:7b57f7ab1a8cf85c… 155B
<missing> 4 years ago /bin/sh -c #(nop) EXPOSE 5000/tcp 0B
<missing> 4 years ago /bin/sh -c #(nop) VOLUME [/var/lib/registry] 0B
<missing> 4 years ago /bin/sh -c #(nop) COPY file:6c4758d509045dc4… 295B
<missing> 4 years ago /bin/sh -c #(nop) COPY file:b99d4fe47ad1addf… 22.8MB
<missing> 4 years ago /bin/sh -c set -ex && apk add --no-cache… 5.61MB
<missing> 4 years ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 4 years ago /bin/sh -c #(nop) ADD file:89e72bfc19e81624b… 4.81MB
创建registry容器,registry镜像生成容器作为私有仓库
-p 5000:5000做端口映射,物理机端口5000:容器端口5000
-v /docker/var/lib/registry:/var/lib/registry数据卷挂载,物理机目录/docker/var/lib/registry:容器目录/var/lib/registry
[root@k8smaster ~]# docker run -dit --restart=always --name=docker-registry -p 5000:5000 -v /docker/var/lib/registry:/var/lib/registry hub.c.163.com/library/registry:latest
3f8378272356bece1d690f16ad925bbd25a9ec12840d0612df2c45f84c27b3f5
[root@k8smaster ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
3f8378272356 hub.c.163.com/library/registry:latest "/entrypoint.sh /etc…" 4 seconds ago Up 2 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp docker-registry
此时仓库下还没有任何文件
[root@k8smaster ~]# ls /docker/var/lib/registry
3.3 k8sworker1节点配置从私有仓库上传和拉取镜像
3.3.1 上传镜像到私有仓库
现在在k8sworker1配置docker客户端
查看现有的镜像,如果没有镜像,直接docker pull即可
[root@k8sworker1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hub.c.163.com/library/wordpress latest dccaeccfba36 4 years ago 406MB
hub.c.163.com/library/tomcat latest 72d2be374029 4 years ago 292MB
hub.c.163.com/library/mysql latest 9e64176cd8a2 4 years ago 407MB
docker tag对镜像进行重命名,命名格式为:私有仓库ip:端口/分类/镜像:镜像版本
[root@k8sworker1 ~]# docker tag hub.c.163.com/library/wordpress 192.168.110.137:5000/boke/wordpress:latest
[root@k8sworker1 ~]# docker tag hub.c.163.com/library/tomcat 192.168.110.137:5000/web/tomcat:v1
[root@k8sworker1 ~]# docker tag hub.c.163.com/library/mysql 192.168.110.137:5000/db/mysql:5.7
把我们命名好的镜像推送到k8smatser的仓库里,但是报错了,报错客户端的连接为HTTPS,但是服务器端返回的是http
[root@k8sworker1 ~]# docker push 192.168.110.137:5000/boke/wordpress:latest
The push refers to repository [192.168.110.137:5000/boke/wordpress]
Get https://192.168.110.137:5000/v2/: http: server gave HTTP response to HTTPS client
解决方式有两种:第一种修改/usr/lib/systemd/system/docker.service文件
[root@k8sworker1 ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since 二 2022-01-04 10:53:14 CST; 7h ago
Docs: https://docs.docker.com
Main PID: 1039 (dockerd)
Memory: 1.2G
CGroup: /system.slice/docker.service
└─1039 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
#/usr/bin/dockerd有一个参数--insecure-registry用于指定不安全的仓库
[root@k8sworker1 ~]# /usr/bin/dockerd --help | grep insecure
--insecure-registry list Enable insecure registry communication
[root@k8sworker1 ~]# vim /usr/lib/systemd/system/docker.service
#修改内容如下:添加了私有仓库地址和端口 --insecure-registry 192.168.110.137:5000
[root@k8sworker1 ~]# cat /usr/lib/systemd/system/docker.service | grep insecure-registry
ExecStart=/usr/bin/dockerd --insecure-registry 192.168.110.137:5000 -H fd:// --containerd=/run/containerd/containerd.sock
#重新加载配置文件并重启docker
[root@k8sworker1 ~]# systemctl daemon-reload ; systemctl restart docker
[root@k8sworker1 ~]# systemctl status docker
● docker.service - Docker Application Container Engine
Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
Active: active (running) since 二 2022-01-04 17:57:26 CST; 14s ago
Docs: https://docs.docker.com
Main PID: 62817 (dockerd)
Memory: 49.0M
CGroup: /system.slice/docker.service
└─62817 /usr/bin/dockerd --insecure-registry 192.168.110.137:5000 -H fd:// --containerd=/run/containerd/containerd.sock
#此时,推送wordpress镜像到私有仓库成功
[root@k8sworker1 ~]# docker push 192.168.110.137:5000/boke/wordpress:latest
The push refers to repository [192.168.110.137:5000/boke/wordpress]
53e16fa1f104: Pushed
562dd11ed871: Pushed
......
ddd6dcab19ff: Pushed
2c40c66f7667: Pushed
latest: digest: sha256:ca4cf4692b7bebd81f229942c996b1c4e6907d6733e977e93d671a54b8053a22 size: 4078
第二种方式是修改/etc/docker/daemon.json
#新增"insecure-registries":["192.168.110.137:5000"]
[root@k8sworker1 ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://frz7i079.mirror.aliyuncs.com"],
"insecure-registries":["192.168.110.137:5000"]
}
[root@k8sworker1 ~]# systemctl restart docker
[root@k8sworker1 ~]# cat /etc/docker/daemon.json
{
"registry-mirrors": ["https://frz7i079.mirror.aliyuncs.com"],
"insecure-registries":["192.168.110.137:5000"]
}
#推送tomcat镜像到私有仓库成功
[root@k8sworker1 ~]# docker push 192.168.110.137:5000/web/tomcat:v1
The push refers to repository [192.168.110.137:5000/web/tomcat]
f79699072473: Pushed
......
fe40be59465f: Pushed
cf4ecb492384: Pushed
v1: digest: sha256:6241d7435b5c4e9d54be7d61e834836a71b1934b5403e01eff8768f0e2bcf210 size: 3045
[root@k8sworker1 ~]# docker push 192.168.110.137:5000/db/mysql:5.7
The push refers to repository [192.168.110.137:5000/db/mysql]
8129a85b4056: Pushed
......
295d6a056bfd: Pushed
5.7: digest: sha256:c0806ac73235043de2a6cb4738bb2f6a74f71d9c7aa0f19c8e7530fd6c299e75 size: 2617
查看私有仓库里的镜像
[root@k8sworker1 ~]# curl 192.168.110.137:5000/v2/_catalog
{"repositories":["boke/wordpress","db/mysql","web/tomcat"]}
查看某个镜像的版本
[root@k8sworker1 ~]# curl 192.168.110.137:5000/v2/boke/wordpress/tags/list
{"name":"boke/wordpress","tags":["latest"]}
[root@k8sworker1 ~]# yum -y install jq
已加载插件:fastestmirror
base ......
已安装:
jq.x86_64 0:1.6-2.el7
作为依赖被安装:
oniguruma.x86_64 0:6.8.2-1.el7
完毕!
使用脚本查看私有仓库里的镜像
[root@k8sworker1 ~]# cat list_images_from_registries.sh
#!/bin/bash
file=$(mktemp)
curl -s $1:5000/v2/_catalog | jq | egrep -v '\{|\}|\[|]' | awk -F\" '{print $2}' > $file
while read aa ; do
tag=($(curl -s $1:5000/v2/$aa/tags/list | jq | egrep -v '\{|\}|\[|]|name' | awk -F\" '{print $2}'))
for i in ${tag[*]} ; do
echo $1:5000/${aa}:$i
done
done < $file
rm -rf $file
[root@k8sworker1 ~]# bash list_images_from_registries.sh 192.168.110.137
192.168.110.137:5000/boke/wordpress:latest
192.168.110.137:5000/db/mysql:5.7
192.168.110.137:5000/web/tomcat:v1
先使用docker rmi 删除刚才修改的本地镜像
[root@k8sworker1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
3.3.2 从私有仓库里拉取镜像
从私有仓库里拉取镜像
[root@k8sworker1 ~]# docker pull 192.168.110.137:5000/boke/wordpress:latest
latest: Pulling from boke/wordpress
21f90b3df721: Pull complete
13ce341a48bc: Pull complete
......
500c148f4d2b: Pull complete
Digest: sha256:ca4cf4692b7bebd81f229942c996b1c4e6907d6733e977e93d671a54b8053a22
Status: Downloaded newer image for 192.168.110.137:5000/boke/wordpress:latest
192.168.110.137:5000/boke/wordpress:latest
[root@k8sworker1 ~]# docker pull 192.168.110.137:5000/web/tomcat:v1
v1: Pulling from web/tomcat
a2149b3f2ac2: Pull complete
......
8dbb09972def: Pull complete
Digest: sha256:6241d7435b5c4e9d54be7d61e834836a71b1934b5403e01eff8768f0e2bcf210
Status: Downloaded newer image for 192.168.110.137:5000/web/tomcat:v1
192.168.110.137:5000/web/tomcat:v1
[root@k8sworker1 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.110.137:5000/boke/wordpress latest dccaeccfba36 4 years ago 406MB
192.168.110.137:5000/web/tomcat v1 72d2be374029 4 years ago 292MB
从docker客户端上传镜像之后,仓库文件夹里已经存在镜像了
[root@k8smaster ~]# ls /docker/var/lib/registry
docker
[root@k8smaster ~]# ls /docker/var/lib/registry/docker/
registry
[root@k8smaster ~]# ls /docker/var/lib/registry/docker/registry/
v2
[root@k8smaster ~]# ls /docker/var/lib/registry/docker/registry/v2/
blobs repositories
[root@k8smaster ~]# ls /docker/var/lib/registry/docker/registry/v2/repositories/
boke db web
[root@k8smaster ~]# ls /docker/var/lib/registry/docker/registry/v2/repositories/boke/
wordpress
[root@k8smaster ~]# ls /docker/var/lib/registry/docker/registry/v2/repositories/boke/wordpress/
_layers _manifests _uploads
使用脚本删除私有仓库里的镜像(脚本在附录里)
#给脚本授予可执行权限
[root@k8smaster ~]# chmod +x delete_docker_registry_image
#设置私有仓库的镜像文件夹
[root@k8smaster ~]# export REGISTRY_DATA_DIR=/docker/var/lib/registry/docker/registry/v2/
#删除私有仓库的wordpress镜像
[root@k8smaster ~]# ./delete_docker_registry_image -i boke/wordpress:latest
INFO [2022-01-04 19:56:08,375] Deleting /docker/var/lib/registry/docker/registry/v2/blobs/sha256/46/4676067592f277e1723e4ab4c588603df0b3dea762e22c354f7ada29b391cf10
.......
INFO [2022-01-04 19:56:08,412] Deleting /docker/var/lib/registry/docker/registry/v2/repositories/boke/wordpress
#在docker客户端查看发现私有仓库里的wordpress镜像已经被删除了
[root@k8sworker1 ~]# bash list_images_from_registries.sh 192.168.110.137
192.168.110.137:5000/db/mysql:5.7
192.168.110.137:5000/web/tomcat:v1
四.附录:删除私有仓库镜像的Python脚本
[root@k8smaster ~]# cat delete_docker_registry_image
#!/usr/bin/env python
"""
Usage:
Shut down your registry service to avoid race conditions and possible data loss
and then run the command with an image repo like this:
delete_docker_registry_image.py --image awesomeimage --dry-run
"""
import argparse
import json
import logging
import os
import sys
import shutil
import glob
logger = logging.getLogger(__name__)
def del_empty_dirs(s_dir, top_level):
"""recursively delete empty directories"""
b_empty = True
for s_target in os.listdir(s_dir):
s_path = os.path.join(s_dir, s_target)
if os.path.isdir(s_path):
if not del_empty_dirs(s_path, False):
b_empty = False
else:
b_empty = False
if b_empty:
logger.debug("Deleting empty directory '%s'", s_dir)
if not top_level:
os.rmdir(s_dir)
return b_empty
def get_layers_from_blob(path):
"""parse json blob and get set of layer digests"""
try:
with open(path, "r") as blob:
data_raw = blob.read()
data = json.loads(data_raw)
if data["schemaVersion"] == 1:
result = set([entry["blobSum"].split(":")[1] for entry in data["fsLayers"]])
else:
result = set([entry["digest"].split(":")[1] for entry in data["layers"]])
if "config" in data:
result.add(data["config"]["digest"].split(":")[1])
return result
except Exception as error:
logger.critical("Failed to read layers from blob:%s", error)
return set()
def get_digest_from_blob(path):
"""parse file and get digest"""
try:
with open(path, "r") as blob:
return blob.read().split(":")[1]
except Exception as error:
logger.critical("Failed to read digest from blob:%s", error)
return ""
def get_links(path, _filter=None):
"""recursively walk `path` and parse every link inside"""
result = []
for root, _, files in os.walk(path):
for each in files:
if each == "link":
filepath = os.path.join(root, each)
if not _filter or _filter in filepath:
result.append(get_digest_from_blob(filepath))
return result
class RegistryCleanerError(Exception):
pass
class RegistryCleaner(object):
"""Clean registry"""
def __init__(self, registry_data_dir, dry_run=False):
self.registry_data_dir = registry_data_dir
if not os.path.isdir(self.registry_data_dir):
raise RegistryCleanerError("No repositories directory found inside " \
"REGISTRY_DATA_DIR '{0}'.".
format(self.registry_data_dir))
self.dry_run = dry_run
def _delete_layer(self, repo, digest):
"""remove blob directory from filesystem"""
path = os.path.join(self.registry_data_dir, "repositories", repo, "_layers/sha256", digest)
self._delete_dir(path)
def _delete_blob(self, digest):
"""remove blob directory from filesystem"""
path = os.path.join(self.registry_data_dir, "blobs/sha256", digest[0:2], digest)
self._delete_dir(path)
def _blob_path_for_revision(self, digest):
"""where we can find the blob that contains the json describing this digest"""
return os.path.join(self.registry_data_dir, "blobs/sha256",
digest[0:2], digest, "data")
def _blob_path_for_revision_is_missing(self, digest):
"""for each revision, there should be a blob describing it"""
return not os.path.isfile(self._blob_path_for_revision(digest))
def _get_layers_from_blob(self, digest):
"""get layers from blob by digest"""
return get_layers_from_blob(self._blob_path_for_revision(digest))
def _delete_dir(self, path):
"""remove directory from filesystem"""
if self.dry_run:
logger.info("DRY_RUN: would have deleted %s", path)
else:
logger.info("Deleting %s", path)
try:
shutil.rmtree(path)
except Exception as error:
logger.critical("Failed to delete directory:%s", error)
def _delete_from_tag_index_for_revision(self, repo, digest):
"""delete revision from tag indexes"""
paths = glob.glob(
os.path.join(self.registry_data_dir, "repositories", repo,
"_manifests/tags/*/index/sha256", digest)
)
for path in paths:
self._delete_dir(path)
def _delete_revisions(self, repo, revisions, blobs_to_keep=None):
"""delete revisions from list of directories"""
if blobs_to_keep is None:
blobs_to_keep = []
for revision_dir in revisions:
digests = get_links(revision_dir)
for digest in digests:
self._delete_from_tag_index_for_revision(repo, digest)
if digest not in blobs_to_keep:
self._delete_blob(digest)
self._delete_dir(revision_dir)
def _get_tags(self, repo):
"""get all tags for given repository"""
path = os.path.join(self.registry_data_dir, "repositories", repo, "_manifests/tags")
if not os.path.isdir(path):
logger.critical("No repository '%s' found in repositories directory %s",
repo, self.registry_data_dir)
return None
result = []
for each in os.listdir(path):
filepath = os.path.join(path, each)
if os.path.isdir(filepath):
result.append(each)
return result
def _get_repositories(self):
"""get all repository repos"""
result = []
root = os.path.join(self.registry_data_dir, "repositories")
for each in os.listdir(root):
filepath = os.path.join(root, each)
if os.path.isdir(filepath):
inside = os.listdir(filepath)
if "_layers" in inside:
result.append(each)
else:
for inner in inside:
result.append(os.path.join(each, inner))
return result
def _get_all_links(self, except_repo=""):
"""get links for every repository"""
result = []
repositories = self._get_repositories()
for repo in [r for r in repositories if r != except_repo]:
path = os.path.join(self.registry_data_dir, "repositories", repo)
for link in get_links(path):
result.append(link)
return result
def prune(self):
"""delete all empty directories in registry_data_dir"""
del_empty_dirs(self.registry_data_dir, True)
def _layer_in_same_repo(self, repo, tag, layer):
"""check if layer is found in other tags of same repository"""
for other_tag in [t for t in self._get_tags(repo) if t != tag]:
path = os.path.join(self.registry_data_dir, "repositories", repo,
"_manifests/tags", other_tag, "current/link")
manifest = get_digest_from_blob(path)
try:
layers = self._get_layers_from_blob(manifest)
if layer in layers:
return True
except IOError:
if self._blob_path_for_revision_is_missing(manifest):
logger.warn("Blob for digest %s does not exist. Deleting tag manifest: %s", manifest, other_tag)
tag_dir = os.path.join(self.registry_data_dir, "repositories", repo,
"_manifests/tags", other_tag)
self._delete_dir(tag_dir)
else:
raise
return False
def _manifest_in_same_repo(self, repo, tag, manifest):
"""check if manifest is found in other tags of same repository"""
for other_tag in [t for t in self._get_tags(repo) if t != tag]:
path = os.path.join(self.registry_data_dir, "repositories", repo,
"_manifests/tags", other_tag, "current/link")
other_manifest = get_digest_from_blob(path)
if other_manifest == manifest:
return True
return False
def delete_entire_repository(self, repo):
"""delete all blobs for given repository repo"""
logger.debug("Deleting entire repository '%s'", repo)
repo_dir = os.path.join(self.registry_data_dir, "repositories", repo)
if not os.path.isdir(repo_dir):
raise RegistryCleanerError("No repository '{0}' found in repositories "
"directory {1}/repositories".
format(repo, self.registry_data_dir))
links = set(get_links(repo_dir))
all_links_but_current = set(self._get_all_links(except_repo=repo))
for layer in links:
if layer in all_links_but_current:
logger.debug("Blob found in another repository. Not deleting: %s", layer)
else:
self._delete_blob(layer)
self._delete_dir(repo_dir)
def delete_repository_tag(self, repo, tag):
"""delete all blobs only for given tag of repository"""
logger.debug("Deleting repository '%s' with tag '%s'", repo, tag)
tag_dir = os.path.join(self.registry_data_dir, "repositories", repo, "_manifests/tags", tag)
if not os.path.isdir(tag_dir):
raise RegistryCleanerError("No repository '{0}' tag '{1}' found in repositories "
"directory {2}/repositories".
format(repo, tag, self.registry_data_dir))
manifests_for_tag = set(get_links(tag_dir))
revisions_to_delete = []
blobs_to_keep = []
layers = []
all_links_not_in_current_repo = set(self._get_all_links(except_repo=repo))
for manifest in manifests_for_tag:
logger.debug("Looking up filesystem layers for manifest digest %s", manifest)
if self._manifest_in_same_repo(repo, tag, manifest):
logger.debug("Not deleting since we found another tag using manifest: %s", manifest)
continue
else:
revisions_to_delete.append(
os.path.join(self.registry_data_dir, "repositories", repo,
"_manifests/revisions/sha256", manifest)
)
if manifest in all_links_not_in_current_repo:
logger.debug("Not deleting the blob data since we found another repo using manifest: %s", manifest)
blobs_to_keep.append(manifest)
layers.extend(self._get_layers_from_blob(manifest))
layers_uniq = set(layers)
for layer in layers_uniq:
if self._layer_in_same_repo(repo, tag, layer):
logger.debug("Not deleting since we found another tag using digest: %s", layer)
continue
self._delete_layer(repo, layer)
if layer in all_links_not_in_current_repo:
logger.debug("Blob found in another repository. Not deleting: %s", layer)
else:
self._delete_blob(layer)
self._delete_revisions(repo, revisions_to_delete, blobs_to_keep)
self._delete_dir(tag_dir)
def delete_untagged(self, repo):
"""delete all untagged data from repo"""
logger.debug("Deleting utagged data from repository '%s'", repo)
repositories_dir = os.path.join(self.registry_data_dir, "repositories")
repo_dir = os.path.join(repositories_dir, repo)
if not os.path.isdir(repo_dir):
raise RegistryCleanerError("No repository '{0}' found in repositories "
"directory {1}/repositories".
format(repo, self.registry_data_dir))
tagged_links = set(get_links(repositories_dir, _filter="current"))
layers_to_protect = []
for link in tagged_links:
layers_to_protect.extend(self._get_layers_from_blob(link))
unique_layers_to_protect = set(layers_to_protect)
for layer in unique_layers_to_protect:
logger.debug("layer_to_protect: %s", layer)
tagged_revisions = set(get_links(repo_dir, _filter="current"))
revisions_to_delete = []
layers_to_delete = []
dir_for_revisions = os.path.join(repo_dir, "_manifests/revisions/sha256")
for rev in os.listdir(dir_for_revisions):
if rev not in tagged_revisions:
revisions_to_delete.append(os.path.join(dir_for_revisions, rev))
for layer in self._get_layers_from_blob(rev):
if layer not in unique_layers_to_protect:
layers_to_delete.append(layer)
unique_layers_to_delete = set(layers_to_delete)
self._delete_revisions(repo, revisions_to_delete)
for layer in unique_layers_to_delete:
self._delete_blob(layer)
self._delete_layer(repo, layer)
def get_tag_count(self, repo):
logger.debug("Get tag count of repository '%s'", repo)
repo_dir = os.path.join(self.registry_data_dir, "repositories", repo)
tags_dir = os.path.join(repo_dir, "_manifests/tags")
if os.path.isdir(tags_dir):
tags = os.listdir(tags_dir)
return len(tags)
else:
logger.info("Tags directory does not exist: '%s'", tags_dir)
return -1
def main():
"""cli entrypoint"""
parser = argparse.ArgumentParser(description="Cleanup docker registry")
parser.add_argument("-i", "--image",
dest="image",
required=True,
help="Docker image to cleanup")
parser.add_argument("-v", "--verbose",
dest="verbose",
action="store_true",
help="verbose")
parser.add_argument("-n", "--dry-run",
dest="dry_run",
action="store_true",
help="Dry run")
parser.add_argument("-f", "--force",
dest="force",
action="store_true",
help="Force delete (deprecated)")
parser.add_argument("-p", "--prune",
dest="prune",
action="store_true",
help="Prune")
parser.add_argument("-u", "--untagged",
dest="untagged",
action="store_true",
help="Delete all untagged blobs for image")
args = parser.parse_args()
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter(u'%(levelname)-8s [%(asctime)s] %(message)s'))
logger.addHandler(handler)
if args.verbose:
logger.setLevel(logging.DEBUG)
else:
logger.setLevel(logging.INFO)
# make sure not to log before logging is setup. that'll hose your logging config.
if args.force:
logger.info(
"You supplied the force switch, which is deprecated. It has no effect now, and the script defaults to doing what used to be only happen when force was true")
splitted = args.image.split(":")
if len(splitted) == 2:
image = splitted[0]
tag = splitted[1]
else:
image = args.image
tag = None
if 'REGISTRY_DATA_DIR' in os.environ:
registry_data_dir = os.environ['REGISTRY_DATA_DIR']
else:
registry_data_dir = "/opt/registry_data/docker/registry/v2"
try:
cleaner = RegistryCleaner(registry_data_dir, dry_run=args.dry_run)
if args.untagged:
cleaner.delete_untagged(image)
else:
if tag:
tag_count = cleaner.get_tag_count(image)
if tag_count == 1:
cleaner.delete_entire_repository(image)
else:
cleaner.delete_repository_tag(image, tag)
else:
cleaner.delete_entire_repository(image)
if args.prune:
cleaner.prune()
except RegistryCleanerError as error:
logger.fatal(error)
sys.exit(1)
if __name__ == "__main__":
main()
Recommend
-
85
目前 Docker 官方维护了一个公共仓库 Docker Hub,其中已经包括了数量超过 15,000
-
24
在使用 Kubernetes 时,我们需要经常访问 gcr.io 镜像仓库,由于众所周知的原因,gcr.io 在中国无法访问。gcr.azk8s.cn 是 gcr.io 镜像仓库的代理站点,原来可以通过 gcr.azk8s.cn 访问 gcr.io 仓库里的镜像,但是目前 *.azk8s.cn 已经仅...
-
11
为了实现docker tar包能够直接通过页面上传,调研了一下registry的api,以及如何解析tar包(其实就是docker daemon程序实现的部分)。 要想实现,首先要了解docker tar包中结构组成: tar包结构 拿了一个包含一个镜像的tar包进行解压:
-
9
搭建私有docker镜像仓库 作者: wencst 分类: linux,Uncategorized,
-
10
Jager · 7月4日 · 2014年iso制作yum仓库 · 本地yum仓库 382次已读这两天工作是用...
-
8
在mac中用minikube搭建了一个k8s环境,但是每次拉取镜像都很慢甚至失败, 本文总结两种从本地私有镜像仓库拉取镜像的方法实践, 先将镜像在宿主机上翻墙拉取到本地, 再由minikube 虚机中的k8s 来拉取本地镜像, 这样即可解决之前的拉取镜像失败,也可提升拉取镜像的速度...
-
6
Harbor企业级私服Docker镜像仓库搭建及应用 Docker Hub作为Docker默认官方公共镜像,如果想要...
-
8
搭建私有Docker镜像仓库学习笔记 搭建没有GUI界面的仓库 通过Docker官方提供的镜像搭建镜像仓库 docker run --name registry --restart=always -p 5000:5000 -d -v registry-data:/var/lib...
-
11
Docker镜像仓库harbor的搭建与使用 2022-12-19 2 分钟阅读 一:我们在公司内部建立了Docker内部镜像仓库: harbor是vmware出的一个docker镜像仓库,本质是一组容器的集合体,算是一个多容器的pod. 数据卷缺省是宿...
-
6
使用 docker registry 本地仓库时候,一个镜像推送多个 tag 后,删除其中一个 tag 会造成所有 tag 都被删除,如何避免 这几天整了个 TUI 应用,删除仓库上选中的 tag 镜像,查看 github 上代码的时候,折腾出来一个镜像具有多个 tag 下只删除指定 tag 的步...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK