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:fields:service: registry
storage:cache:blobdescriptor: inmemoryfilesystem:rootdirectory: /var/lib/registry
http:addr: :5000headers:X-Content-Type-Options: [nosniff]
health:storagedriver:enabled: trueinterval: 10sthreshold: 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: truecache:blobdescriptor: inmemoryfilesystem:rootdirectory: /var/lib/registry
http:addr: :5000headers:X-Content-Type-Options: [nosniff]
health:storagedriver:enabled: trueinterval: 10sthreshold: 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 sysrepo_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 + ":" + tagdocker_images.append(docker_name)print(docker_name)except:traceback.print_exc()return docker_imagesgetImagesNames(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:92c7f9c92844bbbb5d0a101b22f7c2a7949e40f8ea90c8b3bc396879d95e899a
HTTP/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-world0 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创建私有镜像仓库(配置启动http和https方式私有仓库服务,查询、删除私有仓库镜像)相关推荐

  1. 一文搞定Docker(内含docker-compose及docker核心原理)

    01-Docker概述 Docker简介 Docker是基于Go语言实现的云开源项目. Docker的主要目标是: Build, Ship and Run Any App, Anywhere ,也就是 ...

  2. 一文搞定 Docker 容器技术与常用命令

    简介:Docker 是一个开源的应用容器引擎,基于 Go 语言开发,Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的系统. Docker 简介 Do ...

  3. Docker 概念很难理解?一文搞定 Docker 端口绑定

    作者 | Dieter Jordens 译者 | 苏本如,责编 | 夕颜 出品 | CSDN(ID:CSDNnews) 以下为译文: 作为初级开发人员的你,是不是参加过这样的面试,在面试中面试官希望你 ...

  4. 一文搞定 Docker 入门

  5. 一文搞定深度学习入门级电脑硬件配置

    对于刚接触深度学习的学友而言,可能都会碰到电脑配置的问题,比如显卡型号.内存容量.处理器型号等.好的电脑配置,比如GPU加速的显卡,是能够有效缩短算法的训练时间的,这能让人尽快的看到算法的结果,也便于 ...

  6. 一文搞定Swing和Qt按钮和文本框的创建

    一文搞定Swing和Qt按钮和文本框的创建 Qt的截图 java的 源码 package com.lujun;import java.awt.Container;import javax.swing. ...

  7. 【嵌入式开发-AD19】六文搞定Altium Designer-第一章:AD介绍及原理图库的创建

    [嵌入式开发-AD19]六文搞定Altium Designer-第一章:AD介绍及原理图库的创建 在文章的开头我想首先简单介绍一下国产全免费EDA软件,嘉立创EDA.嘉立创EDA拥有网页版和安装版两种 ...

  8. 一文搞定面试中的二叉树问题

    一文搞定面试中的二叉树问题 版权所有,转载请注明出处,谢谢! http://blog.csdn.net/walkinginthewind/article/details/7518888 树是一种比较重 ...

  9. 一文搞定Matplotlib 各个示例丨建议收藏

    摘要:Matplotlib 是 Python 的绘图库. 它可与 NumPy 一起使用 ,Matplotlib也是深度学习的常用绘图库,主要是将训练的成果进行图形化,因为这样更直观,更方便发现训练中的 ...

最新文章

  1. QIIME 2教程. 24Python命令行模式Artifact API(2021.2)
  2. 函数 —— strtok() 例如:按照字符拆分字符串,放入新定义的数组中;按照字符拆分字符串,放入原先的数组中
  3. [YTU]_2907 (类重载实现矩阵加法)
  4. boost::foreach模块非常量右值的测试程序
  5. 支付宝研究员王益的建议:“学好语文,才能写好代码”
  6. mysql innodb redolog_Mysql的binlog 和InnoDB的redo-log
  7. getwayworker timer_Java定时器之Timer学习二
  8. Java之品优购部署_day01(10)
  9. android.mk if else,gradle - 如何在Android Studio中使用我自己的Android.mk文件 - SO中文参考 - www.soinside.com...
  10. Document/View 模式下的窗口重绘
  11. Fragment真正的完全解析(上)
  12. 已分区的硬盘如何重新合并, 分出去的盘怎么重新合并
  13. 无法安装网络计算机加密,非系统分区使用BitLocker加密导致软件无法安装的解决方法...
  14. Unity打包后窗口在PC端不按照设置的大小显示
  15. Arthas Spring Boot Starter工程启动报错
  16. 余弦于相似度cos similarity
  17. linux串口文件传输工具
  18. android平板忘了密码,平板电脑忘记密码怎么办
  19. Shader攻占笔记(八)屏幕特效
  20. (PC+WAP)织梦模板财税记账工商注册认证类网站

热门文章

  1. 飞机票网上订票系统javabean+jsp+mysql
  2. chrome浏览器背景颜色设置
  3. 怎么将短视频合并成一个视频的方法
  4. 西安宾馆中央空调水系统节能改造-空调改造节能一站式服务公司
  5. 企业常见的纳税信用等级失分项有哪些?
  6. 设计传感器,需要注意哪些问题
  7. 机器人笔记psv中文_机器人笔记精英版
  8. 洛谷 - 一些好玩的问题 2
  9. ROS1云课→03工作空间
  10. PHP使用imap读取邮件内容,2018可用