前言

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. angular 缓存模板 ng-template $templateCache

    由于浏览器加载html模板是异步加载的,如果加载大量的模板会拖慢网站的速度,这里有一个技巧,就是先缓存模板. 使用angular缓存模板主要有三种方法: 方法一:通过script标签引入 <sc ...

  2. 我们一起学习WCF 第一篇初识WCF(附源码供对照学习)

    前言:去年由于工作需要我学习了wcf的相关知识,初期对wcf的作用以及为何用怎么样都是一知半解,也许现在也不是非常的清晰.但是通过项目对wcf的运用在脑海里面也算有了初步的模型.今天我就把我从开始wc ...

  3. 初遇python进程

    计算机硬件组成 主板 固化(寄存器,是直接和cpu进行交互的一个硬件) cpu 中央处理器:计算(数字计算和逻辑计算)和控制(控制所有硬件协调工作) 存储 硬盘,内存 输入设备 键盘,鼠标,话筒 输出 ...

  4. ffmpeg 踩坑实录 近期使用总结(三)

    一.背景介绍 将ffmpeg运用到项目上已经有一段时间了,趁现在有空赶紧记下来. 二.技术点总结    2.1 实现方式 项目里面主要运用的形式是,在java端,调用操作系统的方法,并执行切片命令. ...

  5. ShipStation Now Uses AWS And Amazon Fulfillment To Automatically Ship From eBay, Sears And Other Marketplaces

    ShipStation today unveiled a first-of-its-kind service to leverage Amazon Web Services and Amazon.co ...

  6. [shell] sed学习

    Q:匹配内容有1没有a的行 echo -e "1a\n2b\n1b\n2a" | sed -n '/1/{/a/d;p}' echo -e "1a\n2b\n1b\n2a ...

  7. python实现中文验证码识别方法(亲测通过)

    验证码截图如下: # coding:utf-8from PIL import Image,ImageEnhanceimport pytesseract#上面都是导包,只需要下面这一行就能实现图片文字识 ...

  8. Bracket Sequences Concatenation Problem括号序列拼接问题(栈+map+思维)

    A bracket(括号) sequence is a string containing only characters "(" and ")".A regu ...

  9. (二)java.util.Scanner的使用

    Scanner是一个使用正则表达式来解析基本类型和字符串的简单文本扫描器.Scanner 使用分隔符模式将其输入分解为标记,默认情况下该分隔符模式与空白匹配.然后可以使用不同的 next 方法将得到的 ...

  10. 第九章 Mysql函数

    简介 数学函数:处理数字 字符串函数:处理字符串 日期和时间函数:处理日期和时间,获取时间 条件判断函数:控制条件选择 系统信息函数:获取MySQL系统信息,包括数据库名称,当前用户名和数据库版本 加 ...