Harbor是由VMware公司开源的企业级的Docker Registry管理项目,它包括权限管理(RBAC)、LDAP、日志审核、管理界面、自我注册、镜像复制和中文支持等功能。harbor项目是由VMware中国研发的团队负责开发,所以对国内非常友好。
使用
部署
安装Harbor,需要提前安装docker,和docker-compose,这边就不详细叙述了。当然这是单独部署harbor,也可以部署在k8s中,也可以使用helm部署到k8s中,都是差不多的。
1、下载installer
其实就是去harbor的github的release上下载一个版本:https://github.com/goharbor/harbor/releases
wget 'https://storage.googleapis.com/harbor-releases/release-1.8.0/harbor-offline-installer-v1.8.4-rc1.tgz' .
tar -zxvf harbor-offline-installer-v1.8.4-rc1.tgz
2、修改配置
下载下来之后解压缩,目录下会有harbor.conf,就是Harbor的配置文件了,修改hostname,harbor_admin_password。
#harbor.yml
cat harbor.yml |grep -v '#' |grep -v '^$'
hostname: registry.test.myop.com
http:
port: 80
harbor_admin_password: Harbor12345
database:
password: root123
data_volume: /data1/harbor
clair:
updaters_interval: 12
http_proxy:
https_proxy:
no_proxy: 127.0.0.1,localhost,core,registry
jobservice:
max_job_workers: 10
chart:
absolute_url: disabled
log:
level: info
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
_version: 1.8.0
#修改docker-compose.yml, 把 ports改为5000.
vim docker-compose.yml,
dns_search:
ports:
- 5000:5000
配置文件详解
主要参数
1、hostname:目标主机的主机名,用于访问UI和注册表服务。它应该是目标计算机的IP地址或完全限定域名(FQDN),例如192.168.1.10或reg.yourdomain.com。不要使用localhost或127.0.0.1用于主机名 - 注册表服务需要由外部客户端访问! 2、ui_url_protocol:(http或https。默认为http)用于访问UI和令牌/通知服务的协议。默认情况下,这是http。要设置https协议,如果启用了认证,则此参数必须为https。 3、db_password:用于db_auth的MySQL数据库的根密码。更改此密码以用于任何生产使用! 4、max_job_workers:(缺省值为3)作业服务中的最大复制worker数。对于每个图像复制作业,工作程序将存储库的所有标记同步到远程目标。增加此数量允许系统中更多的并发复制作业。但是,由于每个工人消耗一定量的网络/ CPU / IO资源,请根据主机的硬件资源仔细选择此属性的值。 5、customize_crt:(开启或关闭,默认为开启),如果此属性开启,在准备脚本创建注册表的令牌生成/验证私钥和根证书。当外部源提供密钥和根证书时,将此属性设置为off。以下属性:crt_country,crt_state,crt_location,crt_organization,crt_organizationalunit,crt_commonname,crt_email用作生成密钥的参数。当密钥和根证书由外部源提供时,将此属性设置为off。 6、ssl_cert:SSL证书的路径,仅在协议设置为https时应用。 7、ssl_cert_key:SSL密钥的路径,仅在协议设置为https时应用。 8、secretkey_path:用于加密或解密复制策略中远程注册表密码的密钥路径。 9、log_rotate_count:日志文件在被删除之前会被轮询log_rotate_count次数。如果count为0,则删除旧版本而不是轮询。 10、log_rotate_size:仅当日志文件大于log_rotate_size字节时才会轮换日志文件。如果大小后跟k,则大小以千字节为单位。如果使用M,则大小以兆字节为单位,如果使用G,则大小为千兆字节。 11、harbour_admin_password:管理员的初始密码。此密码仅在harbor首次发布时生效。之后,将忽略此设置,并且应在UI中设置管理员的密码。请注意,默认用户名/密码为admin / Harbor12345。
可选参数
1、电子邮件设置:Harbor需要这些参数才能向用户发送“密码重置”电子邮件,并且只有在需要该功能时才需要。还有,千万注意,在默认情况下SSL连接是没有启用-如果你的SMTP服务器需要SSL,但不支持STARTTLS,那么你应该通过设置启用SSL email_ssl = TRUE。 email_server = smtp.mydomain.com email_server_port = 25 email_username = sample_admin@mydomain.com email_password = abc email_from = admin \<sample_admin@mydomain.com\> email_ssl = false 2、auth_mode:使用的认证类型。默认情况下,它是db_auth,即凭据存储在数据库中。对于LDAP认证,请将其设置为ldap_auth。 ldap_url:LDAP端点URL(例如ldaps://ldap.mydomain.com)。 仅当auth_mode设置为ldap_auth时使用。 ldap_searchdn:具有搜索LDAP / AD服务器(例如uid=admin,ou=people,dc=mydomain,dc=com)的权限的用户的DN 。 ldap_search_pwd:由指定的用户的密码ldap_searchdn。 ldap_basedn:查找用户的基本DN,例如ou=people,dc=mydomain,dc=com。 仅当auth_mode设置为ldap_auth时使用。 ldap_filter:用于查找用户的搜索过滤器,例如(objectClass=person)。 ldap_uid:用于在LDAP搜索期间匹配用户的属性,可以是uid,cn,电子邮件或其他属性。 ldap_scope:用于搜索用户的范围,1-LDAP_SCOPE_BASE,2-LDAP_SCOPE_ONELEVEL,3-LDAP_SCOPE_SUBTREE。默认值为3。 3、self_registration:(on或off。默认为on)启用/禁用用户注册自己的能力。禁用时,新用户只能由管理员用户创建,只有管理员用户才能在Harbor中创建新用户。 注意:当auth_mode设置为ldap_auth时,将始终禁用自注册功能,并且将忽略此标志。 4、use_compressed_js:(on或off。默认为on)对于生产使用,将此标志设置为on。在开发模式下,将其设置为off,以便可以单独修改js文件。 5、token_expiration:令牌服务创建的令牌的过期时间(以分钟为单位),默认为30分钟。 6、verify_remote_cert:(on或off。默认为on)此标志确定当Harbor与远程注册表实例通信时是否验证SSL / TLS证书。将此属性设置为关闭将绕过SSL / TLS验证,这通常在远程实例具有自签名或不受信任的证书时使用。
后端存储调整
主要在common/templates/registry/config.yml文件,这块其实就是去改registry的配置文件。改完之后prepare一下,然后docker-compse up -d就可以了。
3、安装
直接执行安装脚本就行
#执行安装脚本
sh ./install.sh
[Step 0]: checking installation environment ...
Note: docker version: 18.06.1
Note: docker-compose version: 1.24.1
[Step 1]: loading Harbor images ...
b80136ee24a4: Loading layer [==================================================>] 34.25MB/34.25MB
[Step 2]: preparing environment ...
prepare base dir is set to /data1/software/harbor
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/nginx/nginx.conf
Generated configuration file: /config/core/env
Generated configuration file: /config/core/app.conf
Generated configuration file: /config/registry/config.yml
Generated configuration file: /config/registryctl/env
Generated configuration file: /config/db/env
Generated configuration file: /config/jobservice/env
Generated configuration file: /config/jobservice/config.yml
Generated and saved secret to file: /secret/keys/secretkey
Generated certificate, key file: /secret/core/private_key.pem, cert file: /secret/registry/root.crt
Generated configuration file: /compose_location/docker-compose.yml
Clean up the input dir
[Step 3]: starting Harbor ...
Creating network "harbor_harbor" with the default driver
Creating harbor-log ... done
Creating redis ... done
Creating harbor-db ... done
Creating registry ... done
Creating registryctl ... done
Creating harbor-core ... done
Creating harbor-jobservice ... done
Creating harbor-portal ... done
Creating nginx ... done
安装启动后可以查看相关组件的运行情况
# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
248ae75cf72b vmware/nginx-photon:v1.4.0 "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp, 0.0.0.0:4443->4443/tcp nginx
2f4278759096 vmware/harbor-jobservice:v1.4.0 "/harbor/start.sh" 4 seconds ago Up 4 seconds (health: starting) harbor-jobservice
5977ecfd082b vmware/harbor-ui:v1.4.0 "/harbor/start.sh" 5 seconds ago Up 4 seconds (health: starting) harbor-ui
ff6fc31844a9 vmware/harbor-db:v1.4.0 "/usr/local/bin/dock…" 5 seconds ago Up 3 seconds (health: starting) 3306/tcp harbor-db
2ed6ff381ab9 vmware/harbor-adminserver:v1.4.0 "/harbor/start.sh" 5 seconds ago Up 4 seconds (health: starting) harbor-adminserver
d3e1e93bce1b vmware/registry-photon:v2.6.2-v1.4.0 "/entrypoint.sh serv…" 5 seconds ago Up 4 seconds (health: starting) 5000/tcp registry
096310feb030 vmware/harbor-log:v1.4.0 "/bin/sh -c /usr/loc…" 6 seconds ago Up 5 seconds (health: starting) 127.0.0.1:1514->10514/tcp harbor-log
4、测试访问
安装完毕后可以测试访问页面: registry.test.myop.com 账号默认是admin,密码默认Harbor12345,这时候就能通过harbor的基本界面进行操作了。
基本使用
1、启停harbor
$ sudo docker-compose down -v
$ vim harbor.yml
$ sudo prepare
$ sudo docker-compose up -d
这个是docker-compose中的命令,k8s中一样使用kubectl或者helm就可以了。
2、https配置
修改配置文件sudo vim harbor.cfg
将hostname更改为xxxxxx.com,ui_url_protocol更改为https方式。
将ssl_cert以及ssl_cert_key的名字更改为你要生成证书的名字。
#The protocol for accessing the UI and token/notification service, by default it is http. #It can be set to https if ssl is enabled on nginx. ui_url_protocol = https #The path of cert and key files for nginx, they are applied only the protocol is set to https ssl_cert = /data/cert/server.crt ssl_cert_key = /data/cert/server.key
生成证书
官方文档有Harbor生成证书的说明,直接照做就好。
生成CA证书 openssl req \ -newkey rsa:4096 -nodes -sha256 -keyout ca.key \ -x509 -days 365 -out ca.crt 生成证书签名 openssl req \ -newkey rsa:4096 -nodes -sha256 -keyout yourdomain.com.key \ -out yourdomain.com.csr FQDN方式生成注册表主机的证书 openssl x509 -req -days 365 -in yourdomain.com.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out yourdomain.com.crt
以上yourdomain.com替换为要使用的FQDN必须和harbor中的hostname以及ssl_cert配置相同。
证书配置以及安装
获取yourdomain.com.crt和yourdomain.com.key文件后,可以将它们放入如下目录/root/cert/(我将放在/data/cert目录下):
cp yourdomain.com.crt /data/cert/ cp yourdomain.com.key /data/cert/
为Harbor生成配置文件:
sudo ./prepare
最后重启Harbor:
docker-compose up -d
3、登陆
无论采用http还是https的方式,在docker客户端远程登录Harbor都需要修改一些配置。
http
需要在启动参数中新增
--insecure-registry=192.168.26.252(Harbor地址)
可以是service启动文件docker.service文件,也可以是docker配置文件/etc/docker/daemon.json
然后就可以docker login [ip地址或域名]
https
在Docker客户端服务器上创建指定目录:/etc/docker/certs.d/[IP地址或域名](docker证书一般都在这个目录下,一般我们也可以去这个目录下找文件)
mkdir -p /etc/docker/certs.d/[IP地址或域名]
拷贝CA证书到上述目录中
然后就可以docker login [ip地址或域名]
登陆出错
Harbor是搭建完成了,在我们上传项目时可能会出现一些问题,在另外一个服务器(client)登录harbor,会出错!
$docker login registry.test.myop.com
Error response from daemon: Get https://registry.test.myop.com/v2/: dial tcp registry.test.myop.com:443: connect: connection refused
这是因为docker1.3.2版本开始默认docker registry使用的是https,我们设置Harbor默认http方式,所以当执行用docker login、pull、push等命令操作非https的docker regsitry的时就会报错。
解决方法
编辑harbor及client机器的docker配置文件/etc/docker/daemon.json
vim /etc/docker/daemon.json { "insecure-registries": [ "harbor_ip or harbor_domain" ] }
重启docker
#reload docker systemctl daemon-reload #docker ps |grep -v CONTAINER |awk '{print $1}'>docker_online.txt #cat docker_online.txt |while read line; do echo "$line"; docker start $line; done; #systemctl start docker #服务会停止,使用reload较好。 systemctl reload docker systemctl status docker.service -l
登录仓库
docker login registry.test.myop.com Username: admin Password: WARNING! Your password will be stored unencrypted in /root/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store
4、镜像管理
配置http镜像仓库可信任
vi /etc/docker/daemon.json {"insecure-registries":["registry.test.myop.com"]} systemctl restart docker
打标签
docker tag centos:6 registry.test.myop.com/library/centos:6
上传
docker push registry.test.myop.com/library/centos:6
下载
docker pull registry.test.myop.com/library/centos:6
示例
#推送之前先登录Harbor
docker login docker login registry.test.myop.com
admin
Harbor12345
提示success登录成功
查看自己有哪些镜像;docker images
把需要上传到Harbor的镜像运行如下命令就可以了
#镜像打标签
docker tag 镜像名:标签 私服地址/仓库项目名/镜像名:标签
#推送到私服
docker push 私服地址/仓库项目名/镜像名:标签
#从私服拉取镜像
docker pull 私服地址/仓库项目名/镜像名:标签
5、用户账户
Harbor支持两种身份验证方式:
Database(db_auth): 这种情况下,所有用户被存放在一个本地数据库
当注册或添加一个新的用户到Harbor中时,Harbor系统中的用户名、email必须是唯一的。密码至少要有8个字符长度,并且至少要包含一个大写字母(uppercase letter)、一个小写字母(lowercase letter)以及一个数字(numeric character)。
LDAP/Active Directory(ldap_auth): 在这种认证模式下,用户的credentials都被存放在外部的LDAP或AD服务器中,用户在那边完成认证后可以直接登录到Harbor系统。
当一个LDAP/AD用户通过username和password的方式登录进系统时,Harbor会用LDAP Search DN及LDAP Search Password绑定LDAP/AD服务器(请参看installation guide)。假如成功的话,Harbor会在LDAP的LDAP Base DN目录及其子目录来查询该用户。通过LDAP UID指定的一些属性(比如: uid、cn)会与username一起共同来匹配一个用户。假如被成功匹配,用户的密码会通过一个发送到LDAP/AD服务器的bind request所验证。假如LDAP/AD服务器使用自签名证书(self-signed certificate)或者不受信任的证书的话,请不要检查LDAP Verify Cert
6、项目管理
Harbor中的一个工程包含了一个应用程序所需要的所有repositories。在工程创建之前,并不允许推送镜像到Harbor中。Harbor对于project采用基于角色的访问控制。在Harbor中projects有两种类型:
- Public: 所有的用户都具有读取public project的权限, 其主要是为了方便你分享一些repositories
- Private: 一个私有project只能被特定用户以适当的权限进行访问
在登录之后,你就可以创建一个工程(project)。默认情况下,创建的工程都是私有的,你可以通过在创建时选中Access Level复选框来使创建的工程变为public的。
在项目中,你可以通过导航标签Logs选项卡来查看所有的日志,可以使用Configuration选项卡设置工程相关属性,可以使用member来新增和删除项目成员。
7、权限
Harbor基于角色的访问控制,与project关联的角色简单地分为Guest/Developer/Admin三类,角色/project/镜像三者之间进行关联,不同角色的权限不同,如下图
权限说明
角色 权限说明
Guest 对于指定项目拥有只读权限
Developer 对于指定项目拥有读写权限
ProjectAdmin 除了读写权限,同时拥有用户管理/镜像扫描等管理权限
我们可以到数据库中看一下角色管理,Harbor的数据库的信息非常简单,从Access表中可以看到其将访问权限进行地划分
MariaDB [registry]> select * from access;
+-----------+-------------+-------------------------------+
| access_id | access_code | comment |
+-----------+-------------+-------------------------------+
| 1 | M | Management access for project |
| 2 | R | Read access for project |
| 3 | W | Write access for project |
| 4 | D | Delete access for project |
| 5 | S | Search access for project |
+-----------+-------------+-------------------------------+
5 rows in set (0.00 sec)
项目级别的角色目前的5种细粒度的访问权限分别为:M/R/W/D/S
访问权限 说明
M 管理操作的权限
R 读操作的权限
W 写操作的权限
D 删除访问权限的权限
R 查询权限
我们再来看项目权限和角色的关联
MariaDB [registry]> select * from role;
+---------+-----------+-----------+--------------+
| role_id | role_mask | role_code | name |
+---------+-----------+-----------+--------------+
| 1 | 0 | MDRWS | projectAdmin |
| 2 | 0 | RWS | developer |
| 3 | 0 | RS | guest |
+---------+-----------+-----------+--------------+
3 rows in set (0.00 sec)
很明显的就能看出对应的角色的权限,除此之外,还有两种系统级别的角色,在harbor创建的时候就被创建出来了。
角色 权限说明
SysAdmin 具有最多的权限,除了以上提及的权限,可以跨项目操作,查询所有项目,设定某个用户作为管理员以及扫描策略等
Anonymous: 没有登录的用户被视作匿名用户。匿名用户对private的项目不具访问权限,对public的项目具有只读权限
6、镜像复制
镜像复制被用于从一个Harbor实例向另一个Harbor实例复制repositories。,Harnor镜像复制可在不同的数据中心、不同的运行环境之间同步镜像,并提供友好的管理界面,大大简化了实际运维中的镜像管理工作.
Harbor仍然以“项目”为中心, 通过对项目配置“复制策略”,标明需要复制的项目以及镜像。管理员在复制策略中指明目标实例,即复制的“目的地”,并对它的地址和连接时使用的用户名密码进行设置。当复制策略被激活时,源项目下的所有镜像,都会被复制到目标实例;此外,当源项目下的镜像被添加或删除(push或delete), 只要策略还在激活状态,镜像的变化都会同步到目标实例上去, 如下图所示:
在较大的容器集群中,往往需要多个Registry服务器做负载均衡,可以采用主从发布模式,镜像只需要发布一次,就可以推送到多个Registry实例中。同时还支持双主复制和层次型的多级镜像发布,如下图所示:
具体的搭建和使用这边就不多说了。
架构
从架构图中可以看出,Harbor由6个大的模块所组成:
- Proxy: Harbor的registry、UI、token services等组件,都处在一个反向代理后边。该代理将来自浏览器、docker clients的请求转发到后端服务上。
- Registry: 负责存储Docker镜像,以及处理Docker push/pull请求。因为Harbor强制要求对镜像的访问做权限控制, 在每一次push/pull请求时,Registry会强制要求客户端从token service那里获得一个有效的token。
- Core services: Harbor的核心功能,主要包括如下3个服务:
- UI: 作为Registry Webhook, 以图像用户界面的方式辅助用户管理镜像。
- WebHook是在registry中配置的一种机制, 当registry中镜像发生改变时,就可以通知到Harbor的webhook endpoint。Harbor使用webhook来更新日志、初始化同步job等。
- Token service会根据该用户在一个工程中的角色,为每一次的push/pull请求分配对应的token。假如相应的请求并没有包含token的话,registry会将该请求重定向到token service。
- Database 用于存放工程元数据、用户数据、角色数据、同步策略以及镜像元数据。
- Job services: 主要用于镜像复制,本地镜像可以被同步到远程Harbor实例上。
- Log collector: 负责收集其他模块的日志到一个地方
这里我们与运行的7个容器对比,多了一个harbor-adminserver主要是作为一个后端的配置数据管理,并没有太多的其他功能。harbor-ui所要操作的所有数据都通过harbor-adminserver这样一个数据配置管理中心来完成。
其他组件
harbor的发展,有着很多其他的组件逐渐的成熟被需要,所以很多组件也被加入到了harbor生态中。
clair
harbor仓库中的镜像扫描这个功能,看似很高大上,其实等你了解了它的底层原理与流程,你就会发现就是做了那么一件事而已,用通俗的一句话概括,就是找到每个镜像文件系统中已经安装的软件包与版本,然后跟官方系统公布的信息比对,官方已经给出了在哪个系统版本上哪个软件版本有哪些漏洞,比如Debian 7系统上,nginx 1.12.1有哪些CVE漏洞,通过对逐个安装的软件包比对,就能知道当前这个镜像一共有多少CVE。
镜像就是由许多Layer层组成的文件系统,重要的是每个镜像有一个manifest,这个东西跟springboot中的一个概念,就是文件清单的意思。一个镜像是由许多Layer组成,总需要这个manifest文件来记录下到底由哪几个层联合组成的。要扫描分析一个镜像,首先你就必须获取到这个镜像的manifest文件,通过manifest文件获取到镜像所有的Layer的地址digest,digest在docker镜像存储系统中代表的是一个地址,类似操作系统中的一个内存地址概念,通过这个地址,可以找到文件的内容,这种可寻址的设计是v2版本的重大改变。在docker hub储存系统中,所有文件都是有地址的,这个digest就是由某种高效的sha算法通过对文件内容计算出来的。
clair是 coreos 开源的容器漏洞扫描工具,在容器逐渐普及的今天,容器镜像安全问题日益严重。clair 是目前少数的开源安全扫描工具,主要提供OS(centos,debian,ubuntu等)的软件包脆弱性扫描。clair的可以单机部署也可以部署到k8s上,可以与现有的registry集成。harbor 很好的整合了 clair ,通过简单的UI就可以对上传的镜像扫描,还可以通过每天的定时扫描对所有镜像进行统一扫描,架构如下:
Clair主要包括以下模块:
获取器(Fetcher)- 从公共源收集漏洞数据
检测器(Detector)- 指出容器镜像中包含的Feature
容器格式器(Image Format)- Clair已知的容器镜像格式,包括Docker,ACI
通知钩子(Notification Hook)- 当新的漏洞被发现时或者已经存在的漏洞发生改变时通知用户/机器
数据库(Databases)- 存储容器中各个层以及漏洞
Worker - 每个Post Layer都会启动一个worker进行Layer Detect
具体的部署官方也有,主要是用官方提供的镜像进行操作,目前也在发展中,可以集成到harbor中用启动参数进行启动,这边不多说。
我们主要讲一下他的工作流程
Clair定期从配置的源获取漏洞元数据然后存进数据库。
客户端使用Clair API处理镜像,获取镜像的特征并存进数据库。
客户端使用Clair API从数据库查询特定镜像的漏洞情况,为每个请求关联漏洞和特征,避免需要重新扫描镜像。
当更新漏洞元数据时,将会有系统通知产生。另外,还有webhook用于配置将受影响的镜像记录起来或者拦截其部署。
具体针对镜像的校验过程
1.UI向Job发起镜像扫描请求,参数中包含了仓库名称以及tag
2.Job收到请求之后,向registry发起一个Head请求(/v2/nginx/manifest/v1.12.1),判断当前镜像的manifest是否存在,取出当前manifest的digest,这个digest是存放在响应头中的Docker-Content-Digest。
3.Job把第2步获取到的digest以及仓库名、tag作为一条记录插入job表中,job的状态为pending。
这个时候Job系统则会新建一个扫描任务的job进行调度,这里则涉及到一个状态机处理流程。
4.Job系统通过manifest文件获取镜像的所有Layer digest,针对每一层,封装一个ClairLayer参数对象,然后根据层的数量,循环请求Clair系统,ClairLayer参数结构如下:
Name: sha256:7d99455a045a6c89c0dbee6e1fe659eb83bd3a19e171606bc0fd10eb0e34a7dc
Headers: tokenHeader,
Format: "Docker",
Path: http://registry:5000/v2/nginx/blobs/7d99455a045a6c89c0dbee6e1fe659eb83bd3a19e171606bc0fd10eb0e34a7dc
ParentName: a55bba68cd4925f13c34562c891c8c0b5d446c7e3d65bf06a360e81b993902e1
5.Clair系统收到请求之后,根据ParentName首先校验父Layer是否存在,不存在则报错。
我们正常除了给容器做镜像扫描,还会将Clair可以集成到CI/CD管道中,如此一来当生成镜像时,将镜像推送到仓库之后触发Clair扫描该镜像的请求。 集成思路如下:
用户推送镜像到容器仓库,仓库根据设置的黑白名单选择是否调用Clair进行扫描
一旦触发Clair扫描,则等待扫描结果返回,然后通知用户
如果发现漏洞,则CI也同时阻止CD流程启动,否则CD流程开启
目前Docker Hub上的镜像上大部分都是存在漏洞的,所以安全扫描还是很有必要的。
Notary
Notary是一套docker镜像的签名工具, 用来保证镜像在pull,push和传输工程中的一致性和完整性。避免中间人攻击,避免非法的镜像更新和运行。
可以看见只有认证的签名的镜像才能进行pull,push,从而保证仓库的安全。具体可以查看官网。
高可用
目前有两种主流的方案来解决这个问题:
双主复制
多harbor实例共享后端存储
双主复制
1、主从同步
主从复制的原理我们已经在上面讲过了,harbor官方默认提供主从复制的方案来解决镜像同步问题,通过复制的方式,我们可以实时将测试环境harbor仓库的镜像同步到生产环境harbor,类似于如下流程:
在实际生产运维的中,往往需要把镜像发布到几十或上百台集群节点上。这时,单个Registry已经无法满足大量节点的下载需求,因此要配置多个Registry实例做负载均衡。手工维护多个Registry实例上的镜像,将是十分繁琐的事情。Harbor可以支持一主多从的镜像发布模式,可以解决大规模镜像发布的难题:
只要往一台Registry上发布,镜像就像“仙女散花”般地同步到多个Registry中,高效可靠。
如果是地域分布较广的集群,还可以采用层次型发布方式,如从集团总部同步到省公司,从省公司再同步到市公司:
然而单靠主从同步,仍然解决不了harbor主节点的单点问题。
2、双主复制
所谓的双主复制其实就是复用主从同步实现两个harbor节点之间的双向同步,来保证数据的一致性,然后在两台harbor前端顶一个负载均衡器将进来的请求分流到不同的实例中去,只要有一个实例中有了新的镜像,就是自动的同步复制到另外的的实例中去,这样实现了负载均衡,也避免了单点故障,在一定程度上实现了Harbor的高可用性:
这个方案有一个问题就是有可能两个Harbor实例中的数据不一致。假设如果一个实例A挂掉了,这个时候有新的镜像进来,那么新的镜像就会在另外一个实例B中,后面即使恢复了挂掉的A实例,Harbor实例B也不会自动去同步镜像,这样只能手动的先关掉Harbor实例B的复制策略,然后再开启复制策略,才能让实例B数据同步,让两个实例的数据一致。
根据我的使用经验,在实际生产使用中,主从复制十分的不靠谱。所以一般企业都是会使用下面这种方案。
多harbor实例共享后端存储
共享后端存储算是一种比较标准的方案,就是多个Harbor实例共享同一个后端存储,任何一个实例持久化到存储的镜像,都可被其他实例中读取。通过前置LB进来的请求,可以分流到不同的实例中去处理,这样就实现了负载均衡,也避免了单点故障:
这个方案在实际生产环境中部署需要考虑三个问题:
1、共享存储的选取,Harbor的后端存储目前支持AWS S3、Openstack Swift, Ceph等,在我们的测试环境里,都可以直接使用nfs
2、Session在不同的实例上共享,这个现在其实已经不是问题了,在最新的harbor中,默认session会存放在redis中,我们只需要将redis独立出来即可。可以通过redis sentinel或者redis cluster等方式来保证redis的可用性。在我们的实验环境里,仍然使用单台redis
3、Harbor多实例数据库问题,这个也只需要将harbor中的数据库拆出来独立部署即可。让多实例共用一个外部数据库,数据库的高可用也可以通过数据库的高可用方案保证。
API
Harbor 提供了一些列 API 用于镜像仓库的管理,完整的 API 文档可以查看 Harbor 的 Swagger文件:https://raw.githubusercontent.com/goharbor/harbor/master/docs/swagger.yaml 可以通过 Swagger 工具 https://editor.swagger.io/ 在线查看,将上述文件内容黏贴进改工具的编辑框中即可。这边就不详细说明了,开发的时候直接查询就好。
原理
登陆
在我们使用docker login harborip之后,Docker Client会发送一个HTTP GET请求到192.168.1.10/v2/地址处,Harbor的不同容器组件将会按照如下步骤进行处理:
1、首先,该请求将会被监听在80端口上的代理容器所接收到。容器中的Nginx将会把该请求转发给后端的Registry容器
2、由于registry容器已经被配置为基于token的认证,因此其会返回一个401错误码,用于通知docker客户端从一个指定的URL处获得一个有效的token。在Harbor中,该URL会指向Core service中的token service。
3、当Docker Client接收到这个错误码,其就会发送一个请求到token service URL,会根据HTTP基本认证协议在请求头中内嵌username和password相关信息
4、在该请求被发送到代理的80端口上后,Nginx会根据预先所配置的规则将请求转发到UI容器上。UI容器中的token service接收到该请求之后,其就会对该请求进行解码然后获得相应的用户名及密码
5、在成功获得用户名及密码之后,token Service就会检查mysql数据库以完成用户的认证。当token service被配置为LDAP/AD认证的时候,其就会通过外部的LDAP/AD服务来完成认证。在成功认证之后,token Service就会返回一个认证成功的http code, Http body部分会返回一个通过private key所产生的token
到这里为止,Docker login就处理完成。Docker client会将步骤©所产生的username及password编码后保存到一个隐藏的文件中
上传
省略nginx转发,直接展示组件之间的交互
1、首先,docker client执行类似登录时的流程发送一个请求到registry,然后返回一个token service的URL
2、然后,docker client通过提供一些额外的信息与ui/token交互以获得push镜像library/hello-world的token
3、在成功获得来自Nginx转发的请求之后,Token Service查询数据库以寻找用户推送镜像的角色及权限。假如用户有相应的权限,token service就会编码相应的push操作信息,并用一个private key进行签名。然后返回一个token给Docker client
4、在docker client获得token之后,其就会发送一个push请求到registry,在该push请求的头中包含有上面返回的token信息。一旦registry收到了该请求,其就会使用public key来解码该token,然后再校验其内容。该public key对应于token service处的private key。假如registry发现该token有效,则会开启镜像的传输流程。