原文来源: Rancher Labs
对于 Harbor 这样一个优秀的 Docker Registry 管理开源项目,以下内容基本上来自前人已有的研究,我只是将其在实践中进行了测试,并整理汇集了相关资料供大家参考,同时针对 Harbor 与 Rancher产品的整合做了一些实验性的工作,以更好更全面的理解 Harbor 这个工具,也更加了解 Rancher 在快速一键部署、弹性伸缩高可用等方面的优势。
Harbor 是一个企业级 Registry 服务。它对开源的 Docker Registry 服务进行了扩展,添加了更多企业用户需要的功能。Harbor 被设计用于部署一套组织内部使用的私有环境,这个私有 Registry 服务对于非常关心安全的组织来说是十分重要的。另外,私有 Registry 服务可以通过避免从公域网下载镜 像而提高企业生产力。这对于没有良好的 Internet 连接状态,使用 Docker Container 的用户是一个福音。
Harbor 在架构上主要由五个组件构成:
Harbor 的每个组件都是以 Docker 容器的形式构建的,因此很自然地,我们使用 Docker Compose 来对它进行部署。在源代码中
( https://github.com/vmware/harbo r),用于部署 Harbor 的 Docker Compose 模板位于 /Deployer/docker-compose.yml. 打开这个模板文件,会发现 Harbor 由 5 个容器组成:
这几个容器通过 Docker link 的形式连接在一起,这样,在容器之间可以通过容器名字互相访问。对终端用户而言,只需要暴露 proxy (即 Nginx)的服务端口。
下面以两个 Docker 命令为例,讲解主要组件之间如何协同工作。
1) docker login
假设我们将 Harbor 部署在主机名为 registry.yourdomainname.com 的虚机上。用户通过 docker login 命令向这个 Harbor 服务发起登录请求:docker login registry.yourdomainname.com当用户输入所需信息并点击回车后,Docker 客户端会向地址“registry.yourdomainname.com/v2/” 发出 HTTP GET 请求。 Harbor 的各个容器会通过以下步骤处理:
(a) 首先,这个请求会由监听 80 端口的 proxy 容器接收到。根据预先设置的匹配规则,容器中的 Nginx会将请求转发给后端的 registry 容器;
(b) 在 registry 容器一方,由于配置了基于 token 的认证,registry 会返回错误代码 401,提示 Docker客户端访问 token 服务绑定的 URL。在 Harbor 中,这个 URL 指向 Core Services;
(c) Docker 客户端在接到这个错误代码后,会向token服务的URL发出请求,并根据HTTP协议的BasicAuthentication 规范,将用户名密码组合并编码,放在请求头部(header);
(d)类似地,这个请求通过 80 端口发到 proxy 容器后,Nginx 会根据规则把请求转发给 ui 容器,ui 容器监听 token 服务网址的处理程序接收到请求后,会将请求头解码,得到用户名、密码;
(e) 在得到用户名、密码后,ui 容器中的代码会查询数据库,将用户名、密码与 mysql 容器中的数据进行比对(注:ui 容器还支持 LDAP 的认证方式,在那种情况下 ui 会试图和外部 LDAP 服务进行通信并校验用户名/密码)。比对成功,ui 容器会返回表示成功的状态码, 并用密钥生成 token,放在响应体中返回给 Docker 客户端。这个过程中组件间的交互过程如下图所示:
至此,一次 docker login 成功地完成了,Docker 客户端会把步骤(c)中编码后的用户名密码保存在本地的隐藏文件中。
2) docker push
用户登录成功后用 docker push 命令向 Harbor 推送一个 Docker 镜像:docker push registry.youdomainname.com/library/hello-world
(a) 首先,docker 客户端会重复 login 的过程,首先发送请求到 registry,之后得到 token 服务的地址;
(b) 之后,Docker 客户端在访问ui容器上的token服务时会提供额外信息,指明它要申请一个对imagelibrary/hello-world 进行 push 操作的 token;
(c) token 服务在经过 Nginx 转发得到这个请求后,会访问数据库核实当前用户是否有权限对该 image进行 push。如果有权限,它会把 image 的信息以及 push 动作进行编码,并用私钥签名,生成 token返回给 Docker 客户端;
(d) 得到 token 之后 Docker 客户端会把 token 放在请求头部,向 registry 发出请求,试图开始推送image。 Registry 收到请求后会用公钥解码 token 并进行核对,一切成功后,image 的传输就开始了。我们省去 proxy 转发的步骤,下图描述了这个过程中各组件的通信
过程 :
此次示范以 CentOS 7.2.1511 x86_64 为例:
[root@registry ~]# yum install https://yum.dockerproject.org/repo/main/centos/7/Packages/docker-engine-selinux-1.11.2- 1.el7.centos.noarch.rpm [root@registry ~]# yum install https://yum.dockerproject.org/repo/main/centos/7/Packages/docker-engine-1.11.2- 1.el7.centos.x86_64.rpm [root@registry ~]# systemctl enable docker [root@registry ~]# systemctl start docker [root@registry ~]# yum install git [root@registry ~]# git clone https://github.com/vmware/harbor [root@registry ~]# cd harbor/ [root@registry harbor]# cd Deploy/ [root@registry Deploy]# vi harbor.cfg
修改的重点内容如下:
hostname = registry.yourdomainname.comui_url_protocol = https email_server = smtp.yourmailserver.comemail_server_port = 25 email_username = registry_admin@yourdomainname.comemail_password = yourpassword email_from = registry_admin@yourdomainname.comemail_ssl = false harbor_admin_password = myharborpasswordauth_mode = db_auth db_password = yoursqlpasswordself_registration = off customize_crt = off
修改完成
假设已经准备好站点的数字证书文件 registry.yourdomainname.com.crt 和registry.yourdomainname.com.key,则可以配置 https 的访问模式:
[root@registry Deploy]# cd config/nginx/ [root@registry nginx]# ls cert/ registry.yourdomainname.com.crt registry.yourdomainname.com.key [root@registry nginx]# mv nginx.conf nginx.conf.bak [root@registry nginx]# cp nginx.https.conf nginx.conf [root@registry nginx]# vi nginx.conf
修改内容如下:
修改内容结束
安装 docker-compose 命令:
添加 harbor 的启停脚本:
添加 harbor 为 systemd 服务:
管理 Harbor 的生命周期:
关于数字证书,上面的描述适用于向第三方根证书颁发机构申请得到的数字证书文件,如果是自签名数字证书,可参考 Harbor 官方文档:
https://github.com/vmware/harb ... ps.md
访问 Harbor:
cp registry.yourdomainname.com.crt
/usr/local/share/ca-certificates/update-ca-certificates
以上两条命令适用于 Ubuntu 系列
cp registry.yourdomainname.com.crt
/etc/pki/ca-trust/source/anchors/update-ca-trust
以上两条命令适用于 RHEL 或 CentOS 系列
登陆及 push image 过程:
[root@RancherHost01 ~]# docker login registry.yourdomainname.com Username: admin Password: Login Succeeded [root@RancherHost01 ~]#
登陆 Web 端即可看见已经上传的 image 了:
新增用户界面:
Mirror 是 Docker Registry 的一种特殊类型,它起到了类似代理服务器的缓存角色,在用户和Docker Hub 之间做 Image 的缓存。
其基本工作原理是,当用户 pull 一个镜像时,若镜像在 mirror 服务器存在,则直接从 mirror 服务器拉取,否则若不存在该镜像,则由 mirror server 自动代理往 dockerhub(可配置)中拉取镜像,并缓存到 mirror 服务器中,当客户再次拉取这个镜像时,直接从 mirror server 中拉取,不需要再次从docker hub 中拉取。
Harbor 目前不支持 pull cache 功能,已提交 Github issue #120。
https://github.com/vmware/harbor/issues/120
不过我们只需要手动修改下配置即可完成,具体配置可查看官方 Registry as a pull through cache.
https://github.com/vmware/harb ... 85bc7
我们在运行./prepare 之前修改 config/registry/config.yml 文件,追加以下配置
:proxy:remoteurl: https://registry-1.docker.io
如果需要访问私有仓库,需要填写 Docker Hub 的用户名和密码
:proxy: remoteurl: https://registry-1.docker.io username: [username] password: [password]
然后重新启动 Harbor 服务:(注意不要执行./prepare)
docker-compose stop docker-compose rm -f docker-compose up -d
除了设置 Harbor(或者 registry),还需要配置本地 docker 服务,指定--registry-mirror 参数,修改docker 配置文件
Ubuntu:/etc/default/docker DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=https://registry.yourdomainname.com
或
DOCKER_OPTS="$DOCKER_OPTS --registry-mirror=https://registry.yourdomainname.com --insecure-registry registry.yourdomainname.com"
或者
RHEL/CentOS:/usr/lib/systemd/system/docker.service): [Service] ExecStart= ExecStart=/usr/bin/docker daemon -H fd:// --registry-mirror=https://registry.yourdomainname.com
注意:修改了 docker 配置文件,必须重启 docker 服务才能生效。
Harbor 由于引进了认证功能,因此 push 操作时,必须保证 project 存在,比如 push krystism/ffmpeg,必须保证 Harbor 创建了 krystism project,否则会失败。为了能够正常 push/pulldockerhub 的官方镜像,务必创建 library project,如图:
我们第一次 pull python 后,Harbor 发现不存在该镜像,于是自己作为代理往 Docker Hub 里拉取,拉取后保存到本地,可以通过 Web UI 查看。客户端再次拉取 python 镜像时,由于 Harbor 已经存在该镜像,因此不需要再往 Docker Hub 拉取,速度大幅度提高!
注意,对于 Mirror Registry 模式,虽然可以 pull cache 了,但是 push 功能却不被支持了: https://github.com/vmware/harbor/issues/220
1)Add Harbor deploy stack and 5 services in Rancher:(在 Rancher 系统里添加包含 5 个 services 的stack)
2)Add Registry server in Rancher:(在 Rancher 系统里添加 Registry 服务器,供 Rancher Agent Hosts调用)
3)Build a Catalog entry in Rancher:(为 Harbor 创建一个 Rancher 专有的应用模板项,实现一键部署,使安装调试复杂的 Harbor 产品简单化、并实现弹性伸缩及高可用等特性)
Harbor 支持两种认证方式,默认为本地存储,即账号信息存储在 mysql 下,上文已经具体介绍。接下来介绍另外一种认证方式 LDAP,只需要修改配置文件即可。需要提供 ldap url 以及 ldap basedn 参数,并且设置 auth_mode 为 ldap_auth。
快速部署 LDAP 服务:
为了测试方便,我们使用 Docker 启动一个 LDAP 服务器,启动脚本如下:
!/bin/bash NAME=ldap_server docker rm -f $NAME 2>/dev/null docker run --env LDAP_ORGANISATION="Unitedstack Inc." /--env LDAP_DOMAIN="ustack.com" / --env LDAP_ADMIN_PASSWORD="admin_password" / -v pwd/containers/openldap/data:/var/lib/ldap / -v pwd/containers/openldap/slapd.d:/etc/ldap/slapd.d /--detach --name $NAME osixia/openldap:1.1.2
创建新用户,首先需要定义 ldif 文件,
new_user.ldif:dn: uid=test,dc=ustack,dc=com uid: test cn: test sn: 3 objectClass: topobjectClass: posixAccountobjectClass: inetOrgPersonloginShell: /bin/bashhomeDirectory: /home/testuidNumber: 1001gidNumber: 1001userPassword: 1q2w3e4rmail: test@example.comgecos: test
通过以下脚本创建新用户,其中 ldap_server 为 LDAP 服务容器名称。
docker cp new_user.ldif ldap_server:/ docker exec ldap_server ldapadd -x / -D "cn=admin,dc=ustack,dc=com" / -w admin_password /-f /new_user.ldif -ZZ
查看用户是否创建成功:
docker exec ldap_server ldapsearch -x -h localhost / -b dc=ustack,dc=com -D "cn=admin,dc=ustack,dc=com" / -w admin_password
检查 test 用户是否存在,若存在,则说明创建成功,否则需要使用 docker logs 查看日志。
配置 Harbor 使用 LDAP 认证
修改 harbor.cfg 文件关于 LDAP 配置项,如下
:auth_mode = ldap_auth ldap_url = ldap://42.62.x.x ldap_basedn = uid=%s,dc=ustack,dc=com
然后重新部署 Harbor:
./prepare docker-compose stop docker-compose rm -f docker-compose up -d
测试是否能够使用 test 用户登录:
docker login -u test -p 1q2w3e4r / -e test@example.com 42.62.x.x