前言

Docker不仅是一个强大的服务器部署工具,而且它还有一个官方的Docker Hub registry用于储存Docker镜像。上传镜像到Docker Hub是免费的,上传的镜像文件同时也对公共领域开放,而这可能不是我们想要的。

本文介绍如何配置一个私有的Docker registry,在此上传的镜像是私密的,你可以从另一个联网的主机以安全的方式下载此registry上的镜像。

本文仅介绍registry的创建,而不讨论应用的容器化。有关Docker镜像创建的操作可参考这篇Docker入门文章。

本文在Ubuntu 14.04上实测通过,在其他Debian类系统上应该也可以通过。使用的Docker Registry版本为2.0版。
Docker基本概念

如果你此前尚未用过Docker,那么最好先花几分钟时间了解一下它的基本概念。如果你已经使用过Docker,只想了解建立私有registry部分的内容,则可跳过本小节。

Docker入门者可参阅这篇Docker Cheat Sheet。

Docker的核心理念是应用及其依赖项与其运行环境(操作系统)的分离,这种分离通过容器(containers)和镜像(images)来实现。一个Docker镜像本质上来说就是一个文件系统的模板,运行一个Docker镜像就是在你的系统上的一个Docker容器中运行该文件系统的一个实例。默认来说,该容器是不会接触到最初的那个镜像或者Docker运行环境所处的宿主机上的文件系统:该容器是完全独立的环境。

在容器内部操作进行的变更直接在容器中预存,而不会造成初始镜像的变更;要保存这些变更,需要通过docker commit指令将变更提交给指定的Docker镜像。也就是说,从一个旧的容器,你可以不断的生成新的容器,而旧的那个容器(镜像)永远也不会因为意外而被搞砸。该模式对于Git用户而言应该非常眼熟,这相当于创建新的分支(git branch相当于Docker image),运行一个镜像相当于做一次git checkout。

运用同样的类比,一个私有Docker registry就相当于一个私有的git仓库。
准备工作

完成本教程需要如下准备工作:

两台Ubuntu 14.04的云主机,一台作为私有Docker registry服务器,一台作为Docker客户端。
    两台服务器上都建立具有sudo权限的非root用户(用户建立教程可参考这篇文章)。
    两台服务器上都安装Docker以及Docker Compose(安装教程见此)。
    为私有Docker registry服务器配置好可供客户端访问的域名。

步骤1:安全加固

针对Docker Registry的安全加固,建议使用Docker Compose。如此,我们可以在一个容器内运行Docker Registry,而与外部的通讯安全则交给另一个容器内的Nginx来处理。我们在准备工作中应该已经安装过Docker Compose。

用Nginx来处理通讯安全,则需要将可访问私有registry的用户名和密码的列表保存到一个文件里以供Nginx读取。我们将安装apache2-utils软件包,该软件包下的htpasswd可以很方便的生成一个Nginx可读的密码哈希:

sudo apt-get -y install apache2-utils

步骤2:安装配置Docker Registry

如果你只需要管理一两个Docker容器,那么Docker命令行工具就足够好了。然而,大部分在容器内运行的应用并非是独立运作的,他们需要成组配合才能运行。比如,大部分Web应用都至少需要一个Web服务器用于托管应用代码、一个服务器用于运行PHP/Ruby on Rails等解释脚本语言、一台数据库服务器(如MySQL)。

Docker Compose可以让我们为每一个容器用一个.yml配置文件,该文件不仅可以指定容器的配置项,还可以写入有关该容器如何对外通讯的信息。docker-compose命令行工具可以对应用的各个组件下达指令。

Docker registry本身也是一个由多个组件组成的应用,因此我们将使用Docker Compose对其进行配置管理。

最简单的registry配置就是其存储数据的位置。让我们先来创建一个最基本的Docker Compose YAML文件。

首先,创建一个目录,用于储存本教程将要用到的一些文件:

mkdir ~/docker-registry && cd $_
mkdir data

在该目录下创建一个docker-compose.yml文件:

nano docker-compose.yml

将如下内容复制粘贴到该文件中:

registry:
  image: registry:2
  ports:
    - 127.0.0.1:5000:5000
  environment:
    REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
  volumes:
    - ./data:/data

注意这部分内容:environment: REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data为Docker registry容器设置了一个环境变量路径/data,如此,Docker registry在启动时就会检查这个环境变量,从而将其数据保存到/data路径下。

最后的volumes: - ./data:/data这一段的意思是,容器内的/data路径应该映射到宿主机的./data路径,也就是说Docker registry的数据都会保存到宿主机的~/docker-registry/data目录下。

现在启动Docker Compose:

cd ~/docker-registry
docker-compose up

输入该命令后,你会看到一系列下载进度条,这些是Docker在从官方Registry下载Docker registry镜像文件的下载进度。如果一切顺利,下载应该在一两分钟内完成,最终呈现的输出应该是这样的:

registry_1 | time="2015-10-18T23:45:58Z" 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." instance.id=44c828de-c27a-401e-bb2e-38b17e6a4b7b version=v2.1.1
registry_1 | time="2015-10-18T23:45:58Z" level=info msg="redis not configured" instance.id=44c828de-c27a-401e-bb2e-38b17e6a4b7b version=v2.1.1
registry_1 | time="2015-10-18T23:45:58Z" level=info msg="using inmemory blob descriptor cache" instance.id=44c828de-c27a-401e-bb2e-38b17e6a4b7b version=v2.1.1
registry_1 | time="2015-10-18T23:45:58Z" level=info msg="listening on [::]:5000" instance.id=44c828de-c27a-401e-bb2e-38b17e6a4b7b version=v2.1.1
registry_1 | time="2015-10-18T23:45:58Z" level=info msg="Starting upload purge in 1m0s" instance.id=44c828de-c27a-401e-bb2e-38b17e6a4b7b version=v2.1.1

里面有一条No HTTP secret provided的警告信息,不用在意它。

至此,你的Docker registry已经在运行,监听端口为5000(这个端口可以在docker-compose.yml文件中的ports:部分设置)。不过这个registry现在还用处不大:一方面它需要手动启动,另一方面它还没设置任何身份验证机制所以并不安全。

默认状态下,Docker Compose会一直等待你输入指令。现在我们直接CTRL-C将其关闭退出。
步骤3:设置Nginx容器

现在来解决安全认证的问题。首先我们需要一个Nginx容器,再把它跟刚才的Docker registry容器连接起来。

创建一个新目录用于保存Nginx配置项:

mkdir ~/docker-registry/nginx

打开刚才的docker-compose.yml文件:

nano docker-compose.yml

将下面的内容复制粘贴到文件开头处:

nginx:
  image: "nginx:1.9"
  ports:
    - 5043:443
  links:
    - registry:registry
  volumes:
    - ./nginx/:/etc/nginx/conf.d:ro

这将基于官方Nginx镜像创建一个新的Docker容器。注意这里的links部分,这个功能可以自动建立两个容器之间的连接:当Nginx容器启动时,它将能够直接使用registry这个主机名访问registry容器(无论该容器的IP地址为何。其背后的机制其实是在nginx容器里面的/etc/hosts文件把registry容器的IP自动填写进去)。

volumes:部分跟上面一样,是容器内外路径的映射关系。末尾的:ro意思是只读,即该Nginx容器对宿主机文件系统只有只读权限。

到目前为止,完整的docker-compose.yml文件应该是这样的:

nginx:
  image: "nginx:1.9"
  ports:
    - 5043:443
  links:
    - registry:registry
  volumes:
    - ./nginx/:/etc/nginx/conf.d
registry:
  image: registry:2
  ports:
    - 127.0.0.1:5000:5000
  environment:
    REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
  volumes:
    - ./data:/data

现在如果再次运行docker-compose up,将会启动两个容器:一个Docker registry和一个Nginx。不过我们需要先配置好Nginx。创建一个新的Nginx配置文件registry.conf:

nano ~/docker-registry/nginx/registry.conf

将如下内容复制粘贴进去:

upstream docker-registry {
  server registry:5000;
}

server {
  listen 443;
  server_name myregistrydomain.com;

# SSL
  # ssl on;
  # ssl_certificate /etc/nginx/conf.d/domain.crt;
  # ssl_certificate_key /etc/nginx/conf.d/domain.key;

# disable any limits to avoid HTTP 413 for large image uploads
  client_max_body_size 0;

# required to avoid HTTP 411: see Issue #1486 (https://github.com/docker/docker/issues/1486)
  chunked_transfer_encoding on;

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;
    }

# To add basic authentication to v2 use auth_basic setting plus add_header
    # auth_basic "registry.localhost";
    # auth_basic_user_file /etc/nginx/conf.d/registry.password;
    # add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;

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;
  }
}

保存退出。现在可以启动Docker Compose了:

docker-compose up

Nginx在启动时没有输出信息,不过我们可以用curl来测试一下它是不是已经成功启动并连接至registry。首先用curl发送HTTP请求给registry:

curl http://localhost:5000/v2/

你应该能看到返回的结果——一个空json对象:

{}

现在再给Nginx端口发送HTTP请求:

curl http://localhost:5043/v2/

你应该看到同样的返回结果:

{}

如果一切顺利,在docker-compose的终端能看到如下的输出内容:

registry_1 | time="2015-08-11T10:24:53.746529894Z" level=debug msg="authorizing request" environment=development http.request.host="localhost:5043" http.request.id=55c3e2a6-4f34-4b0b-bc57-11c814b4f4d3 http.request.method=GET http.request.remoteaddr=172.17.42.1 http.request.uri="/v2/" http.request.useragent="curl/7.35.0" instance.id=55634dfc-c9e0-4ec9-9872-6f4930c17759 service=registry version=v2.0.1
    registry_1 | time="2015-08-11T10:24:53.747650205Z" level=info msg="response completed" environment=development http.request.host="localhost:5043" http.request.id=55c3e2a6-4f34-4b0b-bc57-11c814b4f4d3 http.request.method=GET http.request.remoteaddr=172.17.42.1 http.request.uri="/v2/" http.request.useragent="curl/7.35.0" http.response.contenttype="application/json; charset=utf-8" http.response.duration=8.143193ms http.response.status=200 http.response.written=2 instance.id=55634dfc-c9e0-4ec9-9872-6f4930c17759 service=registry version=v2.0.1
    registry_1 | 172.17.0.21 - - [11/Aug/2015:10:24:53 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "curl/7.35.0"
    nginx_1    | 172.17.42.1 - - [11/Aug/2015:10:24:53 +0000] "GET /v2/ HTTP/1.1" 200 2 "-" "curl/7.35.0" "-"

如果你看到registry_这样的前缀(后面的数字不一定是1),则说明一切正常,Nginx已经成功建立了到Docker registry的代理。

CTRL-C退出,准备进行下一步操作。
步骤4:设置验证信息

现在我们需要让Nginx验证访问Docker registry的用户权限。首先我们需要用htpasswd工具创建一个Apache格式的验证文件(Nginx也可以识别该文件):

cd ~/docker-registry/nginx
htpasswd -c registry.password USERNAME

其中的USERNAME是你自己指定的用户名。指令输入后,命令行会请求为该用户建立一个密码。

如果以后要添加新用户,还是一样使用htpasswd工具,只是不用再输入-c选项了(c是新建的意思):

htpasswd registry.password USERNAME

现在我们有了一个registry.password文件,里面保存了可以访问registry的用户名列表。这个文件是可以随时查看编辑的。

接下来需要让Nginx把这个文件用起来。还是打开~/docker-registry/nginx/registry.conf文件:

nano ~/docker-registry/nginx/registry.conf

找到下面这几行内容:

# To add basic authentication to v2 use auth_basic setting plus add_header
# auth_basic "registry.localhost";
# auth_basic_user_file /etc/nginx/conf.d/registry.password;
# add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;

将auth_basic和add_header这两行前面的井号去掉:

# To add basic authentication to v2 use auth_basic setting plus add_header
auth_basic "registry.localhost";
auth_basic_user_file /etc/nginx/conf.d/registry.password;
add_header 'Docker-Distribution-Api-Version' 'registry/2.0' always;

这样就启动了HTTP验证功能。保存退出,来把容器们启动起来看看:

cd ~/docker-registry
docker-compose up

还是用curl来给Nginx发送请求:

curl http://localhost:5043/v2/

这次的返回结果是一个验证失败的页面:

<html>
<head><title>401 Authorization Required</title></head>
<body bgcolor="white">
<center><h1>401 Authorization Required</h1></center>
<hr><center>nginx/1.9.7</center>
</body>
</html>

现在加上用户名和密码,再用curl发送一次请求:

curl http://USERNAME:PASSWORD@localhost:5043/v2/

这次,你应该能看到之前的返回结果——空json对象{}。在docker-compose的终端也能够看到registry_部分的内容。

CTRL-C退出,准备进行下一步。
步骤5:设置SSL

虽然已经有了基本的HTTP验证,但现在还是不够安全,因为连接是未加密的。我们需要把SSL启用起来。还是打开刚才的Nginx配置文件:

nano ~/docker-registry/nginx/registry.conf

找到如下内容:

server {
  listen 443;
  server_name myregistrydomain.com;

# SSL
  # ssl on;
  # ssl_certificate /etc/nginx/conf.d/domain.crt;
  # ssl_certificate_key /etc/nginx/conf.d/domain.key;

把SSL以下的三行前面的井号删掉。不要忘了把server_name部分的值改成你的服务器域名:

server {
  listen 443;
  server_name myregistrydomain.com;

# SSL
  ssl on;
  ssl_certificate /etc/nginx/conf.d/domain.crt;
  ssl_certificate_key /etc/nginx/conf.d/domain.key;

保存退出。Nginx将使用/etc/nginx/conf.d/domain.crt证书以及/etc/nginx/conf.d/domain.key密钥来提供SSL服务。根据之前的配置,容器内的/etc/nginx/conf.d/路径是映射到宿主机的~/docker-registry/nginx/路径下,所以我们需要把证书文件复制到这里。你可以购买证书,也可以获取一个免费的SSL证书。或者,你也可以使用自签名的SSL证书。
自签名的SSL证书

目前为止,Docker还无法正式支持自签名的SSL证书,所以这个配置起来要麻烦一些——我们需要将宿主机设置为证书的颁发机构。

到~/docker-registry/nginx目录下,创建一个新的root key:

cd ~/docker-registry/nginx
openssl genrsa -out devdockerCA.key 2048

生成一个root证书(需要填写国家省市信息之类的,这些可以随便填):

openssl req -x509 -new -nodes -key devdockerCA.key -days 10000 -out devdockerCA.crt

然后,生成key(这个密钥就是上面需要用到的ssl_certificate_key):

openssl genrsa -out domain.key 2048

然后,我们需要进行一个证书签名的请求。

输入如下命令。输入之后,OpenSSL会向你提出几个问题。其他问题怎么回答都好,不过关于"Common Name"这一项,务必要填写服务器的域名或IP:

openssl req -new -key domain.key -out dev-docker-registry.com.csr

比如,如果你的Docker registry使用的域名是www.ilovedocker.com,则需要这样填写:

Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:www.ilovedocker.com
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

A challenge password []:这里不要填。

然后,我们要给这个证书请求做签名:

openssl x509 -req -in dev-docker-registry.com.csr -CA devdockerCA.crt -CAkey devdockerCA.key -CAcreateserial -out domain.crt -days 10000

因为我们刚才生成的这些证书没有被任何权威机构(比如VeriSign)验证过,因此我们需要用另外的方法告诉所有使用这个Docker registry的客户端说,这个Docker registry使用的证书是合法的。这个方法就是,在每个Docker客户端上做如下设置(需要把刚才生成的devdockerCA.crt复制过去):

sudo mkdir /usr/local/share/ca-certificates/docker-dev-cert
sudo cp devdockerCA.crt /usr/local/share/ca-certificates/docker-dev-cert
sudo update-ca-certificates

重启Docker守护进程以使该证书生效:

sudo service docker restart

详细配置过程见本文步骤9。上述指令在本机执行可直接生效。
步骤6:测试SSL

现在启动容器:

cd ~/docker-registry
docker-compose up

再做一次curl,但是用https(这里输入的域名或IP必须与刚才在证书生成过程中填写的Common Name部分完全一致):

curl https://USERNAME:PASSWORD@[YOUR-DOMAIN]:5043/v2/

如果刚才用了自签名证书,你会看到如下问题报告:

curl: (60) SSL certificate problem: self signed certificate

为curl命令加上-k选项可以跳过该验证:

curl -k https://USERNAME:PASSWORD@[YOUR-DOMAIN]:5043/v2/

如此,应该可以得到空json对象{}的返回结果。docker-compose的终端窗口那边也会输出registry_部分内容。否则的话,则需要回去重新检查SSL设置的步骤。

至此,如果你的防火墙配置允许来自外部的请求访问5043端口,则你应该可以使用自己的用户名和密码通过docker login https://<YOURDOMAIN>登陆到该Docker registry上了。
步骤7:将SSL端口设置为443

443是标准的SSL端口,所以我们要把之前设置的5043改成443。不过在Linux上,1024以下的端口都是“特权”端口,所以docker-compose容器必须以root权限运行才能使用该端口。

打开docker-compose.yml进行编辑:

nano ~/docker-registry/docker-compose.yml

在Nginx部分的ports:段落,原本的内容是- 5043:443,即把宿主机的5043端口映射到Nginx容器的443端口。我们要把它改成- 443:443:

nginx:
  image: "nginx:1.9"
  ports:
    - 443:443
  links:
    - registry:registry
  volumes:
    - ./nginx/:/etc/nginx/conf.d:ro
registry:
  image: registry:2
  ports:
    - 127.0.0.1:5000:5000
  environment:
    REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY: /data
  volumes:
    - ./data:/data

CTRL-C退出之前运行的docker-compose(如果之前已经退出就无需进行此操作),然后以sudo权限再次启动:

sudo docker-compose up

现在docker-compose已经启动,再次使用curl命令来做一次测试。这次我们在URL中不再指定端口:

curl https://<YOURUSERNAME>:<YOURPASSWORD>@YOUR-DOMAIN/v2/

检查返回的结果是否为{},docker-compose终端窗口的输出是否包含registry_。在外部的另一台机器上重复本操作,以确保Docker registry可以从外部访问。

如果一切正常,CTRL-C退出,准备进行下一步。
步骤8:将Docker Registry启动为服务

接下来我们创建一个Upstart脚本以使Docker registry在每次系统启动时一起启动。

首先我们需要移除之前已经生成的容器,好把整个Docker registry目录移动到系统通用目录下,再将其权限更改为root权限:

cd ~/docker-registry
docker-compose rm   # 移除现有的容器
sudo mv ~/docker-registry /docker-registry
sudo chown -R root: /docker-registry

然后创建一个Upstart脚本:

sudo nano /etc/init/docker-registry.conf

将以下内容复制粘贴到文件中(该脚本内容有一些复杂,其说明可参考这篇博文。有关Upstart的用法可参考这篇教程。):

description "Docker Registry"

start on runlevel [2345]
stop on runlevel [016]

respawn
respawn limit 10 5

chdir /docker-registry

exec /usr/local/bin/docker-compose up

现在用如下命令测试一下该Upstart脚本:

sudo service docker-registry start

返回的结果应该是这样的:

docker-registry start/running, process 25303

使用如下命令检查Docker服务是否已经在运行:

docker ps

返回的结果应该是这样的(其中包含dockerregistry_的项目):

CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS                          NAMES
d4b6fef0b4d1        nginx:1.9           "nginx -g 'daemon of   2 minutes ago       Up 2 minutes        80/tcp, 0.0.0.0:443->443/tcp   dockerregistry_nginx_1
77668352bd39        registry:2          "registry cmd/regist   2 minutes ago       Up 2 minutes        127.0.0.1:5000->5000/tcp       dockerregistry_registry_1

Upstart会把docker-compose命令的输出都录入到/var/log/upstart/docker-registry.log日志文件中。用tail命令检查一下这个日志文件(需要使用sudo,因为upstart日志是以root用户写入的):

sudo tail -f /var/log/upstart/docker-registry.log

里面应该能看到包含registry_的条目。再从本机的新终端窗口或另一台机器curl到registry服务器上:

curl https://<YOUR_USERNAME>:<YOURPASSWORD>@[YOUR-DOMAIN]/v2/

检查返回的结果是否为{}。日志文件中应该能看到跟之前一样的信息:

registry_1 | time="2015-08-12T08:01:12.241887501Z" level=debug msg="authorizing request" environment=development http.request.host=docker.meatflavoredbeer.com http.request.id=e8d69e16-9448-4c48-afd8-57b1f1302742 http.request.method=GET http.request.remoteaddr=106.1.247.4 http.request.uri="/v2/" http.request.useragent="curl/7.37.1" instance.id=14d4727b-fda1-463f-8d0e-181f4c70cb17 service=registry version=v2.0.1
registry_1 | time="2015-08-12T08:01:12.242206499Z" level=info msg="response completed" environment=development http.request.host=docker.meatflavoredbeer.com http.request.id=e8d69e16-9448-4c48-afd8-57b1f1302742 http.request.method=GET http.request.remoteaddr=106.1.247.4 http.request.uri="/v2/" http.request.useragent="curl/7.37.1" http.response.contenttype="application/json; charset=utf-8" http.response.duration=3.359883ms http.response.status=200 http.response.written=2 instance.id=14d4727b-fda1-463f-8d0e-181f4c70cb17 service=registry version=v2.0.1
registry_1 | 172.17.0.4 - - [12/Aug/2015:08:01:12 +0000] "GET /v2/ HTTP/1.0" 200 2 "" "curl/7.37.1"
nginx_1    | 106.1.247.4 - nik [12/Aug/2015:08:01:12 +0000] "GET /v2/ HTTP/1.1" 200 2 "-" "curl/7.37.1" "-"

步骤9:配置需要访问Docker Registry的客户端

如步骤5所述,对于使用自签名SSL证书的情况,所有需要访问该Docker registry的客户端都需要添加我们创建的证书。我们需要把~/docker-registry/nginx/devdockerCA.crt这个文件复制到客户端机器上。

首先在服务器上查看该证书文件:

sudo cat /docker-registry/nginx/devdockerCA.crt

文件内容差不多是这样的形式:

-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJANiXy7fHSPrmMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTQwOTIxMDYwODE2WhcNNDIwMjA2MDYwODE2WjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAuK4kNFaY3k/0RdKRK1XLj9+IrpR7WW5lrNaFB0OIiItHV9FjyuSWK2mj
ObR1IWJNrVSqWvfZ/CLGay6Lp9DJvBbpT68dhuS5xbVw3bs3ghB24TntDYhHMAc8
GWor/ZQTzjccHUd1SJxt5mGXalNHUharkLd8mv4fAb7Mh/7AFP32W4X+scPE2bVH
OJ1qH8ACo7pSVl1Ohcri6sMp01GoELyykpXu5azhuCnfXLRyuOvQb7llV5WyKhq+
SjcE3c2C+hCCC5g6IzRcMEg336Ktn5su+kK6c0hoD0PR/W0PtwgH4XlNdpVFqMST
vthEG+Hv6xVGGH+nTszN7F9ugVMxewIDAQABo1AwTjAdBgNVHQ4EFgQULek+WVyK
dJk3JIHoI4iVi0FPtdwwHwYDVR0jBBgwFoAULek+WVyKdJk3JIHoI4iVi0FPtdww
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAkignESZcgr4dBmVZqDwh
YsrKeWSkj+5p9eW5hCHJ5Eg2X8oGTgItuLaLfyFWPS3MYWWMzggxgKMOQM+9o3+k
oH5sUmraNzI3TmAtkqd/8isXzBUV661BbSV0obAgF/ul5v3Tl5uBbCXObC+NUikM
O0C3fDmmeK799AM/hP5CTDehNaFXABGoVRMSlGYe8hZqap/Jm6AaKThV4g6n4F7M
u5wYtI9YDMsxeVW6OP9ZfvpGZW/n/88MSFjMlBjFfFsorfRd6P5WADhdfA6CBECG
LP83r7/MhqO06EOpsv4n2CJ3yoyqIr1L1+6C7Erl2em/jfOb/24y63dj/ATytt2H
6g==
-----END CERTIFICATE-----

把证书内容复制到剪贴板上。

登陆到客户端机器,创建证书目录:

sudo mkdir /usr/local/share/ca-certificates/docker-dev-cert

再创建证书文件,使用同样的文件名devdockerCA.crt:

sudo nano /usr/local/share/ca-certificates/docker-dev-cert/devdockerCA.crt

将刚才复制到剪贴板上的内容粘贴进来。保存退出。再使用cat查看一下新创建的文件,检查内容是否正确:

cat /usr/local/share/ca-certificates/docker-dev-cert/devdockerCA.crt

确认无误后,更新证书信息:

sudo update-ca-certificates

返回的结果应该包含1 added信息:

Updating certificates in /etc/ssl/certs... 1 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d....done.

重启Docker以重新加载系统CA证书列表:

sudo service docker restart

现在可以使用如下指令登入Docker registry了:

docker login https://YOUR-DOMAIN

服务器会要求你输入用户名、密码和Email。用户名和密码就是刚才在服务器上创建的,Email可以随便填:

Username: USERNAME
Password: PASSWORD
Email:
Account created. Please see the documentation of the registry http://localhost:5000/v1/ for instructions how to activate it.

如果输入的信息无误,应该可以看到登陆成功的信息:

Login Succeeded

步骤10:将本机镜像发布到Docker Registry

我们先在客户端上创建一个简单的镜像(基于Docker Hub上的ubuntu镜像。如果本机上已经有镜像那就可以省去这一步了):

docker run -t -i ubuntu /bin/bash

该指令会下载ubuntu镜像并运行其中的bash以等待我们给该容器输入指令,这可能需要一段时间。等等待输入的指令出现之后,我们来创建一个文件SUCCESS:

touch /SUCCESS

现在可以退出容器了:

exit

将变更后的镜像提交为test-image:

docker commit $(docker ps -lq) test-image

根据我们上面的操作,这个test-image镜像与官方ubuntu镜像相比,只是添加了一个空文件SUCCESS。

现在我们把这个测试镜像推送到registry。

登陆到registry服务器:

docker login https://YOUR-DOMAIN

输入用户名和密码:

Username: USERNAME
Password: PASSWORD
Email:
Account created. Please see the documentation of the registry http://localhost:5000/v1/ for instructions how to activate it.

现在可以推送刚才的镜像。根据Docker的设计,我们推送之前,需要给它加一个tag用于标注registry的位置:

docker tag test-image [YOUR-DOMAIN]/test-image

这里需要注意的是,tag中的域名不需要https://,只需要域名、端口、加上镜像名称即可。

现在可以推送了:

docker push [YOUR-DOMAIN]/test-image

推送需要一段时间,完成后应该能看到如下内容:

latest: digest: sha256:5ea1cfb425544011a3198757f9c6b283fa209a928caabe56063f85f3402363b4 size: 8008

步骤11:从Docker Registry拉取镜像

现在测试从另一台机器拉取该镜像(我们也可以直接在registry服务器上进行本测试)。

登陆到registry服务器:

docker login https://[YOUR-DOMAIN]

使用刚才创建的tag拉取镜像:

docker pull [YOUR-DOMAIN]/test-image

Docker会下载该镜像。下载完成后,输入如下指令运行镜像以进入到里面:

docker run -t -i [YOUR-DOMAIN]/test-image /bin/bash

看看里面是不是有刚才创建的文件:

ls

应该可以看到SUCCESS文件出现在列表中:

SUCCESS  bin  boot  dev  etc  home  lib  lib64  media   mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

总结

至此,我们已经成功创建了一个私有Docker Registry服务器,并且完成了镜像的推送和拉取。现在可以尽情的玩弄你的Docker啦!

转载:http://blog.csdn.net/zstack_org/article/details/53301211?locationNum=12&fps=1

Docker学习笔记六:Docker搭建企业级私有仓库的更多相关文章

  1. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...

  2. Kubernetes-5:搭建企业级私有仓库Harbor

    搭建企业级私有仓库Harbor 安装需求 python版本 >= 2.7 Docker引擎版本 >= 1.10 docker-compose版本 >= 1.6.0 安装环境 一.Py ...

  3. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境(转)

    前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装.部署和升级,非常 ...

  4. [转]Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    本文转自:http://www.blogjava.net/yongboy/archive/2013/12/12/407498.html 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 ...

  5. DOCKER 学习笔记8 Docker Swarm 集群搭建

    前言 在前面的文章中,已经介绍如何在本地通过Docker Machine 创建虚拟Docker 主机,以及也可以在本地Windows 创建虚拟主机,也是可以使用的.这一节,我们将继续学习 Docker ...

  6. Docker学习笔记2: Docker 概述

    一.什么是Docker Docker是基于Go语言实现的云开源项目. Docker 的主要目标是:"Bulid,Ship and  Run Any App ,AnyWhere" , ...

  7. DOCKER 学习笔记7 Docker Machine 在阿里云实例化ECS 以及本地Windows 实例化虚拟机实战

    前言 通过以上6小节的学习,已经可以使用DOCKER 熟练的部署应用程序了.大家都可以发现使用 DOCKER 带来的方便之处,因为现在的话,只是在一台服务器上部署,这样部署,我们只需要一条命令,需要的 ...

  8. DOCKER 学习笔记7 Docker Machine 建立虚拟机实战,以及错误总结

    前言 通过以上6小节的学习,已经可以使用DOCKER 熟练的部署应用程序了.大家都可以发现使用 DOCKER 带来的方便之处,因为现在的话,只是在一台服务器上部署,这样部署,我们只需要一条命令,需要的 ...

  9. Docker学习笔记(3) — docker仓库的镜像怎么删除

    docker越来越炙手可热,如果你的团队已经准备开始使用docker,那么私有仓库是必不可少的东西,首先是可以帮助你加快从服务器pull镜像的速度,其次也可以帮助你存放私有的镜像,本文主要为大家介绍如 ...

随机推荐

  1. Arduino 101/Genuino101使用-第一篇

    1. 函数API说明文档在哪里? 2. 如果我想定义一个引脚做GPIO,不是库里有的. 3. digitalWrite(13, lighting); 这个函数里面 13代表的是啥? 4. setup( ...

  2. Maven学习(十七)-----Maven外部依赖

    Maven外部依赖 正如大家所了解的那样,Maven确实使用 Maven 库的概念作依赖管理.但是,如果依赖是在远程存储库和中央存储库不提供那会怎么样? Maven 提供为使用外部依赖的概念,就是应用 ...

  3. python全栈开发-面向对象-进阶

    python_day_18 1,面向对象的三大特性是什么?继承,多态,封装2,什么是面向对象的新式类?什么是经典类?凡是继承object类都是新式类.凡是不继承object类都是经典类.3,面向对象为 ...

  4. js显示对象所有属性和方法的函数

    function ShowObjProperty2( obj ) { // 用来保存所有的属性名称和值 var attributes = '' ; var methods = '' // 开始遍历 f ...

  5. 2019年猪年颁奖典礼、公司年会、跨年晚会、科技会议、年终答谢会之幕布背景展板PSD模板-第三部分

    16套--2019年猪年颁奖典礼.公司年会.跨年晚会.科技会议.年终答谢会之幕布.背景和展板PSD模板,免费颁奖典礼PSD展板背景幕布,下载地址:百度网盘,https://pan.baidu.com/ ...

  6. tomcat 设定自定义图片路径

    1.问题 平常图片路径都是在项目目录下存放,都是ip地址+端口号+项目名+图片路径,因为项目需要要把图片从tomcat中分离出来,并且设置可以通过自定义地址访问自定义图片路径. 2.解决 在 tomc ...

  7. selenium、unittest——POM框架并出报告

    学习隔壁大神的POM框架,结合自己的用例进行修改整理并执行,操作遇到的主要问题是如何分布的写各个模块并统一运行,每个文件夹想要import里面的模块需要有__init__模块 POM主要分为三个部分, ...

  8. Spring Cloud(三):服务提供与调用 Eureka【Finchley 版】

    Spring Cloud(三):服务提供与调用 Eureka[Finchley 版]  发表于 2018-04-15 |  更新于 2018-05-07 |  上一篇文章我们介绍了 Eureka 服务 ...

  9. dp算法之硬币找零问题

    题目:硬币找零 题目介绍:现在有面值1.3.5元三种硬币无限个,问组成n元的硬币的最小数目? 分析:现在假设n=10,画出状态分布图: 硬币编号 硬币面值p 1 1 2 3 3 5 编号i/n总数j ...

  10. mysql系列学习

    # 帮助help create user;# 查看当前用户select user();# 创建用户create user 'egon'@'localhost' identified by '123'; ...