搭建registry mirror


Docker registry是专门用于存放docker镜像的,docker官方提供了docker hub,是全球最大的docker镜像存储中心。但是在中国既没有服务器也没有CDN,所以导致pull镜像特别的慢,而且很不稳定。解决这个问题的方式一般有两种:

  1. 搭建自己私有的docker registry,存储镜像,并定期同步官方常用的镜像。
  2. 搭建docker mirror。

其实,选用哪一种或者both主要取决于自己的使用场景。如果你想要一个类似docker hub的私有registry,那肯定是第一种。如果你只是想解决从docker hub拉取镜像慢的问题,那就选择第二种,因为第一种的维护成本比较高。当然,不管是哪一种,我们都可以使用docker官方开源的registry镜像去实现。如果你想部署私有的registry,可以关注一下VMware开源的Harbor项目,其在开源registry的基础上增加了一些实际应用场景中需要的一些特性,比如项目权限、角色管理等。本文介绍如何使用部署registry mirror。

在这之前,需要强调一下目前如果registry部署为mirror方式,将只能pull镜像而不能push镜像

registry mirror原理

Docker Hub的镜像数据分为两部分:index数据和registry数据。前者保存了镜像的一些元数据信息,数据量很小;后者保存了镜像的实际数据,数据量比较大。平时我们使用docker pull命令拉取一个镜像时的过程是:先去index获取镜像的一些元数据,然后再去registry获取镜像数据。

所谓registry mirror就是搭建一个registry,然后将docker hub的registry数据缓存到自己本地的registry。整个过程是:当我们使用docker pull去拉镜像的时候,会先从我们本地的registry mirror去获取镜像数据,如果不存在,registry mirror会先从docker hub的registry拉取数据进行缓存,再传给我们。而且整个过程是流式的,registry mirror并不会等全部缓存完再给我们传,而且边缓存边给客户端传。

对于缓存,我们都知道一致性非常重要。registry mirror与docker官方保持一致的方法是:registry mirror只是缓存了docker hub的registry数据,并不缓存index数据。所以我们pull镜像的时候会先连docker hub的index获取镜像的元数据,如果我们registry mirror里面有该镜像的缓存,且数据与从index处获取到的元数据一致,则从registry mirror拉取;如果我们的registry mirror有该镜像的缓存,但数据与index处获取的元数据不一致,或者根本就没有该镜像的缓存,则先从docker hub的registry缓存或者更新数据。

registry mirror的工作原理我们就介绍完了,下面介绍如何利用docker开源的registry镜像部署自己的registry mirror。

registry mirror部署

NB:假设我们将缓存的数据存放到/data目录。

  1. 从官方拉取registry的镜像,目前最新的registry镜像是2.5版本(我使用的是2.5.0)。
  2. 获取registry的默认配置:

    docker run -it --rm --entrypoint cat registry:2.5.0  /etc/docker/registry/config.yml > config.yml

    文件的内容大概是下面这样:

    version: 0.1
    log:
      fields:
        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

    我们在最后面加上如下配置:

    proxy:
      remoteurl: https://registry-1.docker.io
      username: [username]
      password: [password]

    usernamepassword是可选的,如果配置了的话,那registry mirror除了可以缓存所有的公共镜像外,也可以访问这个用户所有的私有镜像。

  3. 启动registry容器:

    docker run  --restart=always -p 5000:5000 --name v2-mirror -v /data:/var/lib/registry -v  $PWD/config.yml:/etc/registry/config.yml registry:2.5.0 /etc/registry/config.yml

    当然我们也可以使用docker-compose启动:

    version: '2'
    services:
      registry:
        image: library/registry:2.5.0
        container_name: registry_mirror
        restart: always
        volumes:
          - /data:/var/lib/registry
          - ./config.yml:/etc/registry/config.yml
        ports:
          - 5000:5000
        command:
          ["serve", "/etc/registry/config.yml"]

    当我们看到如下日志输出的时候就说明已经启动成功了:

    time="2016-12-19T14:22:35Z" level=warning msg="No HTTP secret provided - generated random secret. This may cause problems with uploads if multiple registries are behind a load-balancer. To provide a shared secret, fill in http.secret in the configuration file or set the REGISTRY_HTTP_SECRET environment variable." go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0
    time="2016-12-19T14:22:35Z" level=info msg="redis not configured" go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0
    time="2016-12-19T14:22:35Z" level=info msg="Starting upload purge in 39m0s" go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0
    time="2016-12-19T14:22:35Z" level=info msg="using inmemory blob descriptor cache" go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0
    time="2016-12-19T14:22:35Z" level=info msg="Starting cached object TTL expiration scheduler..." go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0
    time="2016-12-19T14:22:35Z" level=info msg="Registry configured as a proxy cache to https://registry-1.docker.io" go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0
    time="2016-12-19T14:22:35Z" level=info msg="listening on [::]:5000" go.version=go1.6.3 instance.id=da5468c4-1ee1-4df2-95cf-1336127c87bb version=v2.5.0

至此,registrymirror就算部署完了。我们也可以用curl验证一下服务是否启动OK:

curl -I http://registrycache.example.com:5000/v2/
HTTP/1.1 200 OK
Content-Length: 2
Content-Type: application/json; charset=utf-8
Docker-Distribution-Api-Version: registry/2.0
Date: Thu, 17 Sep 2015 21:42:02 GMT

registry mirror使用

要使用registry mirror,我们需要配置一下自己的docker daemon。

对于Mac:在docker的客户端的Preferences——>Advanced——>Registry mirrors里面添加你的地址,然后重启。

对于Ubuntu 14.04:在/etc/default/docker文件中添加DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=http://registrycache.example.com:5000”,然后重启docker(services docker restart)。

其他系统和发行版的配置方法请Google之。

然后我们pull一个本地不存在的镜像,这时去查看registry mirror服务器的data目录下面已经有了数据。执行如下命令也可以看到效果:

curl https://mycache.example.com:5000/v2/library/busybox/tags/list

需要说明的是缓存的镜像的有效期默认是一周(168hour),而且如果registry被配置成mirror模式,这个时间是不能通过maintenance部分来改变的:

  maintenance:
    uploadpurging:
      enabled: true
      age: 168h
      interval: 24h
      dryrun: false
    readonly:
      enabled: false

我研究了好久发现怎么改都不能生效,最后发现mirror模式下这个时间竟然在registry的代码里面写死了:

// todo(richardscothern): from cache control header or config
const repositoryTTL = time.Duration(24 * 7 * time.Hour)

囧o(╯□╰)o~不过看这TODO,应该是后面会改的~

当然如果你想你的registry mirror是https的话,在config.yml的http部分增加tls配置即可:

   http:
      addr: :5000
      headers:
        X-Content-Type-Options: [nosniff]
      tls:
        certificate: /etc/registry/domain.crt
        key: /etc/registry/domain.key

OK,至此registry mirror就介绍完了。


本文由时间轨迹创作,转载请注明链接。
赞赏


微信赞赏

支付宝赞赏

已有 5 条评论

  1. bubble

    我部署registry镜像遇到个问题,只有library/xxxxx这样的镜像能pull下来,其他的社区镜像,比如microsoft/dotnet 这种镜像死活pull不下来,不知道是什么问题,求大神指点。

    bubble 回复
    1. 时间轨迹
      @bubble

      死活pull不下来最大的两种可能是:1. 镜像不存在。2. 网络问题,比如google镜像仓库的国内没梯子就pull不下来。所以,你可以先单独docker pull一下,看是是哪个问题。我估计可能是网络问题。

      时间轨迹 博主 回复
      1. bubble
        @时间轨迹

        可能是我没说明白吧。我的意思registry镜像模式下,docker官方的镜像,比如library目录的镜像,如(nginx,mysql,mariadb,node .etc)等没问题,但是社区镜像,例如微软旗下的microsoft,比如gitlab的gitlab,他们的镜像都无法pull。
        另外,我的registry的上游设置的是registry.docker-cn.com

        bubble 回复
        1. 时间轨迹
          @bubble

          哦,这样啊。那从registry.docker-cn.com直接拉能拉下来吗(直接把本地镜像库设置成这个)?如果也不行,那就和你搭建方式没关系了。如果可以,那就看下你registry的日志,看下拉microsoft/dotnet之类镜像的时候有没有什么错误日志。

          时间轨迹 博主 回复
    2. bubble
      @bubble

      ps: 我用的是harbor
      registry配置如下

      version: 0.1
      log:
        level: info
        fields:
          service: registry
      storage:
        cache:
          layerinfo: inmemory
        filesystem:
          rootdirectory: /storage
        maintenance:
          uploadpurging:
            enabled: false
        delete:
          enabled: true
      http:
        addr: :5000
        secret: placeholder
        debug:
          addr: localhost:5001
      auth:
        token:
          issuer: harbor-token-issuer
          realm: https://registry.mydomain.com/service/token
          rootcertbundle: /etc/registry/root.crt
          service: harbor-registry
      notifications:
        endpoints:
        - name: harbor
          disabled: false
          url: http://ui:8080/service/notifications
          timeout: 3000ms
          threshold: 5
          backoff: 1s
      proxy:
        #remoteurl: https://hub-mirror.c.163.com
        remoteurl: https://registry.docker-cn.com
      
      bubble 回复

添加新评论

选择表情 captcha

友情提醒:不填或错填验证码会引起页面刷新,导致已填的评论内容丢失。

|