zoukankan      html  css  js  c++  java
  • Docker:搭建私有仓库(Registry 2.4)

    一、背景

    首先,Docker Hub是一个很好的用于管理公共镜像的地方,我们可以在上面找到想要的镜像(Docker Hub的下载量已经达到数亿次);而且我们也可以把自己的镜像推送上去。但是,有的时候,使用场景需要我们有一个私有的镜像仓库用于管理自己的镜像,这个时候我们就通过Registry来实现此目的。本文详细介绍了本地镜像仓库Docker Registry & Portus的搭建过程。

    Registry作为Docker的核心组件之一负责镜像内容的存储与分发,客户端的docker pull以及push命令都将直接与registry进行交互。最初版本的registry 由Python实现。由于设计初期在安全性,性能以及API的设计上有着诸多的缺陷,该版本在0.9之后停止了开发,新的项目distribution(新的docker register被称为Distribution,你可以在这里找到文档 。)来重新设计并开发下一代registry。新的项目由go语言开发,所有的API,底层存储方式,系统架构都进行了全面的重新设计已解决上一代registry中存在的问题。2016年4月份rgistry 2.0正式发布,docker 1.6版本开始支持registry 2.0,而八月份随着docker 1.8 发布,docker hub正式启用2.1版本registry全面替代之前版本 registry。新版registry对镜像存储格式进行了重新设计并和旧版不兼容,docker 1.5和之前的版本无法读取2.0的镜像。

    另外,Registry 2.4版本之后支持了回收站机制,也就是可以删除镜像了。在2.4版本之前是无法支持删除镜像的,所以如果你要使用最好是大于Registry 2.4版本的。

    二、Registry V2的变化

    Docker build镜像时会为每个layer生成一串layer id,这个layer id是一个客户端随机生成的字符串,和镜像内容无关。我们可以通过一个简单的例子来查看。提供一个简单的dockerfile。

    加上–no-cache强制重新build。

    接下来再次build。

    可以看到使用cache层的layer id一致,其余layer的id都发生了变化。这种随机layer id以及layer id与内容无关的设计会带来很多的问题。

    首先, registry v1通过id来判断镜像是否存在,客户需不需要重新push,而由于镜像内容和id无关,再重新build后layer在内容不变的情况下很可能id发生变化,造成无法利用registry中已有layer反复push相同内容。服务器端也会有重复存储造成空间浪费。

    其次,尽管id由32字节组成但是依然存在id碰撞的可能,在存在相同id的情况下,后一个layer由于id和仓库中已有layer相同无法被push到registry中,导致数据的丢失。用户也可以通过这个方法来探测某个id是否存在。

    最后,同样是由于这个原因如果程序恶意伪造大量layer push到registry中占位会导致新的layer无法被push到registry中。Docker官方重新设计新版registry的一个主要原因也就是为了解决该问题。

    新版的registry吸取了旧版的教训,在服务器端会对镜像内容进行哈希,通过内容的哈希值来判断layer在registry中是否存在,是否需要重新传输。这个新版本中的哈希值被称为digest是一个和镜像内容相关的字符串,相同的内容会生成相同的digest。由于digest和内容相关,因此只要重新build的内容相同理论上讲无需重新push,但是由于安全性的考量在特定情况下layer依然要重新传输。由于layer是按digest进行存储,相对v1按照随机id存储可以大幅减小磁盘空间占用。registry服务端会对冲突digest进一步进行处理,同时由于digest是由registry服务端生成,用户无法伪造digest也很大程度上保证了registry内容的安全性。

    1)安全性改进

    除了对image内容进行唯一性哈希外,新版registry还在鉴权方式以及layer权限上上进行了大幅度调整。鉴权方式:

    旧版本的服务鉴权模型如下图所示:

    Docker:搭建私有仓库(Registry 2.4)

    该模型每次client端和registry的交互都要多次和index打交道,新版本的鉴权模型去除了上图中的第四第五步,如下图所示:

    Docker:搭建私有仓库(Registry 2.4)

    新版本的鉴权模型需要registry和authorization service在部署时分别配置好彼此的信息,并将对方信息作为生成token的字符串,已减少后续的交互操作。新模型客户端只需要和authorization service进行一次交互获得对应token即可和registry进行交互,减少了复杂的流程。同时registry和authorization service一一对应的方式也降低了被攻击的可能。

    2)权限控制

    旧版的registry中对layer没有任何权限控制,所有的权限相关内容都由index完成。在新版registry中加入了对layer的权限控制,每个layer都有一个manifest来标识该layer由哪些repository共享,将权限做到repository级别。

    3)Pull性能改进

    旧版registry中镜像的每个layer都包含一个ancestry的json文件包含了父亲layer的信息,因此当我们pull镜像时需要串行下载,下载完一个layer后才知道下一个layer的id是多少再去下载。如下图所示:

    Docker:搭建私有仓库(Registry 2.4)

    新版registry在image的manifest中包含了所有layer的信息,客户端可以并行下载所有的layer如下图所示:

    Docker:搭建私有仓库(Registry 2.4)

    4)其他改进

    – 全新的API。

    – push和pull支持断点。

    – 后端存储的插件。

    – notification机制。

    – 支持删除镜像,有了回收站机制。

    三、安装配置Registry

    直接下载registry

    v2.4.1的registry是把image文件放到了/var/lib/registry下。

    最简单方式启动,启动一个registry是很容易的,如下:

    --name :指定容器名称。

    --privileged=true :CentOS7中的安全模块selinux把权限禁掉了,参数给容器加特权,不加上传镜像会报权限错误。

    这里指定了一个/var/lib/registry的卷,是为了把真实的镜像数据储存在主机上,而别在容器挂掉之后丢失数据。就算这样,也还是不保险。要是主机挂了呢?Docker官方建议可以放到ceph 、 swift这样的存储里,或是亚马逊S3 、微软Azure 、谷歌GCS 、阿里云OSS之类的云商那里。Docker registry提供了配置文件,可以从容器里复制出来查看:

    配置文件里有一个storage ,按照这里写的配置,然后执行以下命令重新挂载这个文件来启动registry就可以了,有条件的话可以去试一试:

    Docker Registry配置完了,然后可以在本机通过docker push 127.0.0.1:5000/xxx的方式推送镜像到registry中(推送镜像必须使用docker images可查看)。

    但是只能在本地使用127.0.0.1进行推送,不能在其他主机push镜像,包括本机通过IP地址也不可以推送镜像。当在其他主机或者在本机通过IP推送镜像时,docker默认会认为地址是HTTPS加密的,而实际上我们启动registry时并没有加密,所以会报错。如下:

    解决方案:

    第一种:在需要推送镜像的服务器上修改dockerd启动参数【官方资料】,然后重启docker。再推送镜像时就会认为这个地址是HTTP,不会报错了,但在每一台主机添加这个配置是很麻烦和危险的。另外我参照官方的做法和网上的做法根本没有办法解决。后来就在网上翻了很久找到了一个解决办法,在docker host端的/etc/docker目录下添加一个daemon.json文件,内容如下:

    然后重启docker,就OK了。

    如果有多个地址,可以这么写。

    再次PUSH镜像就成功了。

    第二种:自建证书,让register以TLS的方式启动,【官方资料】。

    1. 创建你自己的CA证书

    2. 生成证书签名请求

    如果使用像dockerhub.ywnds.com这样的FQDN连接register主机,则必须使用dockerhub.ywnds.com作为CN(通用名称)。否则,如果你使用IP地址连接你的register主机,CN可以是任何类似你的名字等等:

    3. 生成register主机的证书

    如果你使用的是像dockerhub.ywnds.com这样的FQDN来连接您的register主机,请运行以下命令以生成register主机的证书:

    如果你使用的是IP,比如你的register主机10.99.73.10,你可以运行下面的命令生成证书:

    启动register:

    启动后访问会报错:certificate signed by unknown authority,因为这是个自签名的证书(没有经过CA签证的)。docker在验证TLS时会自动读取这个目录下的证书。然后重启docker即可。

    解决方案是将刚生成的docker.crt复制到客户端/etc/docker/certs.d/${registry}:${port}/ca.crt(${registry}是域名或你的register主机IP),如果该目录不存在,请创建它。客户端操作如下,需要把此证书复制到客户端即可(更名为ca.crt),操作如下:

    此时再push就ok了,如下:

    如果报cannot validate certificate for 10.99.73.10 because it doesn’t contain any IP SANs错误,检查一下ca.crt证书是否正确,以及生成register主机的证书的时候使用的是域名还是IP,其方式是否正确。

    问题解决。至此, docker registry私有仓库安装成功。但是还是有些缺点:只要有了证书,还是谁都可以往库里推镜像。简单的解决方案就是使用用户认证。

    四、操作Registry镜像

    下面都是以http方式访问,如果你加了证书就需要使用https进行访问了。

    1)列出当前所有镜像

    2)列出当前指定镜像

    3)搜索镜像

    4)确认Registry是否正常工作

    返回{}就表示正常工作。

    5)删除镜像

    Docker仓库在2.1版本中支持了删除镜像的API,但这个删除操作只会删除镜像元数据,不会删除层数据。在2.4版本中对这一问题进行了解决,增加了一个垃圾回收命令,删除未被引用的层数据。但有一些条件限制,具体操作步骤如下:

    启动仓库容器

    这里需要说明一点,在启动仓库时,需在配置文件中的storage配置中增加delete=true配置项,允许删除镜像,本次试验采用如下配置文件:

    查看数据进行仓库容器中,通过du命令查看大小,可以看到当前仓库数据大小为339M。

    删除镜像对应的API如下:

    name:镜像名称。

    reference:镜像对应sha256值。

    首先查看要删除镜像的sha256

    进行删除操作

    执行垃圾回收

    命令:registry garbage-collect config.yml

    再看数据大小

    可以看到镜像数据已被删除,从339M变成了88K。

    PS:尝试过直接在目录中把镜像删除,然后重启docker daemon,此镜像也会删除。

    下载镜像

    PS:注意后面还可以跟上tags,默认就是latest。

    五、用户认证

    首先在registry生成用户名hello和密码world:

    还得指定认证方式和认证文件等参数,重新启动registry容器:

    再次push就会失败啦。

    但是我们可以用用户名hello和密码world登录,然后在进行push:

    登录成功后,再次push就会成功了。如果想退出登录,使用logout即可。

    Docker私有仓库到这里就结束了,个人感觉还是有很多不足。有兴趣可以看看:

    喜欢 (16)or分享 (1)
  • 相关阅读:
    pycharm快捷键及一些常用设置
    常用笔记
    python开发之路day01
    [转]C++ Unicode SBCS 函数对照表
    PB15151793+PB16001775
    《梦断代码》读书笔记——第四周
    《人件》读书笔记——第三周
    《人月神话》读书笔记——第一周
    软件工程个人作业——词频统计
    《创新者》读书笔记——第五周读书笔记
  • 原文地址:https://www.cnblogs.com/cheyunhua/p/8465815.html
Copyright © 2011-2022 走看看