版权声明:
本文为博主原创文章,未经博主允许不得转载。关注公众号 技术汇(ID: jishuhui_2015) 可联系到作者。
〇、前言
Build, Ship and Run any App, Anywhere
关于Docker更多的概念将不在本文赘述了,作为虚拟化市场的一颗冉冉升起的新星,Docker得到了越来越多企业的青睐,越来越多的开发者决定拥入Docker的怀抱。
“集装箱”是Docker设计哲学之所在,它让一台物理机(或者虚拟机)同时运行多个彼此隔离的应用变得更为轻松简单,当然这一切还是多亏Linux的相关底层技术,当然,也包括OS X,Windows这两个操作系统。
Docker的相关教程已经够多了,但是由于Docker近年来发展迅猛,版本迭代速度较快,多个版本之间还存在不兼容的情况,如果在网上找博客文章,未必能解决自己遇到的问题。
当然,对于Docker的环境安装,基础命令之类的内容,是完全没有问题的,通读官网文档内容基本都能顺利掌握。然而,当笔者尝试着搭建一套基于SSL的Docker Registry(官网推荐的做法)却遇到了不少的麻烦,对于这部分内容,大多数博客文档内容都是直接跳过了SSL的环节,采用了HTTP的访问形式。
特此分享,通读完了此篇文章后,对于搭建Docker Registry就不再是问题了。
> docker --version
Docker version 18.03.1-ce, build 9ee9f40
以上是我的Docker环境,建议安装Docker1.6+以上版本。
除此之外,读者还需要:
1、一台安装了CentOS_7_64bit操作系统的主机(或者虚拟机);
2、申请一个域名。不然,可以改HOST文件,但不保证能成功。笔者在阿里云申请了一个个人域名,包了5年,价值¥105;
3、如果申请了域名,顺便拿一个免费的CA证书,因为需要实现HTTPS访问,SSL证书是必须的,同样,阿里云上有免费证书申请。不然,可以使用OpenSSL自己生成,这也是很多博文所提到的做法,不保证成功;
4、再装上一个nginx做代理,可选。
5、熟悉Docker的基本概念和常用命令,但不必了解Dockerfile,Compose,Swarm,Kubernetes等高阶知识。
一、从Docker镜像说起
抽象的概念阐述不多说了,笔者举两个例子,让大家感受一下:
1、我们从系统之家下载来的ISO文件,除了基础的操作系统,还可能内置了多个预装软件;
2、在使用maven管理jar包依赖的时候,为了避免每次都从中央仓库拉取依赖包,使用了nexus做了代理仓库。
可以认为,Docker镜像就是一系列软件(文件)的组合,只要将它们放在合适的宿主上,即可做到开箱即用。
关于本文需要的Docker镜像操作,有五个常用的命令:
a、拉取镜像,后跟镜像仓库名称,如果要指定某个版本,可以带上tag。
> docker pull [:tag]
b、列出所有镜像,能得到镜像的相关基本信息。
> docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest bfcb1f6df2db 3 weeks ago 107MB
registry 2 d1fd7d86a825 4 months ago 33.3MB
hyper/docker-registry-web latest 0db5683824d8 19 months ago 599MB
c、删除镜像。可以根据镜像ID,或者镜像仓库名称进行删除。
> docker rmi /
d、镜像打标。可以将此操作与Git打标进行类比,相当于是release一个可用的镜像版本。
> docker tag [:tag]
e、镜像推送。同样是可以借鉴Git领域的push操作,将打包好的镜像推送给远程仓库(即为Docker Registry)。
> docker push [:tag]
以上五个命令只做简单介绍,不是本文的重点。更多镜像操作命令,可以自行查阅之。
进行接下来的操作之前,请读者先将registry镜像pull下来。
> docker pull registry:2
2: Pulling from library/registry
81033e7c1d6a: Pull complete
b235084c2315: Pull complete
c692f3a6894b: Pull complete
ba2177f3a70e: Pull complete
a8d793620947: Pull complete
Digest: sha256:672d519d7fd7bbc7a448d17956ebeefe225d5eb27509d8dc5ce67ecb4a0bce54
Status: Downloaded newer image for registry:2
此过程会持续几分钟,视网络状况而定,请读者耐心等候。
注意:笔者在pull的时候,指定了TAG,即为使用v2版本的registry,对于v1版本的registry,读者大可不必在意了,基本上是淘汰了。
二、先睹为快
对于急切想看一下Docker Registry运行效果的读者,可以先阅读本节内容。
运行如下命令即可:
> docker run -d \
-p 5000:5000 \
-v /usr/local/registry:/var/lib/registry \
--restart=always \
--name registry \
registry:2
这是一条典型的run命令,不出意外的话,Registry就在5000端口启动了。
为了验证,读者可以拉取一个busybox镜像(因为体积小),进行实验。
> docker pull busybox
拉取最新的busybox镜像后,再给其打标,准备发布到Registry中。
> docker tag busybox localhost:5000/bosybox:v1.0
最后再推送给Registry。
> docker push localhost:5000/bosybox:v1.0
此时,Registry就有了busybox:v1.0镜像了,这时可以不用再去Docker Hub上面拉取了,通过自建的Registry即可。
> docker pull localhost:5000/bosybox:v1.0
如果想查看远程仓库有哪些镜像,可以运行如下命令:
> curl http://localhost:5000/v2/_catalog
窥一斑而见全豹,通过以上命令,我们能得出一个重要的结论:
对Registry的访问都是通过一系列REST API完成的。
到此为止,我们已经搭建了一个Docker Registry的“半成品”,说是“半成品”是因为这个Registry只能在本机正常工作,如果在其他主机上试图推送镜像上来,结果是失败的。
如果要做到externally-accessible,就必须使用CA安全证书。
三、基于SSL证书改造Registry
在进行本节的操作前,请读者确认是否满足了文章开头所列的条件。
笔者申请了一个域名:iwendao.vip,并映射出来了一个二级域名:registry.iwendao.vip,专门用来作为Docker Registry的访问,然后基于此二级域名申请CA证书。
不出意外的话,从阿里云申请的免费证书都是由Symantec颁发的,将证书下载下来后,压缩包内有两份文件:xxxxxx.pem、xxxxxx.key。
将其更名为server.key,server.pem,通过ftp工具上传至主机,假设存放的目录是:/usr/local/certs。
> ll /usr/local/certs
- rw-r--r-- 1 root root 1678 May 28 13:42 server.key
- rw-r--r-- 1 root root 3662 May 28 13:42 server.pem
因为颁发的是intermediate certificate,会发现没有crt文件,可以使用如下命令得到:
> cat server.pem > server.crt
直接将pem文件内作为crt文件的内容输入,生成了server.crt文件。
至此,域名及其证书已准备就绪。
如果想使用nginx做代理,需要更改一下nginx.conf文件,以下是笔者的配置内容:
user root root;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
keepalive_timeout 60;
gzip on;
server {
listen 443;
server_name i-wendao;
ssl on;
root html;
index index.html index.htm;
ssl_certificate /usr/local/certs/server.pem;
ssl_certificate_key /usr/local/certs/server.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;
location ~ {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass https://registry;
}
}
upstream registry {
server 127.0.0.1:5000;
}
}
在nginx.conf配置文件中,需要注意两个地方:
1、开启nginx的ssl,只需要配置之前下载好的pem和key文件,这是阿里云官方给出的示例,亲测有效;
2、因为对Registry的访问都是通过REST API完成的,而且是HTTPS的访问协议,所以location节点的配置中,proxy_pass配置的是https://registry,如果配置成http://registry,一旦Docker Registry启用了SSL后,是访问不通的。
宿主机的配置已经完成了,接下来对Docker容器进行配置。
对于Docker Registry Server的部署,官方给了两个途径:
其一,针对参数不多的情况,可以直接在docker run命令指定;
另一个是通过yaml配置文件,可以一次性配置多个参数。
在本节,笔者将使用第一种方式部署,第二种方式的部署可以参见文末的附文。
> docker run -d \
-p 5000:5000 \
-v /usr/local/registry:/var/lib/registry \
-v /usr/local/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/server.key \
--restart=always \
--name registry \
registry:2
如果没有安装nginx的读者,可运行这条命令:
> docker run -d \
-p 443:443 \
-v /usr/local/registry:/var/lib/registry \
-v /usr/local/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/server.key \
--restart=always \
--name registry \
registry:2
可以看到,Docker Registry Server启用SSL的时候,用到的是crt、key两个证书文件。
接下来,我们实验一下。
> docker tag busybox registry.iwendao.vip/bosybox:v1.0
最后再推送给Registry。
> docker push registry.iwendao.vip/bosybox:v1.0
查看远程仓库有哪些镜像。
> curl https://registry.iwendao.vip/v2/_catalog
在另外一台主机,重复上述步骤,依然可以成功,说明已经搭建成功了。
四、Authentication的加持
通过对Registry Server的搭建,我们能明显感觉得到,Docker对于安全控制有足够的重视,这在全网HTTPS化的背景下是恰合时宜的做法。
这节是进阶知识,目的是将Docker的安全机制做得更彻底——加上登录校验机制。
很明显,既然是私服,就意味着不是每个人都能提交镜像的,只有凭借登录用户和密码才行。
当然,登录校验机制的前提是有HTTPS协议,否则,用户名和密码都将会明文传输。
Docker的认证机制也有很多实现,可以直接用代理(比如nginx)在Registry之前进行拦截验证,高端的一些的是有Token服务端,引导用户授权登录,实现难度较大。
本文以最简单的htpasswd在实现登录校验机制。关于htpasswd的更多介绍不在本文的范畴,请读者自行查阅之。
如果主机上没有安装此命令工具,可以运行如下命令:
> yum install httpd-tools
因为htpasswd是Apache2的附属工具命令,如果安装了Apache2,此命令理应是可以用的。
如果读者不想安装了,可以直接使用registry镜像,其内置了httpd。
假设密码文件存放在/usr/local/auth目录下面,运行如下命令
> htpasswd -Bbn admin 123456 > /usr/local/auth/passwd
使用registry镜像内置的httpd,如下:
> docker run --entrypoint htpasswd registry:2 -Bbn admin 123456 > /usr/local/auth/passwd
两种方式都能达到同样的目的:在/usr/local/auth/passwd文件中生成用户名和密码。
命令中的admin是用户名,123456即为密码。
查看passwd文件内容:
> cat /usr/local/auth/passwd
admin:$2y$05$/2H8DTcY.1JROHm0MnnK8.UulmbSclib63qTe8FGyWnnE9XWBz3cy
虽然是同样的命令,但在不同的主机,生成的结果并不相同。因此,在主机A上生成的密码文件不能用作主机B上进行认证。
接下来要启动registry容器了:
> docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
-v /usr/local/auth:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM=Registry_Realm \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/passwd \
-v /usr/local/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/server.key \
registry:2
启动成功后,如果试图直接查看远程仓库有哪些镜像,会提示未认证,如下:
> curl https://registry.iwendao.vip/v2/_catalog
{
"errors": [{
"code": "UNAUTHORIZED",
"message": "authentication required",
"detail": [{
"Type": "registry",
"Class": "",
"Name": "catalog",
"Action": "*"
}]
}]
}
包括pull,push操作也都受限了。因此,在做操作之前,需要进行登录。
> docker login https://registry.iwendao.vip
既然有登录,当然就有登出了。
> docker logout https://registry.iwendao.vip
五、WEB UI for Registry
当我们把Registry Server搭建好了之后,就意味着要开始管理我们的镜像了。这个时候会发现,并没有一个可视化的工具帮助用户进行镜像管理。
目前已经有很多开源的WEB UI管理工具:
1、docker-registry-frontend。截止到目前(2018年5月),其功能主要是镜像列表查看,标签查看,还未开放镜像删除功能,在GitHub上开源,stars 1k+。
2、docker-registry-web。相比docker-registry-frontend项目,此项目提供了镜像删除功能,还接入了角色系统,功能有了进一步完善,在GitHub上开源,stars 300+。
3、Rancher。这个平台的定位类似Kubernetes,不仅仅是镜像管理这么简单了,对于整个Docker容器管理都是能胜任的。
4、shipyard。很可惜,作者已经没有精力维护了,从GitHub上的stars,不难看出其昔日的辉煌。
关于WEB UI的安装部署就不再赘述了,都有其对应的文档。如果对于镜像管理没有什么特别要求,可以不用WEB UI,或者使用前两个之一。
六、总结
本文详述了Docker Registry私服搭建的过程,总结了来自各类博客,官网的学习资料,帮助读者顺利搭建Docker Registry私服。
附:
1、使用yaml文件启动registry server
假设配置文件的存放路径是:/usr/local/registry/config.yml
编辑其内容,如下:
version: 0.1
log:
fields:
service: registry
storage:
cache:
blobdescriptor: inmemory
filesystem:
rootdirectory: /var/lib/registry
maxthreads: 100
delete:
enabled: true
http:
addr: 0.0.0.0:5000
host: https://registry.iwendao.vip
secret: yoogurt-taxi-123!@#
headers:
X-Content-Type-Options: [nosniff]
tls:
certificate: /certs/214709594090104.crt
key: /certs/214709594090104.key
health:
storagedriver:
enabled: true
interval: 10s
threshold: 3
更多配置项,可以访问Configuring a registry。
配置文件中的配置项是可以对应到前文中-e参数的环境变量,其规则就是:
1、变量名由大写字母组成;
2、前缀固定加上REGISTRY;
3、将YAML中的配置项的冒号(:)变成了下划线(_)。
比如:
REGISTRY_HTTP_TLS_CERTIFICATE,对应的是http: tls: certificate配置项;
REGISTRY_AUTH_HTPASSWD_PATH,对应的是auth: htpasswd: path配置项。
值得注意的是,配置文件中所涉及的路径都是针对容器内的,这就意味着,在启动registry镜像的时候,需要通过-v参数指定挂载目录。
保存配置文件后,即可启动容器:
> docker run -d -p 5000:5000 --restart=always --name registry \
-v /usr/local/certs:/certs
-v /usr/local/registry/config.yml:/etc/docker/registry/config.yml \
registry:2
2、介绍关于Docker的书籍
- 《第一本Docker书(修订版)》,当之无愧的Docker启蒙书。零基础入门者可以着重看前五章基础部分,掌握Docker的相关原理及其使用,可用作工具书。读此书,建议跟着内容同步进行实践,入门以后,能够建立起对Docker的兴趣,以便持续学习下去。
- 《Docker 容器与容器云(第2版)》,知识内容有所进阶。第一部分内容为基础知识,可以快速过一遍。本书对于容器云的概念做了各方面反复的解释,非常精彩,可以吸收之。接下来就是容器编排、部署的内容了,可以加之实践,培养感觉。
- 《Kubernetes权威指南(第2版)》,当之无愧的Kubernetes入门书籍。读完了《Docker 容器与容器云(第2版)》的Kubernetes部分,再来读此书,会轻松一些。