Docker学习笔记六:Docker搭建企业级私有仓库
前言
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搭建企业级私有仓库的更多相关文章
- Docker学习笔记之一,搭建一个JAVA Tomcat运行环境
Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...
- Kubernetes-5:搭建企业级私有仓库Harbor
搭建企业级私有仓库Harbor 安装需求 python版本 >= 2.7 Docker引擎版本 >= 1.10 docker-compose版本 >= 1.6.0 安装环境 一.Py ...
- Docker学习笔记之一,搭建一个JAVA Tomcat运行环境(转)
前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序,并通过配置文件可以轻松实现应用程序的自动化安装.部署和升级,非常 ...
- [转]Docker学习笔记之一,搭建一个JAVA Tomcat运行环境
本文转自:http://www.blogjava.net/yongboy/archive/2013/12/12/407498.html 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 ...
- DOCKER 学习笔记8 Docker Swarm 集群搭建
前言 在前面的文章中,已经介绍如何在本地通过Docker Machine 创建虚拟Docker 主机,以及也可以在本地Windows 创建虚拟主机,也是可以使用的.这一节,我们将继续学习 Docker ...
- Docker学习笔记2: Docker 概述
一.什么是Docker Docker是基于Go语言实现的云开源项目. Docker 的主要目标是:"Bulid,Ship and Run Any App ,AnyWhere" , ...
- DOCKER 学习笔记7 Docker Machine 在阿里云实例化ECS 以及本地Windows 实例化虚拟机实战
前言 通过以上6小节的学习,已经可以使用DOCKER 熟练的部署应用程序了.大家都可以发现使用 DOCKER 带来的方便之处,因为现在的话,只是在一台服务器上部署,这样部署,我们只需要一条命令,需要的 ...
- DOCKER 学习笔记7 Docker Machine 建立虚拟机实战,以及错误总结
前言 通过以上6小节的学习,已经可以使用DOCKER 熟练的部署应用程序了.大家都可以发现使用 DOCKER 带来的方便之处,因为现在的话,只是在一台服务器上部署,这样部署,我们只需要一条命令,需要的 ...
- Docker学习笔记(3) — docker仓库的镜像怎么删除
docker越来越炙手可热,如果你的团队已经准备开始使用docker,那么私有仓库是必不可少的东西,首先是可以帮助你加快从服务器pull镜像的速度,其次也可以帮助你存放私有的镜像,本文主要为大家介绍如 ...
随机推荐
- Arduino 101/Genuino101使用-第一篇
1. 函数API说明文档在哪里? 2. 如果我想定义一个引脚做GPIO,不是库里有的. 3. digitalWrite(13, lighting); 这个函数里面 13代表的是啥? 4. setup( ...
- Maven学习(十七)-----Maven外部依赖
Maven外部依赖 正如大家所了解的那样,Maven确实使用 Maven 库的概念作依赖管理.但是,如果依赖是在远程存储库和中央存储库不提供那会怎么样? Maven 提供为使用外部依赖的概念,就是应用 ...
- python全栈开发-面向对象-进阶
python_day_18 1,面向对象的三大特性是什么?继承,多态,封装2,什么是面向对象的新式类?什么是经典类?凡是继承object类都是新式类.凡是不继承object类都是经典类.3,面向对象为 ...
- js显示对象所有属性和方法的函数
function ShowObjProperty2( obj ) { // 用来保存所有的属性名称和值 var attributes = '' ; var methods = '' // 开始遍历 f ...
- 2019年猪年颁奖典礼、公司年会、跨年晚会、科技会议、年终答谢会之幕布背景展板PSD模板-第三部分
16套--2019年猪年颁奖典礼.公司年会.跨年晚会.科技会议.年终答谢会之幕布.背景和展板PSD模板,免费颁奖典礼PSD展板背景幕布,下载地址:百度网盘,https://pan.baidu.com/ ...
- tomcat 设定自定义图片路径
1.问题 平常图片路径都是在项目目录下存放,都是ip地址+端口号+项目名+图片路径,因为项目需要要把图片从tomcat中分离出来,并且设置可以通过自定义地址访问自定义图片路径. 2.解决 在 tomc ...
- selenium、unittest——POM框架并出报告
学习隔壁大神的POM框架,结合自己的用例进行修改整理并执行,操作遇到的主要问题是如何分布的写各个模块并统一运行,每个文件夹想要import里面的模块需要有__init__模块 POM主要分为三个部分, ...
- Spring Cloud(三):服务提供与调用 Eureka【Finchley 版】
Spring Cloud(三):服务提供与调用 Eureka[Finchley 版] 发表于 2018-04-15 | 更新于 2018-05-07 | 上一篇文章我们介绍了 Eureka 服务 ...
- dp算法之硬币找零问题
题目:硬币找零 题目介绍:现在有面值1.3.5元三种硬币无限个,问组成n元的硬币的最小数目? 分析:现在假设n=10,画出状态分布图: 硬币编号 硬币面值p 1 1 2 3 3 5 编号i/n总数j ...
- mysql系列学习
# 帮助help create user;# 查看当前用户select user();# 创建用户create user 'egon'@'localhost' identified by '123'; ...