搭建自己的Docker Registry仓库

本文实验的环境

  • 本地端为自己的Mac笔记本电脑
  • 云端为Ubuntu Server 14.04
  • 本地与云端都需要安装Docker,按照官网文档安装:https://docs.docker.com/engine/installation/

在本地制作Docker镜像

本步骤环境为本地Mac。

编写Dockefile,将我们的python api server打包成一个镜像:

 
$ cd ~/etc/docker/
$ cat Dockerfile
 
FROM alpine:3.5 

RUN apk add --no-cache python && \
    python -m ensurepip && \
    rm -r /usr/lib/python*/ensurepip && \
    pip install --upgrade pip setuptools && \
    rm -r /root/.cache && \
    apk add --no-cache vim py-mysqldb musl-dev linux-headers g++ python-dev libxml2-dev \
    libxml2 libxslt libxslt-dev && \
    ln -s /usr/include/locale.h /usr/include/xlocale.h

##############

COPY VikiQA/requirements.txt /src/
RUN pip install -r /src/requirements.txt

COPY VikiQA /src/VikiQA
COPY VikiAIML /src/VikiAIML
RUN cd /usr/lib/python2.7/site-packages && ln -s /src/VikiQA/viki_qa . && \
    cd /src/VikiQA/viki_qa && cp config_sample.py config.py && \
    mkdir /var/log/viki_qa

WORKDIR /src/VikiQA/viki_qa/

ENTRYPOINT ["/usr/bin/gunicorn", "-k", "tornado", "-b", "0.0.0.0:80", "--workers=4", "viki_qa.wsgi:app"]

然后制作好镜像:

 
$ cd ~/etc/docker/
$ docker build -t kyle/viki_qa .

完成后,可以通过命令查看制作好的镜像:

 
$ docker images
kyle@kyledeMacBook-Pro ~/p/a/VikiDocker> docker images
REPOSITORY                      TAG                 IMAGE ID            CREATED             SIZE
kyle/viki_qa                     latest              5cd56c45db67        27 hours ago        347 MB

在云端运行Docker registry

本步骤环境为云端Ubuntu Server。

假设云端服务器地址为 docker.kyle.ai,在上面安装好docker后,运行registry容器,这里我们用docker-compose来运行。

 
$ cd ~/etc/docker/
$ cat docker-compose.yml 
 
version: '2'

services:

    registry:
        image: registry:2
        restart: always
        ports:
          - 5000:5000
        volumes:
          - /home/deploy/data/docker/registry:/var/lib/registry
#          - /home/deploy/etc/docker/cert/:/certs
#          - /home/deploy/etc/docker/auth/:/auth
#        environment:
#          REGISTRY_HTTP_TLS_CERTIFICATE: /certs/214053375670003.pem
#          REGISTRY_HTTP_TLS_KEY: /certs/214053375670003.key
#          REGISTRY_AUTH: htpasswd
#          REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
#          REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
        container_name: registry

解释一下,就是在本地运行registry窗口服务,端口号为5000,并把仓库的文件数据持久化到本地磁盘 /home/deploy/data/docker/registry 。

注释的那些行,是用来配置使用auth认证与ssl证书的,但由于我们使用nginx来做这个事情,所以docker registry服务就不用了。不能nginx与registry同时配置这两个,不然会访问不成功。

然后把容器运行起来

 
$ cd ~/etc/docker/
$ sudo docker-compose up -d
$ sudo docker-compose ps
  Name                Command               State           Ports          
--------------------------------------------------------------------------
registry   /entrypoint.sh /etc/docker ...   Up      0.0.0.0:5000->5000/tcp 

下一步就需要配置nginx,将服务器的80端口转发到registry服务的5000端口,并设置好ssl与auth认证。

nginx配置文件如下:

 
$ cd ~/etc/nginx/sites-enabled/
$ cat docker.kyle.ai
 
server {
    listen 80;
	listen 443 ssl;
    ssl_certificate   /etc/nginx/cert/docker.kyle.ai/ssl.pem;
    ssl_certificate_key  /etc/nginx/cert/docker.kyle.ai/ssl.key;
    ssl_session_timeout 5m;
    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    add_header X-Frame-Options SAMEORIGIN;
    add_header Strict-Transport-Security "max-age=8640000;";
    add_header X-Content-Type-Options: nosniff;

	server_name docker.kyle.ai;
    access_log  /var/log/nginx/docker-access.log;
    error_log  /var/log/nginx/docker-error.log;

    root /home/deploy/www/;
    client_max_body_size 0;      # 不限制上传文件的大小,一个镜像可能有几百M
    chunked_transfer_encoding on;

    if ($ssl_protocol = "") {
        return 302 https://$server_name$request_uri;
    }

	location ^~ / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Scheme $scheme;
	}

	upstream docker_registry{
	    server 127.0.0.1:5000;
	}

    location /v2/ {
        # Do not allow connections from docker 1.5 and earlier
        # docker pre-1.6.0 did not properly set the user agent on ping, catch "Go *" user agents
        if ($http_user_agent ~ "^(docker\/1\.(3|4|5(?!\.[0-9]-dev))|Go ).*$" ) {
            return 404;
        }
        auth_basic "Registry realm";
        auth_basic_user_file /home/deploy/etc/docker/auth/htpasswd;
        add_header 'Docker-Distribution-Api-Version' 'registry/2.0';

        proxy_pass                          http://docker_registry;
        proxy_set_header  Host              $http_host;   # required for docker client's sake
        proxy_set_header  X-Real-IP         $remote_addr; # pass on real client's IP
        proxy_set_header  X-Forwarded-For   $proxy_add_x_forwarded_for;
        proxy_set_header  X-Forwarded-Proto $scheme;
        proxy_read_timeout                  900;
    }

}

ssl证书,我是直接在阿里云申请的免费dv证书,申请地址:https://common-buy.aliyun.com/?commodityCode=cas#/buy

申请成功后,相应的配置 ssl_certificate 与 ssl_certificate_key 文件路径。

然后就是basic auth的用户文件:/home/deploy/etc/docker/auth/htpasswd,可以通过如下命令生成:

 
sudo docker run --entrypoint htpasswd registry:2 -bn username password > htpasswd

注意不要添加-B参数,之前我用的 -Bbn 参数,结果后面nginx会出现如下错误:

 
[crit] 12472#0: *29935 crypt_r() failed (22: Invalid argument)

nginx的这个配置,可能跟nginx版本有关系

 
add_header 'Docker-Distribution-Api-Version' 'registry/2.0'; 

高版本的nginx可能需要在后面添加个 always

 
add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;

配置好nginx后,就可以通过访问api来测试: curl https://docker.kyle.ai/v2 这样,这里我只是用了示例域名,你需要换成你自己的。

将本地的image push到云端的registry

本步骤是在本地Mac系统环境。

上面的步骤中,我们已经成功地在本地build了一个Image,叫 kyle/viki_qa,现在把这个image映射到云端的registry:

 
$ sudo docker tag kyle/viki_qa docker.kyle.ai/kyle/viki_qa

然后 push 到云端:

 
$ sudo docker push docker.kyle.ai/kyle/viki_qa
Error: Status 405 trying to push repository kyle/viki_qa: "<html>\r\n<head><title>405 Not Allowed</title>

报405 Not Allowed的错误, 是由于需要先登陆,还记得我们在上面配置nginx的时候,设置的basic auth的用户与密码,用这个来登陆一下

 
$ sudo docker login docker.kyle.ai
输入密码与密码

之后再push就行了。

在其它机器拉取我们的镜像

直接

 
$ sudo docker pull docker.kyle.ai/kyle/viki_qa
$ sudo docker run -it --rm -d docker.kyle.ai/kyle/viki_qa

其它

删除远程的image比较麻烦,官方没有提供很好的办法。

目前docker官方提供了如下3个软删除的方法:

  • DELETE:/v2//manifests/:这个API是软删除一个清单(manifest),但是真正占用存储空间的层还在。
  • DELETE:/v2//blobs/:这个API类似上面那个,只不过它要软删除的对象是层(layer)罢了。
  • DELETE:/v2//blobs/uploads/:这个只是取消掉另一个上传的进程罢了。