一、关于Harbor
Harbor是一个企业级开源镜像仓库,也是首个加入 CNCF 且原创于中国的项目,时间于2018年8月。在2014年由VMware中国研发中心内部立项和使用,并于2016年对社区开源。Harbor 项目扎根、成长和壮大于中国社区,在 CNCF 中是唯一原生支持中文的项目,深受中国用户推崇和喜爱。
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器。Harbor用于容器镜像管理,主要提供基于角色的镜像访问控制、镜像复制、镜像漏洞分析、镜像验真和操作审计等功能。迄今为止,Harbor 在 GitHub 上已获得超过 4700+ 颗星。
- 基于角色的访问控制
用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。
- 镜像复制
镜像可以在多个Registry实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景。
- 图形化用户界面
用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间。
- AD/LDAP 支持
Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理。
- 审计管理
所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。
- 国际化
已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。
- RESTful API
RESTful API 提供给管理员对于Harbor更多的操控, 使得与其它管理软件集成变得更容易。
- 部署简单
提供在线(online)和离线(offline)两种安装工具, 也可以安装到vSphere平台(OVA方式)虚拟设备。
<Harbor自传篇>
二、架构分解
如上图所示,Harbor包含6个组件:
Proxy
Harbor的registry, UI, token等服务,通过一个前置的反向代理统一接收浏览器、Docker客户端的请求,并将请求转发给后端不同的服务。
Registry
负责储存Docker镜像,并处理 dockerpush/pull 命令。由于我们要对用户进行访问控制,即不同用户对Docker image有不同的读写权限,Registry会指向一个token服务,强制用户的每次docker pull/push请求都要携带一个合法的token,Registry会通过公钥对 token 进行解密验证。
Core services
这是Harbor的核心功能,主要提供以下服务:
UI
提供图形化界面,帮助用户管理registry上的镜像(image), 并对用户进行授权。
webhook
为了及时获取registry上image状态变化的情况, 在Registry上配置webhook,把状态变化传递给UI模块。
token
负责根据用户权限给每个docker push/pull命令签发token.Docker客户端向Regiøstry服务发起的请求,如果不包含token,会被重定向到这里,获得token后再重新向Registry进行请求。
Database
为core services提供数据库服务,负责存储项目,用户,角色,复制策略和图像的元数据。
Job services
用于映像复制的本地映像可以复制(同步)到其他Harbor实例。
Log collector
为了帮助监控Harbor运行,负责收集其他组件的log,供日后进行分析。
Harbor的每个组件都是以Docker容器的形式构建的,因此很自然地,我们使用Docker Compose来对它进行部署。
三、安装Harbor
Harbor被部署为多个Docker容器,因此可以部署在任何支持Docker的Linux发行版上。目标主机需要安装Python,Docker和Docker Compose。
1 2 3 4 |
$ uname -r 3.10.0-327.el7.x86_64 $ yum install docker docker-compose |
1. 下载安装程序
安装程序的二进制文件可以从发布页面下载。选择在线或离线安装程序。使用tar命令解压缩包。
Online installer:安装程序从Docker hub下载Harbor的图像。因此,安装程序的尺寸非常小。
Offline installer:当主机没有Internet连接时,请使用此安装程序。安装程序包含预先构建的图像,因此其大小较大。
本指南介绍使用联机或脱机安装程序安装和配置Harbor的步骤,安装过程几乎相同。
此外,社区还创建了Kubernetes的部署说明。有关详细信息,请参阅Harbor on Kubernetes。
2. 配置Harbor
配置参数位于文件harbor.cfg中。
harbor.cfg中有两类参数,所需参数和可选参数。
- 所需参数:这些参数需要在配置文件harbor.cfg中设置,如果用户更新它们并运行install.sh脚本重新安装Harbour,参数将生效。
- 可选参数:这些参数对于更新是可选的,即用户可以将其保留为默认值,并在启动Harbour后在Web UI上进行更新。如果它们设置在harbor.cfg中,它们只会在第一次启动Harbour时生效。随后在harbor.cfg对这些参数的更新将被忽略。
注意:如果你选择通过 Web UI 设置这些参数,请确保在启动Harbour后立即执行此操作。具体来说,你必须在注册或在Harbor中创建任何新用户之前设置所需的auth_mode。当系统中有用户时(除了默认的admin用户), auth_mode不能被修改。
所需参数:
hostname:用于访问用户界面和register服务。它应该是目标机器的IP地址或完全限定的域名(FQDN),例如192.168.1.10或reg.yourdomain.com。不要使用localhost或127.0.0.1为主机名。
ui_url_protocol:http或https,默认为http;用于访问UI和令牌/通知服务的协议。如果公证处于启用状态,则此参数必须为https。
max_job_workers:镜像复制作业线程。
db_password:用于db_auth的MySQL数据库的root密码。
customize_crt:打开或关闭,默认打开,打开此属性时,准备脚本创建私钥和根证书,用于生成/验证 register 令牌。当由外部来源提供密钥和根证书时,将此属性设置为off。
ssl_cert:SSL证书的路径,仅当协议设置为https时才应用。
ssl_cert_key:SSL密钥的路径,仅当协议设置为https时才应用。
secretkey_path:用于在复制策略中加密或解密远程 register 密码的密钥路径。
log_rotate_count:日志文件在被删除之前会被轮换log_rotate_count次。如果count为0,则删除旧版本而不是旋转。
log_rotate_size:仅当日志文件大于log_rotate_size字节时才会轮换日志文件。如果大小后跟k,则假定大小以千字节为单位。如果使用M,则大小以兆字节为单位,如果使用G,则大小为千兆字节。大小100,大小100k,大小100M和大小100G都是有效的。
http_proxy:为Clair配置http代理,例如 http://my.proxy.com:3128。
https_proxy:为Clair配置https代理,例如 http://my.proxy.com:3128。
no_proxy:为Clair配置无代理,例如 127.0.0.1 localhost,core,registry。
可选参数:
Email settings:Harbor需要这些参数才能向用户发送“密码重置”电子邮件,并且只有在需要该功能时才需要。另外,请注意,在默认情况下SSL连接时没有启用-如果你的SMTP服务器需要SSL,但不支持STARTTLS,那么你应该通过设置启用SSL email_ssl = TRUE。
1 2 3 4 5 6 7 |
email_server = smtp.mydomain.com email_server_port = 25 email_identity = email_username = sample_admin@mydomain.com email_password = abc email_from = admin sample_admin@mydomain.com email_ssl = false |
harbour_admin_password:管理员的初始密码,这个密码只在Harbour第一次启动时生效。之后,此设置将被忽略,并且应在UI中设置管理员的密码。请注意,默认的用户名/密码是 admin/Harbor12345。
auth_mode:使用的认证类型,默认情况下,它是db_auth,即凭据存储在数据库中。对于LDAP身份验证,请将其设置为ldap_auth。
1 2 3 4 5 6 7 |
ldap_url = ldaps://ldap.mydomain.com ldap_searchdn = uid=searchuser,ou=people,dc=mydomain,dc=com ldap_search_pwd = password ldap_basedn = ou=people,dc=mydomain,dc=com ldap_uid = uid ldap_scope = 3 ldap_timeout = 5 |
self_registration:( 打开或关闭,默认打开)启用/禁用用户注册功能。禁用时,新用户只能由Admin用户创建,只有管理员用户可以在Harbour中创建新用户。 注意:当auth_mode设置为ldap_auth时,自注册功能将始终处于禁用状态,并且该标志被忽略。
token_expiration:由令牌服务创建的令牌的到期时间(分钟),默认为30分钟。
project_creation_restriction:用于控制哪些用户有权创建项目的标志。默认情况下,每个人都可以创建一个项目,设置为“adminonly”,这样只有admin可以创建项目。
verify_remote_cert:( 打开或关闭,默认打开)此标志决定了当Harbour与远程register实例通信时是否验证SSL/TLS证书。将此属性设置为off将绕过SSL/TLS验证,这在远程实例具有自签名或不可信证书时经常使用。
配置存储后端(可选)
另外,默认情况下,Harbour将镜像存储在本地文件系统上。在生产环境中,你可以考虑使用其他存储后端而不是本地文件系统,如S3,Openstack Swift,Ceph等。你需要更新common/templates/registry/config.yml文件。例如,如果你使用Openstack Swift作为存储后端,那么该部分可能如下所示:
1 2 3 4 5 6 7 8 9 |
storage: swift: username: admin password: ADMIN_PASS authurl: http://keystone_addr:35357/v3/auth tenant: admin domain: default region: regionOne container: docker_images |
3. 安装Harbor
配置完成就可以启动Harbor了,进入到被解压后的二进制程序目录,然后执行 install.sh 安装脚本。
- 默认安装(没有Notary/Clair)
Harbor已与Notary和Clair集成(用于漏洞扫描)。但是,默认安装不包括Notary或Clair服务。如下操作:
1 |
$ sudo ./install.sh |
查看启动镜像
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
$ docker-compose ps Name Command State Ports ---------------------------------------------------------------------------------------------------------------------------------- harbor-adminserver /harbor/start.sh Up (healthy) harbor-core /harbor/start.sh Up (healthy) harbor-db /entrypoint.sh postgres Up (healthy) 5432/tcp harbor-jobservice /harbor/start.sh Up harbor-log /bin/sh -c /usr/local/bin/ ... Up (healthy) 127.0.0.1:1514->10514/tcp harbor-portal nginx -g daemon off; Up (healthy) 80/tcp nginx nginx -g daemon off; Up (healthy) 0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp, 0.0.0.0:80->80/tcp redis docker-entrypoint.sh redis ... Up 6379/tcp registry /entrypoint.sh /etc/regist ... Up (healthy) 5000/tcp registryctl /harbor/start.sh Up (healthy) |
如果一切正常,你应该可以打开浏览器访问 http://reg.yourdomain.com 的管理页面(将 reg.yourdomain.com 更改为你的主机名在 harbor.cfg 文件)。请注意,默认的管理员用户名/密码是:admin/Harbor12345
。
至此, Harbor已经搭建完成,具体在 WEB UI 下面操作也是非常的简单,只有几个选项。
登录管理员界面后可以创建一个新项目,例如myproject
。然后,你可以使用docker命令在本地通过127.0.0.1来登录和推送镜像了(默认情况下,Register服务器在端口80上侦听),首先登录Harbor:
1 2 3 4 5 6 7 8 9 |
# 登录Harbor; $ docker login -u admin -p Harbor12345 http://127.0.0.1 Login Succeeded # 镜像打tag; $ docker tag wordpress:latest 127.0.0.1/myproject/wordpress:mytag # 上传镜像到Harbor; $ docker push 127.0.0.1/myproject/wordpress:mytag |
都操作成功之后,在Harbor界面 myproject 目录下就可以看见这个镜像,以及这个镜像的一些信息:
但是,以上操作都是在Harbor本地操作,如果其他客户端操作Harbor,就会报如下错误:
1 2 |
$ docker login -u admin -p Harbor12345 http://10.10.0.109 Error response from daemon: Get https://10.10.0.109/v1/users/: dial tcp 10.10.0.109:443: getsockopt: connection refused |
重要信息:由于Harbor的默认安装使用HTTP,而Register v2版本开始必须使用HTTPS,因此你需要将该选项--insecure-registry
添加到客户端的Docker守护程序并重新启动Docker服务。在Docker客户端配置如下:
1 2 |
$ cat /etc/docker/daemon.json { "insecure-registries":["10.10.0.109:80"] } |
然后重启docker,再次登录就可以了:
1 2 3 |
$ systemctl restart docker $ docker login -u admin -p Harbor12345 10.10.0.109:80 Login Succeeded |
- 使用Notary安装Harbor
要使用Notary安装Harbor,请在运行时 install.sh 时添加一个参数:
1 |
$ ./install.sh --with-notary |
注:对于使用Notary进行安装,必须将参数 ui_url_protocol 设置为“HTTPS”。有关配置HTTPS的信息,请参阅以下部分。
有关Notary和Docker Content Trust的更多信息,请参阅Docker的文档:https://docs.docker.com/engine/security/trust/content_trust
- 使用Clair安装Harbor
要使用Clair服务安装Harbour,请在运行 install.sh 时添加参数:
1 |
$ sudo ./install.sh --with-clair |
有关Clair的更多信息,请参阅Clair的文档:https://coreos.com/clair/docs/2.0.1
四、使用HTTPS访问配置Harbor
由于Harbor未附带任何证书,因此默认情况下使用HTTP来提供 Register 请求。但是,强烈建议为任何生产环境启用安全性。Harbor有一个Nginx实例作为所有服务的反向代理,你可以使用 prepare 脚本配置Nginx以启用https。
在测试或开发环境中,你可以选择使用自签名证书,而不是来自受信任的第三方CA的证书。以下内容将向你展示如何创建自己的CA,并使用你的CA签署服务器证书和客户端证书。
生成CA证书
安装之前首先需要在Harbor服务器上创建ca证书和私钥,以及签发Harbor要使用的证书和私钥。假设你的 register 要访问的域名 dockerhub.ywnds.com,并且其DNS记录指向你正在运行Harbor的主机。你首先应该从CA获得一个证书。证书通常包含 .crt 文件和 .key 文件,例如 ywnds.com.crt 和 ywnds.com.key。创建你自己的CA证书,我这里使用的是私钥和证书一起生成,你也可以先生成私钥然后再生成证书。
1 2 3 4 |
openssl req -newkey rsa:4096 -nodes -sha256 -x509 -days 365 \ -subj "/C=cn/ST=sh/L=sh/O=ca/OU=ca/CN=10.10.0.109" \ -keyout /data/cert/ca.key \ -out /data/cert/ca.crt |
生成Register证书签名请求
如果使用像 dockerhub.ywnds.com 这样的FQDN连接register主机,则必须使用 dockerhub.ywnds.com 作为CN(Common Name)。否则,如果你使用IP地址连接你的register主机,CN可以是任何类似你的名字等等:
1 2 3 4 |
openssl req -newkey rsa:4096 -nodes -sha256 \ -subj "/C=cn/ST=sh/L=sh/O=ywnds/OU=ywnds/CN=10.10.0.109" \ -keyout /data/cert/ywnds.com.key \ -out /data/cert/ywnds.com.csr |
生成Register主机的证书
如果你使用的是像 dockerhub.ywnds.com 这样的FQDN来连接你的 register 主机,请运行以下命令以生成 register 主机的证书:
1 2 3 4 5 6 |
$ openssl x509 -req -days 365 \ -in /data/cert/ywnds.com.csr \ -CA /data/cert/ca.crt \ -CAkey /data/cert/ca.key \ -CAcreateserial \ -out /data/cert/ywnds.com.crt |
如果你使用的是IP,比如你的 register 主机是 10.10.0.109,你可以运行下面的命令生成证书:
1 2 3 4 5 6 7 |
$ echo subjectAltName = IP:10.10.0.109 > extfile.cnf $ openssl x509 -req -days 365 \ -in /data/cert/ywnds.com.csr \ -CA /data/cert/ca.crt -CAkey /data/cert/ca.key \ -CAcreateserial \ -extfile extfile.cnf \ -out /data/cert/ywnds.com.crt |
安装配置
接下来,编辑 harbor.cfg 文件,更新主机名和协议,并更新属性 ssl_cert 和 ssl_cert_key:
1 2 3 4 5 6 7 8 9 |
# set hostname hostname = 10.10.0.109:443 # set ui_url_protocol ui_url_protocol = https # set certificate ssl_cert = /data/cert/ywnds.com.crt ssl_cert_key = /data/cert/ywnds.com.key |
为Harbour生成配置文件(harbor目录下执行,如果有配置错误会报错这里):
1 |
$ ./prepare |
如果Harbor已经在运行,请停止并删除现有的实例,但是你的镜像数据会保留在文件系统中。
1 |
$ docker-compose down -v |
最后重启Harbour:
1 |
$ docker-compose up -d |
为Harbour设置HTTPS后,可以通过以下步骤进行验证:
1. 打开浏览器并输入地址:https://10.0.0.109。它应该显示Harbor的用户界面。
2. 请注意,即使我们通过自签名CA签署证书并将CA部署到上述位置,某些浏览器仍可能出于安全原因显示有关证书颁发机构(CA)未知的警告。这是因为自签名CA本质上不是受信任的第三方CA,你可以自行将CA导入浏览器以解决警告,或者忽略警告。
3. 在具有Docker守护进程的机器上,确保选项--insecure-registry
不存在,并且你必须将上述步骤中生成的ca.crt复制到/etc/docker/certs.d/reg.yourdomain.com(或你的register主机IP),如果该目录不存在,请创建它。如果你将nginx端口443映射到另一个端口,则应该创建目录/etc/docker/certs.d/reg.yourdomain.com:port(或你的 register 主机IP:端口)。
为Docker配置服务器证书,密钥和CA
Docker守护程序将 .crt 文件解释为CA证书,将 .cert 文件解释为客户端证书。
将服务器 ywnds.com.crt 转换为 ywnds.com.cert:
1 |
$ openssl x509 -inform PEM -in /data/cert/ywnds.com.crt -out /data/cert/ywnds.com.cert |
上传 ywds.com.cert,ywnds.com.key和ca.crt 文件到Docker客户端,如下操作:
1 |
$ mkdir /etc/docker/certs.d/10.10.0.109:443/ |
以下说明了使用自定义证书的配置结构:
1 2 3 4 5 |
/etc/docker/certs.d/ └── 10.10.0.109:443 ├── ywnds.com.cert <-- CA签名的服务器证书 ├── ywnds.com.key <-- CA签名的服务器密钥 └── ca.crt <-- CA证书 |
请注意,你可能需要在操作系统级别信任该证书。请参阅下面的故障排除部分。
然后运行任何docker命令来验证设置,例如:
1 2 |
$ docker login -u admin -p Harbor12345 https://10.10.0.109:443 Login Succeeded |
认证成功之后,可以进行镜像上传下载了。
参考:Configuring Harbor with HTTPS Access
五、Harbor实现
1. Docker login的流程
使用docker login登陆Harbor
1 |
$ docker login -u admin -p Harbor12345 http://10.10.0.109 |
当用户输入所需信息并点击回车后,Docker客户端会向地址”10.10.0.109/v1/”发出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协议的Basic Authentication规范,将用户名密码组合并编码,放在请求头部(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 image:
1 2 3 4 5 |
# 创建一个镜像; $ docker tag wordpress 10.10.0.109/myproject/wordpress # push镜像到harbor; $ docker push 10.10.0.109/myproject/wordpress |
a) 首先,docker客户端会重复login的过程,首先发送请求到registry,之后得到token服务的地址;
b) 之后,Docker客户端在访问ui容器上的token服务时会提供额外信息,指明它要申请一个对wordpress进行push操作的token;
c) token服务在经过Nginx转发得到这个请求后,会访问数据库核实当前用户是否有权限对该image进行push。如果有权限,它会把image的信息以及push动作进行编码,并用私钥签名,生成token返回给Docker客户端;
d) 得到token之后Docker客户端会把token放在请求头部,向registry发出请求,试图开始推送image。Registry收到请求后会用公钥解码token并进行核对,一切成功后,image的传输就开始了。
六、管理Harbor
你可以使用docker-compose来管理Harbor。一些有用的命令如下所示(必须在与docker-compose.yml相同的目录中运行)。
停止/启动/重启Harbor:
1 2 3 |
$ docker-compose stop $ docker-compose start $ docker-compose restart |
要更改Harbour的配置,请先停止现有的Harbour实例并更新harbor.cfg。然后运行prepare脚本来填充配置。最后重新创建并启动Harbour的实例:
1 2 3 4 |
$ docker-compose down -v $ vim harbor.cfg $ ./prepare $ docker-compose up -d |
配置Harbour在自定义端口上侦听。默认情况下,Harbour侦听端口80(HTTP)和443(HTTPS,如果已配置)同时用于管理界面和docker命令,则可以使用定制的命令对其进行配置。修改docker-compose.yml文件,将里面的端口替换为自定义的端口,例如8888:80。
<参考>
https://github.com/vmware/harbor/blob/master/docs/user_guide.md
https://github.com/vmware/harbor/blob/master/docs/installation_guide.md