背景:最近基于 Drone 搭建了用于公司内部使用的 CI/CD 平台,而 CI/CD 过程中生成的 Docker Image 需要能够进行集中式的存储和管理 (即:pushpulldelete 等),且不能将其上传到公网环境中去,因此,有必要自己动手搭建 Docker Private Registry 完成镜像的存储与分发任务。当然,仓库搭建完成后,能够可视化的管理也就很有必要了,像浏览 Docker Hub 一样…

应用逻辑图

Step 1: 选择合适的镜像

Docker Private Registry Image

Used Official Image: Docker Registry V2

  • docker pull registry:2.6.2

Recommend reading before you start:

Docker Registry Web UI

My Decision

1
2
Docker Registry:        docker pull registry:2.6.2
Docker Registry UI:     docker pull parabuzzle/craneoperator:2.2.5

Step 2: 部署 Docker Registry Server & Registry UI

环境

机器:CentOS-7-x86_64

host port description docker image
10.0.0.69 5000 Registry Server registry:2.6.2
10.0.0.69 5001 Registry Web UI parabuzzle/craneoperator:2.2.5

部署

Ref to Official Docs

Note:

  • 安装采用的是 HTTPS 方式,因此需要证书,获取方式会在下面介绍
  • 容器服务管理和组织采用的是 docker-compose
  • 创建相关数据存放目录

    1
    2
    3
    4
    5
    6
    7
    8
    
    $ mkdir -p /home/docker/registry
    $ cd /home/docker/registry
    $ mkdir data certs auth
        
    # Note: 
    #   data:   存放 registry 数据
    #   certs:  存放证书文件
    #   auth:   存放认证参数(登陆验证)
    • 获取证书

    官方文档:Get a certificate:即,需要得到两个文件: xxx.crtxxx.key

    Note

    • 这里采用的证书是腾讯云自己提供的 DV SSL 免费一年的证书
    • 配置证书

    将获取到的证书命名为:domain.crt、domain.key

    拷贝证书到 /home/docker/registry/certs 目录下

    • 配置密码
    1
    2
    
    $ cd /home/docker/registry
    $ docker run --entrypoint htpasswd registry:2.6.2 -Bbn <username> <password> > auth/htpasswd
  • 配置 docker-compose.yml

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    
    version: "3"
    services:
    
      registry-web: # Registry Web UI
        restart: always
        image: parabuzzle/craneoperator:2.2.5
        container_name: registry-web
        ports: 
          - 5001:80
        depends_on:
          - registry
        environment:
          REGISTRY_HOST: <__input_your_domain_or_ip__>
          REGISTRY_PORT: 5000
          REGISTRY_USERNAME: <__input_your_username__>
          REGISTRY_PASSWORD: <__input_your_password__>
          REGISTRY_PROTOCOL: https
          SSL_VERIFY: "true"
          ALLOW_REGISTRY_LOGI: "true"
          REGISTRY_ALLOW_DELETE: "true"
          
      registry:     # Priavate Registry Server
        restart: always
        image: registry:2.6.2
        container_name: registry
        ports:
          - 5000:5000
        environment:
          REGISTRY_HTTP_TLS_CERTIFICATE: /certs/domain.crt
          REGISTRY_HTTP_TLS_KEY: /certs/domain.key
          REGISTRY_AUTH: htpasswd
          REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
          REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
          REGISTRY_STORAGE_DELETE_ENABLED: "true"
              
        volumes:
          - /home/docker/registry/data:/var/lib/registry
          - /home/docker/registry/certs:/certs
          - /home/docker/registry/auth:/auth
    • 启动服务
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    $ cd /home/docker/registry
    
    # 在后台启动服务
    $ docker-compose up -d
        
    # 停止服务:停止容器,并移除 up 指令生成的 containers, networks, volumes and images
    $ docker-compose down
    
    # 重启服务
    $ docker-compose restart

测试

登陆服务

首先在命令行执行 docker login 登陆我们刚刚启动的 Docker Private Registry Server, 用户名和密码则写在 配置密码 步骤时设置的值。

1
2
3
4
5
6
Usage:	docker login [OPTIONS] [SERVER]
Log in to a Docker registry
Options:
-p, --password string   Password
    --password-stdin    Take the password from stdin
-u, --username string   Username
1
2
3
4
$ docker login <REGISTRY_HOST>:<REGISTRY_PORT>
#
# 输入安装时设定的用户名密码
#

发布镜像

发布镜像可以从 Docker Hub 拉去然后,上传到私有仓库去;或者通过 Dockerfile 自行构建(build)得到, 然后通过 docker tag 设定好镜像的目标地址后 push 即可完成发布。

  • 目标地址:镜像的目标地址包括三部分:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    <HOST_NAME>[:<HOST_PORT>]/[IMAGE_NAME]:<IMAGE_VERSION>
        
    # HOST_NAME:HOST_PORT
    #   - 目标 registry 服务地址,缺省时使用官方 docker hub 的地址 registry-1.docker.io,且不允许包含下划线
    # 
    # IMAGE_NAME
    #   - 发布目标镜像名称
    #
    # IMAGE_VERSION
    #   - 发布目标镜像版本
    #
    # 例如:repo.company.com:5000/myapp:0.1.2
    • 发布镜像:
    1
    2
    3
    4
    5
    
    $ docker pull hello-world
    $ docker tag hello-world:<tag> <your_domain>:5000/hello-world:0.0.1
    $ docker tag hello-world:<tag> <your_domain>:5000/hello-world:0.0.2
    $ docker push <your_domain>:5000/hello-world:0.0.1
    $ docker push <your_domain>:5000/hello-world:0.0.2

    刷新 <_your_domain_>:5001, 就可以看到刚刚 Push 的 Docker Images 了

  • 从私库中获取:

    1
    
    docker pull <your_domain>:5000/hello-world:0.0.2

    Step 3: 集成到 Drone CI 系统 (Optional)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    image:    # Build image and publish to private registry
    image: plugins/docker                           # Drone Plugins: Docker 用于构建 Docker 镜像
    repo: <__Your_Domain__>:5000/go-app             # 私有仓库名称
    registry: <__Your_Domain__>:5000                # 私有仓库地址
    secrets: [ docker_username, docker_password ]   # Registry 服务登陆密码,在 Drone Web 端配置
    context: ./cicd/                                # docker build 构建的上下文环境
    dockerfile: ./cicd/Dockerfile                   # Dockerfile 文件地址
    default_tags: true                              # 由 Docker Plugins 自动添加标签
    when:                                           # 触发事件为: 有 tag 提交时,执行该流程
    event: tag        

Note: 在 Drone CI 中配置好 Pipeline ,当触发执行后会自动向 Docker Registry Server 发布该 tag 版本的一个镜像

See Also

Thanks to the authors 🙂