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 <repo>[: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 <IMAGE ID>/<repo>
d, 镜像打标. 可以将此操作与 Git 打标进行类比, 相当于是 release 一个可用的镜像版本.
> docker tag <repo> <new_repo>[:tag]
e, 镜像推送. 同样是可以借鉴 Git 领域的 push 操作, 将打包好的镜像推送给远程仓库(即为 Docker Registry).
> docker push <new_repo>[: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, https://github.com/kwk/docker-registry-frontend . 截止到目前(2018 年 5 月), 其功能主要是镜像列表查看, 标签查看, 还未开放镜像删除功能, 在 GitHub 上开源, stars 1k+.
2, https://github.com/mkuchin/docker-registry-web . 相比 docker-registry-frontend 项目, 此项目提供了镜像删除功能, 还接入了角色系统, 功能有了进一步完善, 在 GitHub 上开源, stars 300+.
3,Rancher https://rancher.com/ . 这个平台的定位类似 Kubernetes, 不仅仅是镜像管理这么简单了, 对于整个 Docker 容器管理都是能胜任的.
4, https://github.com/shipyard/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 https://docs.docker.com/registry/configuration/ .
配置文件中的配置项是可以对应到前文中 - 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 部分, 再来读此书, 会轻松一些.
来源: https://segmentfault.com/a/1190000015108428