harbor镜像仓库原理和安装
源地址:harbor镜像仓库原理和安装
目录
------------------------------------------------------------------------
一:Harbor简介
Harbor是一个用于存储和分发Docker镜像的企业级Registry服务器。
Harbor和Registry都是Docker的镜像仓库,但是Harbor作为更多企业的选择,是因为相比较于Regisrty来说,它具有很多的优势。
1. docker registry的缺点:
- 缺少认证机制,任何人都可以随意拉取及上传镜像,安全性缺失
- 缺乏镜像清理机制,镜像可以push却不能删除,日积月累,占用空间会越来越大
- 缺乏相应的扩展机制
2. Harbor优点
a.提供分层传输机制,优化网络传输
Docker镜像是是分层的,而如果每次传输都使用全量文件(所以用FTP的方式并不适合),显然不经济。必须提供识别分层传输的机制,以层的UUID为标识,确定传输的对象。
b.提供WEB界面,优化用户体验
只用镜像的名字来进行上传下载显然很不方便,需要有一个用户界面可以支持登陆、搜索功能,包括区分公有、私有镜像。
c.支持水平扩展集群
当有用户对镜像的上传下载操作集中在某服务器,需要对相应的访问压力作分解。
d.良好的安全机制
企业中的开发团队有很多不同的职位,对于不同的职位人员,分配不同的权限,具有更好的安全性。
e.Harbor提供了基于角色的访问控制机制,并通过项目来对镜像进行组织和访问权限的控制。
kubernetes中通过namespace来对资源进行隔离,在企业级应用场景中,通过将两者进行结合可以有效将kubernetes使用的镜像资源进行管理和访问控制,增强镜像使用的安全性。尤其是在多租户场景下,可以通过租户、namespace和项目相结合的方式来实现对多租户镜像资源的管理和访问控制。
3. Harbor介绍
镜像的存储harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。harbor在docker distribution的基础上增加了一些安全、访问控制、管理的功能以满足企业对于镜像仓库的需求。harbor以docker-compose的规范形式组织各个组件,并通过docker-compose工具进行启停。
docker的registry是用本地存储或者s3都是可以的,harbor的功能是在此之上提供用户权限管理、镜像复制等功能,提高使用的registry的效率。Harbor的镜像拷贝功能是通过docker registry的API去拷贝,这种做法屏蔽了繁琐的底层文件操作、不仅可以利用现有docker registry功能不必重复造轮子,而且可以解决冲突和一致性的问题。
Harbor官方网站:http://vmware.github.io/harbor/
Harbor源码地址:https://github.com/vmware/harbor/
二:Harbor主要组件
Proxy:对应启动组件nginx。它是一个nginx反向代理,代理Notary client(镜像认证)、Docker client(镜像上传下载等)和浏览器的访问请求(CoreService)给后端的各服务;
UI(Core Service):对应启动组件harbor-ui。底层数据存储使用mysql数据库,主要提供了四个子功能:
- UI:一个web管理页面ui;
- API:Harbor暴露的API服务;
- Auth:用户认证服务,decode后的token中的用户信息在这里进行认证;auth后端可以接db、ldap、uaa三种认证实现;
- Token服务(上图中未体现):负责根据用户在每个project中的role来为每一个docker push/pull命令issuing一个token,如果从docker client发送给 registry的请求没有带token,registry会重定向请求到token服务创建token。
Registry:对应启动组件registry。负责存储镜像文件,和处理镜像的pull/push命令。Harbor对镜像进行强制的访问控制,Registry会将客户端的每个pull、push请求转发到token服务来获取有效的token。
Admin Service:对应启动组件harbor-adminserver。是系统的配置管理中心附带检查存储用量,ui和jobserver启动时候需要加载adminserver的配置;
Job Sevice:对应启动组件harbor-jobservice。负责镜像复制工作的,他和registry通信,从一个registry pull镜像然后push到另一个registry,并记录job_log;
Log Collector:对应启动组件harbor-log。日志汇总组件,通过docker的log-driver把日志汇总到一起;
Volnerability Scanning:对应启动组件clair。负责镜像扫描
Notary:对应启动组件notary。负责镜像认证
DB:对应启动组件harbor-db,负责存储project、 user、 role、replication、image_scan、access等的metadata数据。
需要说明的是,harbor的每个组件都是以Docker容器的形式构建的,可以使用Docker Compose来进行部署,当然,如果你的环境中使用了kubernetes,harbor也提供了kubernetes的配置文件。
docker镜像:harbor-jobservice, nginx, harbor-core, redis, harbor-portal, harbor-db, registry, registryctl, harbor-log
harbor共有8个容器组成:
- ui:harbor的核心服务。
- log:运行着rsyslog的容器,进行日志收集。
- mysql:由官方mysql镜像构成的数据库容器
- nginx:使用Nginx做反向代理
- registry:官方的Docker registry
- adminserver:harbor的配置数据管理器
- jobservice:Harbor的任务管理服务。
- redis:用于存储session
-------------------
三:Harbor架构
1. Harbor登录过程
假设Harbor部署在IP为192.168.1.10的主机上。用户运行docker命令将登录请求发送到Harbor:
$ docker login 192.168.1.10
用户输入所需凭证后,Docker客户端向地址“192.168.1.10/v2/”发送HTTP GET请求。Harbor的不同容器将按照以下步骤进行处理:
(a)首先,该请求由监听端口80的代理容器接收。容器中的Nginx将请求转发到后端的registry容器。
(b)Registry容器已配置为基于令牌的身份验证,因此它返回错误代码401,通知Docker客户端从指定的URL获取有效的令牌。在Harbor,这个URL指向核心服务的令牌服务;
(c)Docker客户端收到此错误代码后,会根据HTTP规范的基本认证向令牌服务URL发送请求,将请求头部嵌入用户名和密码;
(d)通过端口80将该请求发送到代理容器后,Nginx会根据预先配置的规则再次将该请求转发给UI容器。UI容器内的令牌服务接收请求,解码请求并获取用户名和密码;
(e)获取用户名和密码后,令牌服务将检查数据库,并通过MySql数据库中的数据验证用户。当令牌服务配置为LDAP / AD身份验证时,它将对外部LDAP / AD服务器进行身份验证。认证成功后,令牌服务返回一个表示成功的HTTP代码。HTTP响应体包含由私钥生成的令牌。
2. Docker push 的过程
(我们省略了代理转发步骤,上图显示了Docker推送过程中不同组件之间的通信)
用户成功登录后,Docker Image将通过Docker Push命令发送到Harbor:
# docker push 192.168.1.10/library/hello-world
(a)首先,码头客户端通过向注册表发送请求重复类似登录的过程,然后取回令牌服务的URL;
(b)随后,当接触令牌服务时,Docker客户端提供附加信息以在image(library/ hello-world)上应用推送操作的令牌;
(c)收到Nginx转发的请求后,令牌服务查询数据库查询用户的角色和权限,以推送image。如果用户具有适当的权限,则对Push操作的信息进行编码,并用私钥对其进行签名,并向Docker客户端生成一个令牌;
(d)在Docker客户端获取令牌之后,它向包含令牌的头部向Registry发送推送请求。一旦Registry接收到请求,它将使用公钥解码令牌并验证其内容。公钥对应于令牌服务的私钥。如果Registry找到令牌有效推送Image,则Image传输过程开始。
四:harbor镜像仓库部署
1. 安装harbor环境
系统版本: centos7.6
确认docker 和 docker-compose版本号(docker和docker-compose安装)
[root@harbor harbor]# docker version
Client: Docker Engine - Community
Version: 18.09.7
Server: Docker Engine - Community
Version: 18.09.7
[root@harbor harbor]# docker-compose --version
docker-compose version 1.24.1, build 4667896
2. 安装harobr镜像仓库
github官网地址 https://github.com/goharbor/harbor/releases
[root@harbor ~]# wget https://github.com/goharbor/harbor/releases/download/v1.9.3/harbor-offline-installer-v1.9.3.tgz
[root@harbor ~]# tar -zxvf harbor-offline-installer-v1.9.1.tgz
[root@harbor ~]# cd harbor/
[root@harbor harbor]# ls
harbor.v1.9.1.tar.gz harbor.yml install.sh LICENSE prepare
[root@harbor harbor]# ls keys/ #自己制作证书的位置
ikan.key ikan.pem
3.修改主机名,开启https认证并安装
不需要添加域名,到时候nginx直接转发过来即可,和主机名同时支持
数据默认放置在data_volume: /data下,日志在/var/lib/harbor下
[root@harbor harbor]# vim harbor.yml #修改以下这些地方
hostname: harbor1.ikan.com
https:
port: 443
certificate: /root/harbor/keys/ikan.pem
private_key: /root/harbor/keys/ikan.key
[root@harbor harbor]# ./prepare
prepare base dir is set to /root/harbor
Generated configuration file: /config/log/logrotate.conf
Generated configuration file: /config/log/rsyslog_docker.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
loaded secret from 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
[root@harbor harbor]# ./install.sh
[Step 0]: checking installation environment ...
Note: docker version: 19.03.2
Note: docker-compose version: 1.24.1
[Step 1]: loading Harbor images ...
cad87ea2da29: Loading layer [==================================================>] 77.02MB/77.02MB
安装完成后,它会提示你访问harbor的地址是多少,你就可以直接在浏览器中访问这个地址了。
- 停止服务: docker-compose stop
- 开始服务: docker-compose start
五:Harbor使用
1. 通过界面登陆harbor
https://harbor1.ikan.com ,开启https后默认只走这个
默认用户名和密码 admin Harbor12345
2. 创建镜像项目kubernetes
路径:项目 -> 新建项目 -> 项目名称 kubernetes -> 确认
3. 测试harbor仓库可用性
[root@harbor2 ~]# docker login harbor1.ikan.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
Login Succeeded
[root@harbor2 ~]# # 登陆成功后,token会存放在 ~/.docker/config.json.文件里
[root@harbor2 ~]# docker tag busybox harbor.ikan.com/kubernetes/busybox:v0.3
[root@harbor2 ~]# docker push harbor.ikan.com/kubernetes/busybox:v0.3
The push refers to repository [harbor.ikan.com/kubernetes/busybox]
eac247cb7af5: Layer already exists
v0.3: digest: sha256:24fd20af232ca4ab5efbf1aeae7510252e2b60b15e9a78947467340607cd2ea2 size: 527
报错1:镜像直接上传到harbor正常,但是通过nginx一直显示超时:
[root@harbor2 ~]# docker push harbor.ikan.com/kubernetes/busybox:v0.3
The push refers to repository [harbor.ikan.com/kubernetes/busybox]
eac247cb7af5: Retrying in 10 seconds
解决:需要修改安装包里面Nginx配置文件,删掉scheme的那几行,在反向代理的配置上如果有写的话
报错2: 在拉取镜像的时候,会抛出仓库不受信任的异常。
解决:需要在所有的docker客户端的docker配置文件/etc/docker/daemon.json中添加如下配置:
{ "insecure-registries": ["https://harbor1.ikan.com"], }
六:harbor镜像仓库高可用
高可用方案有两种:
1. 双主复制
所谓的双主复制其实就是复用主从同步实现两个harbor节点之间的双向同步,来保证数据的一致性,然后在两台harbor前端顶一个负载均衡器将进来的请求分流到不同的实例中去,只要有一个实例中有了新的镜像,就是自动的同步复制到另外的的实例中去,这样实现了负载均衡,也避免了单点故障,在一定程度上实现了Harbor的高可用性:
这个方案有一个问题就是有可能两个Harbor实例中的数据不一致。假设如果一个实例A挂掉了,这个时候有新的镜像进来,那么新的镜像就会在另外一个实例B中,后面即使恢复了挂掉的A实例,Harbor实例B也不会自动去同步镜像,这样只能手动的先关掉Harbor实例B的复制策略,然后再开启复制策略,才能让实例B数据同步,让两个实例的数据一致。
在实际生产使用中,主从复制有时候会出现报错。
2. 多harbor实例共享后端存储,
共享后端存储算是一种比较标准的方案,就是多个Harbor实例共享同一个后端存储,包括数据库,redis和本地存储数据;任何一个实例持久化到存储的镜像,都可被其他实例中读取。通过前置LB进来的请求,可以分流到不同的实例中去处理,这样就实现了负载均衡,也避免了单点故障:
这个方案在实际生产环境中部署需要考虑三个问题:
- 共享存储的选取,Harbor的后端存储目前支持AWS S3、Openstack Swift, Ceph等,在我们的实验环境里,就直接使用nfs
- Session在不同的实例上共享,这个现在其实已经不是问题了,在最新的harbor中,默认session会存放在redis中,我们只需要将redis独立出来即可。可以通过redis sentinel或者redis cluster等方式来保证redis的可用性。在我们的实验环境里,仍然使用单台redis
- Harbor多实例数据库问题,这个也只需要将harbor中的数据库拆出来独立部署即可。让多实例共用一个外部数据库,数据库的高可用也可以通过数据库的高可用方案保证。
目前,Harbor官方并未给出具体的高可用部署方案,用户需要根据自己的情况来设计合适的高可用方案并完成部署。主从同步高可用方案,只是一种简单的实现。
0.1 已经有了另一台镜像仓库harbor2
1. 创建用户
2. 项目中添加用户
3. 仓库管理中添加目标
- 选择系统管理中的仓库管理,点击“新建目标”,如下图
- 输入对应信息。
- 目标名和描述随意,
- 目录URL为另一台地址,如果为https协议,则证书需要安全。(制作免费的https证书.note)
- Access ID和Access Secret为有同步权限的账号即可
- 点击“测试链接”,显示“测试链接成功”,则表示权限通过,点解“确认”添加即可
4. 添加复制规则
- 在系统管理的复制管理里,点击“新建规则”,如下图
- 添加规则信息
- 名称和描述随意
- 选择复制模式:Push-based 从本地仓库推送到远程仓库,Pull-based 拉去镜像到本地仓库
- 镜像过滤规则,包括包含名称,标签等
- 选择远程镜像仓库和命名空间
- 选择触发模式,分为手动/定时/事件,镜像是否强制覆盖,是否启动规则等
5. 测试harbor仓库可用性
这时你推送镜像到镜像仓库harbor1,则在镜像仓库harbor2上也能看到
[root@harbor2 ~]# docker tag busybox harbor.ikan.com/kubernetes/busybox:v0.4
[root@harbor2 ~]# docker push harbor.ikan.com/kubernetes/busybox:v0.4
The push refers to repository [harbor.ikan.com/kubernetes/busybox]
eac247cb7af5: Layer already exists
v0.3: digest: sha256:24fd20af232ca4ab5efbf1aeae7510252e2b60b15e9a78947467340607cd2ea2 size: 527
镜像自动化删除
默认情况下,Harbor将镜像存储在本地磁盘,随着镜像越来越多,可能会导致磁盘空间不够。为了提供磁盘的利用率,需要把不用或者多余的镜像删除。 Harbor提供了删除镜像的功能,但需要手动去处理。
可以采用cron job定期去运行镜像删除脚本来实现镜像自动化删除。脚本通过调用Harbor的RESTful API,来获取要删除镜像的名称和tag。删除镜像的过程如下:
1) 获取所有project并解析project_id字段,得到project的个数;
2) 获取每个project的repo名称;
3) 根据repo名称获取每个repo下的tag并统计个数;
4) 若tag数大于规定的个数,进行排序,删除最早的tag(并不会删除镜像);
5) 删除镜像,命令如下:
docker-compose stop;
docker run -it --name gc --rm --volumes-from registry vmware/registry:2.6.1-photon garbage-collect /etc/registry/config.yml;
docker-compose start;
问题:registry https://192.168.70.120 is unhealthy: unhealthy
解决:证书自签名,不被信任。