您的位置:首页 > 运维架构 > Docker

一文搞定docker创建私有镜像仓库(配置启动http和https方式私有仓库服务,查询、删除私有仓库镜像)

2019-06-29 23:28 1191 查看

       docker除了使用公共镜像仓库之外,也可以创建私有镜像仓库。对于内部开发、测试、部署环境来说,是很有必要的。
       如何创建私有镜像仓库服务呢?当然是以容器的方式啦!

1.拉取官方registry镜像到本地

docker pull registry

2.先尝试启动一个registry容器,看一看都有什么东东

docker run -d -p 5000:5000 registry

[root@webserver ~]# docker run -d -p 5000:5000 registry
40cf413a033447fd91d58fbc971747c877af2834a050d4b6699f261981458dc2
[root@webserver ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
40cf413a0334        registry            "/entrypoint.sh /etc…"   2 seconds ago       Up 1 second         0.0.0.0:5000->5000/tcp   angry_hypatia

       进入容器,搜索registry,会发现只有三条记录

[root@webserver ~]# docker exec -ti 40cf413a0334 sh
/ # find / -name registry
/bin/registry
/etc/docker/registry
/var/lib/registry

       其中,/etc/docker/registry存储配置文件config.yml。

/ # ls -l /etc/docker/registry
total 4
-rw-rw-r--    1 root     root           295 Mar  8 02:46 config.yml

       看一下config.yml都有什么内容。

/ # cat /etc/docker/registry/config.yml
version: 0.1
log:
field
4000
s:
service: registry
storage:
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
/ #

       /var/lib/registry用来存储镜像。

/ # ls -l /var/lib/registry
total 0

       停止这个registry容器,重新启动一个挂载本地目录的registry容器。

docker stop 40cf413a0334

       (如果就这么使用registry容器内存储的话,一旦误删除了registry容器,私有仓库的镜像也就都没了)

3.配置、启动私有镜像仓库容器

       设置一个存储私有仓库镜像的本地路径

mkdir -p /opt/data/registry

       创建一个私有镜像仓库的配置文件

mkdir -p /usr/local/docker

vim /usr/local/docker/config.yml

       注:需在配置文件中的storage配置中增加delete=true配置项,允许删除镜像。默认的配置文件没有这个参数。

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

       访问私有镜像仓库容器,分为http和https两种,默认是https。

3.1 设置http访问的私有镜像仓库容器

       docker从1.3.X之后,与docker registry交互默认使用的是https,修改docker启动配置文件,在启动docker server时增加启动参数为默认使用http访问。

修改前备份一下docker.service

cp /usr/lib/systemd/system/docker.service /usr/lib/systemd/system/docker.service.bak

修改docker.service

vim /usr/lib/systemd/system/docker.service

       找到 ExecStart的行,修改成下面这样,注:xx.yy.com:5000或者ip:5000均可,若是设置成xx.yy.com:5000,要记得修改/etc/hosts文件添加进去

ExecStart=/usr/bin/dockerd  --insecure-registry registry.phoenix.com:5000
重启docker,令修改生效

systemctl daemon-reload

systemctl restart docker

启动registry容器
docker run -d \
--restart=always \
--name registry.phoenix.com \
-p 5000:5000 \
-v /opt/data/registry:/var/lib/registry \
-v /usr/local/docker/config.yml:/etc/docker/registry/config.yml \
registry
参数 解释
-d
容器启动后,在后台运行
--restart=always
--restart
容器重启策略,
always
为自动启动
--name
容器命名
-p
映射端口,前面是本机端口号,后面是容器端口号
-v 映射/挂载volume,前面是本机路径/文件,后面是容器路径/文件

       没有报错的话,容器应该正常运行了,执行

docker ps
可以看到。

查看一下私有仓库容器运行情况
[root@webserver docker]# curl -XGET http://registry.phoenix.com:5000/v2/_catalog
{"repositories":[]}
[root@webserver docker]# curl -XGET http://registry.phoenix.com:5000/v2/hello-world/tags/list
{"errors":[{"code":"NAME_UNKNOWN","message":"repository name not known to registry","detail":{"name":"hello-world"}}]}

       此时镜像仓库是空的,没有hello-world镜像存在,本机/opt/data/registry路径下也是空的。

[root@webserver docker]# ll /opt/data/registry
总用量 0
[root@webserver docker]#
推送镜像测试

       把一个本地镜像push到私有仓库中。
       首先,在测试机下pull一个比较小的镜像来测试(此处使用的是hello-world),已存在的话可以跳过pull这一步骤。

docker pull hello-world

       然后,修改一下该镜像的tag。

docker tag hello-world registry.phoenix.com:5000/hello-world

       接下来把打了tag的镜像上传到私有仓库。

docker push registry.phoenix.com:5000/hello-world

[root@webserver docker]# docker push registry.phoenix.com:5000/hello-world
The push refers to repository [registry.phoenix.com:5000/hello-world]
af0b15c8625b: Pushed
latest: digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a size: 524

       看一下镜像仓库,hello-world已经成功推入仓库中。

[root@webserver docker]# curl -XGET http://registry.phoenix.com:5000/v2/hello-world/tags/list
{"name":"hello-world","tags":["latest"]}[root@webserver docker]# curl -XGET http://registry.phoenix.com:5000/v2/_catalog
{"repositories":["hello-world"]}

       本机/opt/data/registry路径下存储了镜像文件。

[root@webserver docker]# ll /opt/data/registry/ && du -sh /opt/data/registry/
总用量 0
drwxr-xr-x 3 root root 22 6月  28 11:09 docker
32K     /opt/data/registry/

3.2 设置https访问的私有镜像仓库容器

生成自签发证书

       创建certs目录:

mkdir -p certs

       生成自签发证书:

openssl req -newkey rsa:4096 \
-nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt

       执行以上命令,生成证书。
       Common Name要输入我们registry的域名,生成的证书只对该域名有效。其他的可以任意填。

[root@webserver ~]# openssl req -newkey rsa:4096 \
> -nodes -sha256 -keyout certs/domain.key \
> -x509 -days 365 -out certs/domain.crt
Generating a RSA private key
.................++++
....................++++
writing new private key to 'certs/domain.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:XX
Locality Name (eg, city) []:YY
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:registry.phoenix.com
Email Address []:
[root@webserver ~]#

       生成后可以在certs目录下查看到证书。

生成鉴权密码文件

       注:使用时username替换为你自己的用户名,password替换为你自己的密码。

mkdir auth
docker run --entrypoint htpasswd registry -Bbn username password  > auth/htpasswd
启动Registry容器
docker run -d -p 5000:5000 --restart=always --name registry.phoenix.com \
-v `pwd`/auth:/auth \
-e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v `pwd`/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
-v /opt/data/registry:/var/lib/registry \
-v /usr/local/docker/config.yml:/etc/docker/registry/config.yml \
registry

       注:最后一行的

registry
:如果不给冒号+tag指定版本(例如registry:2)话,默认使用latest。

参数 解释
-d
容器启动后,在后台运行
--restart=always
--restart
容器重启策略,
always
为自动启动
--name
容器命名
-p
映射端口,前面是本机端口号,后面是容器端口号
-v
映射volume
-e
设置容器的环境变量
-v `pwd`/certs:/certs
映射certs路径
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt
设置容器证书位置
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key
设置容器私钥位置
-v `pwd`/auth:/auth
映射auth路径
-e "REGISTRY_AUTH=htpasswd"
设置容器认证方式为htpasswd
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm"
设置容器htpasswd配置
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd
设置容器htpasswd密码路径

       修改所有client和server的/etc/hosts,将私有镜像仓库的ip-域名对应关系加进去。

docker client安装私有仓库CA证书

       从私有仓库服务器执行,在client创建证书路径:

sudo ssh root@192.168.56.111 mkdir -p /etc/docker/certs.d/registry.phoenix.com:5000

       从私有仓库服务器将证书拷贝到client中:
sudo scp certs/domain.crt root@192.168.56.111:/etc/docker/certs.d/registry.phoenix.com:5000/ca.crt

       安装证书后,client重启Docker Daemon
sudo ssh root@192.168.56.111 service docker restart

       client不安装证书的话,进行pull/push操作,会出现x509: certificate signed by unknown authority的报错。这是因为docker client认为server传输过来的证书的签署方是一个unknown authority(未知的CA),因此验证失败。另外,如果使用自签发的证书,那么所有要与Registry交互的Docker主机都需要安装私有仓库的ca.crt(domain.crt)。

docker client进行私有仓库登录认证

docker login registry.phoenix.com:5000

docker login registry.phoenix.com:5000
Username: username
Password: password
WARNING: login credentials saved in ~/.docker/config.json
Login Succeeded

       不登录直接push镜像的话,会失败,并且出现no basic auth credentials的错误。

推送镜像测试

       把一个本地镜像push到私有仓库中。
       首先,在测试机下pull一个比较小的镜像来测试(此处使用的是hello-world),已存在的话可以跳过pull这一步骤。

docker pull hello-world

       然后,修改一下该镜像的tag。

docker tag hello-world registry.phoenix.com:5000/hello-world

       登录私有镜像仓库。

docker login registry.phoenix.com:5000

       接下来把打了tag的镜像上传到私有仓库。

docker push registry.phoenix.com:5000/hello-world

[root@webserver docker]# docker push registry.phoenix.com:5000/hello-world
The push refers to repository [registry.phoenix.com:5000/hello-world]
af0b15c8625b: Pushed
latest: digest: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a size: 524

       看一下镜像仓库,hello-world已经成功推入仓库中。

[root@webserver docker]# curl -XGET http://registry.phoenix.com:5000/v2/hello-world/tags/list
{"name":"hello-world","tags":["latest"]}[root@webserver docker]# curl -XGET http://registry.phoenix.com:5000/v2/_catalog
{"repositories":["hello-world"]}

       本机/opt/data/registry路径下存储了镜像文件。

[root@webserver docker]# ll /opt/data/registry/ && du -sh /opt/data/registry/
总用量 0
drwxr-xr-x 3 root root 22 6月  28 11:09 docker
32K     /opt/data/registry/

4.查询私有仓库镜像

       目前无法用

docker search/images/image ls
对私有仓库镜像进行查询,可以通过脚本方式直接列出仓库内所有的镜像。
       附:列出私有仓库的镜像的python脚本。

#!/usr/bin/env python
#-*- coding:utf-8 -*-

import requests
import json
import traceback
import sys

repo_ip = sys.argv[1]
repo_port = sys.argv[2]

def getImagesNames(repo_ip,repo_port):
docker_images = []
try:
url = "http://" + repo_ip + ":" + repo_port + "/v2/_catalog"
res =requests.get(url).content.strip()
res_dic = json.loads(res)
images_type = res_dic['repositories']
for i in images_type:
url2 = "http://" + repo_ip + ":" + repo_port +"/v2/" + str(i) + "/tags/list"
res2 =requests.get(url2).content.strip()
res_dic2 = json.loads(res2)
name = res_dic2['name']
tags = res_dic2['tags']
if tags != None:
for tag in tags:
docker_name = str(repo_ip) + ":" + repo_port + "/" + name + ":" + tag
docker_images.append(docker_name)
print(docker_name)
except:
traceback.print_exc()
return docker_images

getImagesNames(repo_ip, repo_port)

       执行:(将仓库地址registry.phoenix.com和端口号5000作为命令行参数)

python list_private_images.py registry.phoenix.com 5000

       输出结果:

[root@webserver ~]# python list_private_images.py registry.phoenix.com 5000
registry.phoenix.com:5000/hello-world:latest
[root@webserver ~]#

5.删除私有仓库镜像

       docker仓库在2.1版本中支持了删除镜像的API,但这个删除操作只会删除镜像元数据,不会删除层数据。在2.4版本中对这一问题进行了解决,增加了一个垃圾回收命令,删除未被引用的层数据。
       查看当前私有镜像库的大小:

[root@webserver ~]# docker exec -ti registry.phoenix.com sh
/ # du  -csh  /var/lib/registry/
32.0K   /var/lib/registry/
32.0K   total
/ #

       查看当前私有镜像库的镜像:

[root@webserver ~]# python list_private_images.py registry.phoenix.com 5000
registry.phoenix.com:5000/hello-world:latest
[root@webserver ~]#
删除镜像

       删除镜像对应的API如下:

DELETE /v2/<name>/manifests/<reference>

参数 解释
name 镜像名称
reference 镜像对应sha256值

       发送请求,删除刚才上传的hello-world镜像(sha256值就是push镜像到私有仓库成功时返回的值):

curl -I -X DELETE http://registry.phoenix.com:5000/v2/hello-world/manifests/sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a

       执行结果:

[root@webserver ~]# curl -I -X DELETE http://registry.phoenix.com:5000/v2/hello-world/manifests/sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899aHTTP/1.1 202 Accepted
Docker-Distribution-Api-Version: registry/2.0
X-Content-Type-Options: nosniff
Date: Fri, 28 Jun 2019 04:25:27 GMT
Content-Length: 0

[root@webserver ~]#

       此时查看私有镜像仓库中是否还存在hello-word镜像:

[root@webserver ~]# curl -XGET http://registry.phoenix.com:5000/v2/hello-world/tags/list
{"name":"hello-world","tags":null}
[root@webserver ~]# curl -XGET http://registry.phoenix.com:5000/v2/_catalog
{"repositories":["hello-world"]}
[root@webserver ~]#

       之前查询时显示为:

{"name":"hello-world","tags":["latest"]}

       可以看到hello-world的tags发生了变化。
       此时镜像索引已经被删除。
       再查看一下镜像存储空间大小:

[root@webserver ~]# docker exec -ti registry.phoenix.com sh
/ # du  -csh  /var/lib/registry/
20.0K   /var/lib/registry/
20.0K   total
/ #

       容量从32k变为20k,删除命令只删除了元数据。

垃圾回收

       执行容器垃圾回收命令:

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

       执行结果:

[root@webserver ~]# docker exec -ti registry.phoenix.com sh
/ #
/ # registry garbage-collect /etc/docker/registry/config.yml
hello-world

0 blobs marked, 3 blobs and 0 manifests eligible for deletion
blob eligible for deletion: sha256:1b930d010525941c1d56ec53b97bd057a67ae1865eebf042686d2a2d18271ced
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/1b/1b930d010525941c1d56ec53b97bd057a67ae1865eebf042686d2a2d18271ced  go.version=go1.11.2 instance.id=93bd6586-dbca-4fc9-96b8-66f62bbd72b7 service=registry
blob eligible for deletion: sha256:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/92/92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a  go.version=go1.11.2 instance.id=93bd6586-dbca-4fc9-96b8-66f62bbd72b7 service=registry
blob eligible for deletion: sha256:fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e
INFO[0000] Deleting blob: /docker/registry/v2/blobs/sha256/fc/fce289e99eb9bca977dae136fbe2a82b6b7d4c372474c9235adc1741675f587e  go.version=go1.11.2 instance.id=93bd6586-dbca-4fc9-96b8-66f62bbd72b7 service=registry
/ #

       再查看一下镜像存储空间大小:

[root@webserver ~]# docker exec -ti registry.phoenix.com sh
/ # du  -csh  /var/lib/registry/
8.0K    /var/lib/registry/
8.0K    total
/ #

       可以看到镜像层数据已被删除。

疑问:如果push镜像时忘了留存生成的sha256值日志,那么又该如何删除呢?

参考:执酒:centos7 Docker私有仓库搭建及删除镜像
参考:silenceboy:docker搭建私有仓库、自签发证书、登录认证

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: