一文搞定docker创建私有镜像仓库(配置启动http和https方式私有仓库服务,查询、删除私有仓库镜像)
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搭建私有仓库、自签发证书、登录认证
- Docker 私有仓库,pull镜像报错:server gave HTTP response to HTTPS client
- Docker 私有仓库,上传镜像报错:server gave HTTP response to HTTPS client
- docker 1.12.3版本搭建私有仓库,上传镜像报错:server gave HTTP response to HTTPS client”
- Docker 私有仓库,上传镜像报错:server gave HTTP response to HTTPS client
- 005-搭建私有仓库,上传镜像报错:server gave HTTP response to HTTPS client
- 【Docker】创建私有仓库, 查看私有仓库镜像, 方便本地共享
- docker 创建新的镜像到私有仓库
- Docker删除私有仓库镜像
- 配置Docker beta for Mac访问私有镜像仓库
- centos7 Docker私有仓库搭建及删除镜像
- 两种方式创建docker镜像的启动容器时区别介绍(总结篇)
- 巧用Docker镜像仓库Harbor部署私有Mirror服务
- 基于Dockerfile的方式创建SSH服务镜像。
- Docker Registry Server 搭建,配置免费HTTPS证书,及拥有权限认证、TLS 的私有仓库
- Docker私有仓库管理,删除本地仓库中的镜像
- docker下载私有仓库镜像失败:Error response from daemon: Get $ip:5000/v2/: http: server gave HTTP response to HT
- docker本地私有仓库的创建,及https错误修正
- 使用Docker registry镜像创建私有仓库的方法
- docker 查询或获取私有仓库(registry)中的镜像
- Docker Registry Server 搭建,配置免费HTTPS证书,及拥有权限认证的私有仓库