企业级Docker镜像仓库Harbor在Rainbond上的部署

Harbor介绍

Harbor是VMware开源的一个用于存储和分发Docker镜像的企业级Registry服务器,通过添加一些企业必需的功能特性,例如安全、标识和管理等,扩展了开源Docker Distribution;作为一个企业级私有Registry服务器,Harbor提供了更好的性能和安全;提升用户使用Registry构建和运行环境传输镜像的效率。

首先了解Harbor各组件的作用

架构图

image

各组件作用

  • Proxy

是一个nginx前端代理,提供API路由功能,Harbor的组件(例如核心,注册表,Web门户和令牌服务等)都位于此反向代理之后,代理将来自浏览器和Docker客户端的请求转发到各种后端服务。

  • Core

Harbor的核心功能,主要提供以下服务:

认证与授权
Config Management
项目管理
配额管理
标签保留
图表服务
内容信任
镜像复制
扫描管理
Webhook

  • Job Service

一种通用执行队列服务,允许其他组件/服务通过简单的静态API同时提交运行异步任务的请求

  • Registry

第三方注册表服务器,负责存储Docker镜像并处理Docker推/拉命令,由于Harbor需要强制执行对镜像的访问控制,因此注册表将引导客户端使用令牌服务,以便为每个请求请求提供有效的令牌。

存储

  • 键值存储Redis

提供数据缓存功能并支持作业服务的临时持久化作业元数据。

  • 数据库PostgreSQL:

存储Harbor的相关元数据,例如项目,用户,角色,复制策略,标签保留策略,扫描仪,图表和镜像。

从应用市场安装

Harbor已经发布到了好雨公有应用市场,可以从应用市场一键安装:

本次应用市场发布的Harbor版本为1.9.4

等待一段时间,Harbor就部署在了Rainbond集群中了,部署完成后需要修改一些配置

  • registry组件

环境配置–>配置文件设置中挂载了一份配置文件,需要将PROXY_DOMAIN部分更改为proxy组件的对外访问域名,修改完成之后更新并重启组件

  • core组件

在环境配置中找到EXT_ENDPOINT这个变量,将变量值设置为proxy组件的对外访问地址,如果为http协议需要添加端口:80

更新core组件,稍等一段时间就可以访问了

  • 应用网关调整

Rainbond应用网关rbd-gateway生成的域名中nginx的配置client_max_body_size的值默认为1M,在上传较大镜像时会出现报错,所以需要调整该值,在UI控制台调整即可

左侧导航栏打开应用网关–>访问控制,找到proxy组件的域名,进行编辑,将上传限制值设置为0,不做任何限制,更改完毕直接点击确定即刻生效。


客户端使用Harbor

默认使用http协议

docker 从docker 仓库中推送或获取镜像都是默认走https协议。

启动完成后,可以直接访问组件proxy的对外访问地址访问harbor的ui界面,使用的是80端口;
默认账号为admin,密码为Harbor12345

使用Harbor上传下载镜像

harbor支持http和https,但如果使用http的话,在拉取镜像的时候,会抛出仓库不受信任的异常。需要在所有的docker客户端的docker配置文件/etc/docker/daemon.json中添加如下配置:

{
  "insecure-registries": [
    "80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80"#修改为自己的域名+端口
  ]
}
  • 重启docker服务
[root@docker ~]# systemctl daemon-reload 
[root@docker ~]# systemctl restart docker
  • 命令行登录
docker login http://80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80
  • 推拉镜像
docker pull nginx
docker tag nginx  80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80/library/nginx:latest
docker push 80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80/library/nginx:latest
  • 在ui界面查看镜像是否push成功

配置https协议使用harbor

前提条件

需要有一个自己的域名,和其对应的ssl证书,这里以www.insteate.cn域名为例。

使用阿里云签发ssl证书文档请参阅: Rainbond应用域名绑定ssl证书,使用https协议

  • 首先更改网关上传限制,设置值为0,不限制


  • registry组件

环境配置–>配置文件设置中挂载了一份配置文件,需要将PROXY_DOMAIN部分更改为绑定的https域名,修改完成之后更新并重启组件

  • core组件

在环境配置中找到 EXT_ENDPOINT 这个变量,将值设置为访问域名,更新组件

  • proxy组件

环境配置–>配置文件设置添加配置文件,挂载到/etc/nginx/nginx.conf目录, 如下图所示,配置文件内容复制下方代码块内容即可,更新proxy组件。

worker_processes auto;
pid /tmp/nginx.pid;

events {
  worker_connections 1024;
  use epoll;
  multi_accept on;
}

http {
  client_body_temp_path /tmp/client_body_temp;
  proxy_temp_path /tmp/proxy_temp;
  fastcgi_temp_path /tmp/fastcgi_temp;
  uwsgi_temp_path /tmp/uwsgi_temp;
  scgi_temp_path /tmp/scgi_temp;
  tcp_nodelay on;
  keepalive_timeout 65;

  # this is necessary for us to be able to disable request buffering in all cases
  proxy_http_version 1.1;

  upstream core {
    server 127.0.0.1:8080;
  }

  upstream portal {
    server 127.0.0.1:8081;
  }

  log_format timed_combined '$remote_addr - '
    '"$request" $status $body_bytes_sent '
    '"$http_referer" "$http_user_agent" '
    '$request_time $upstream_response_time $pipe';

  access_log /dev/stdout timed_combined;

  server {
    listen 80;
    server_tokens off;
    # disable any limits to avoid HTTP 413 for large image uploads
    client_max_body_size 0;

    # Add extra headers
    add_header X-Frame-Options DENY;
    add_header Content-Security-Policy "frame-ancestors 'none'";

    # costumized location config file can place to /etc/nginx/etc with prefix harbor.http. and suffix .conf
    include /etc/nginx/conf.d/harbor.http.*.conf;

    location / {
      proxy_pass http://portal/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_buffering off;
      proxy_request_buffering off;
    }

    location /c/ {
      proxy_pass http://core/c/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_buffering off;
      proxy_request_buffering off;
    }

    location /api/ {
      proxy_pass http://core/api/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_buffering off;
      proxy_request_buffering off;
    }

    location /chartrepo/ {
      proxy_pass http://core/chartrepo/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_buffering off;
      proxy_request_buffering off;
    }

    location /v1/ {
      return 404;
    }

    location /v2/ {
      proxy_pass http://core/v2/;
      proxy_set_header Host $http_host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto https;
      proxy_buffering off;
      proxy_request_buffering off;
    }

    location /service/ {
      proxy_pass http://core/service/;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

      # When setting up Harbor behind other proxy, such as an Nginx instance, remove the below line if the proxy already has similar settings.
      proxy_set_header X-Forwarded-Proto $scheme;

      proxy_buffering off;
      proxy_request_buffering off;
    }

    location /service/notifications {
      return 404;
    }
  }
}

到此完成https的配置,可直接在命令行登录并推拉镜像了

Harbor应用制作

项目地址: https://gitee.com/Aaron-23/harbor

Harbor官方推荐的部署方式是使用docker-compose部署,这样导致一个问题是在rainbond部署时多组件端口之间的冲突,为了解决这个问题,在部署时将harbor各组件的端口进行了调整,调整方式为更改组件配置文件,各组件端口如下所示:

组件 端口
proxy 80
core 8080
portal 8081
registryctl 8083
jobservices 8084
registry 5000
redis 6379
PostgreSQL 5432

通过官方的docker-compose文件了解了所有组件的依赖关系及配置后开始部署

  • PostgreSQL部署

使用官方的postgresql镜像做了进一步处理,可以自动初始化Harbor所需要的数据库。

部署的方式使用了基于 Dockerfile 的源码构建,项目地址:https://gitee.com/Aaron-23/harbor.git,db目录下

关键Dockerfile部分解析:

FROM postgres:9.6.15-alpine
MAINTAINER zhangz@goodrain.com
ENV TZ Aisa/Shanghai
ENV LANG en_US.utf8

VOLUME /var/lib/postgresql/data

COPY ./docker-healthcheck.sh /docker-healthcheck.sh
# 下面的步骤,会将初始化数据用的sql脚本放置在指定目录下
COPY ./initial-notaryserver.sql /docker-entrypoint-initdb.d/
COPY ./initial-notarysigner.sql /docker-entrypoint-initdb.d/
COPY ./initial-registry.sql /docker-entrypoint-initdb.d/

ENV POSTGRESQL_HOST=127.0.0.1 POSTGRESQL_PORT=5432 POSTGRESQL_USERNAME=postgres POSTGRESQL_PASSWORD=root123 POSTGRESQL_DATABASE=registry POSTGRESQL_SSLMODE=disable

RUN chown -R postgres:postgres /docker-entrypoint.sh /docker-healthcheck.sh /docker-entrypoint-initdb.d \
    && chmod u+x /docker-entrypoint.sh /docker-healthcheck.sh 

ENTRYPOINT ["/docker-entrypoint.sh"]
HEALTHCHECK CMD ["/docker-healthcheck.sh"]
EXPOSE 5432
CMD ["postgres"]

自动初始化的原理参见:https://hub.docker.com/_/postgres 中的 Initialization scripts 部分,这样做的好处是,基于此镜像的容器在首次启动时,不需要其他操作,就会自动执行sql脚本完成初始化。对于Rainbond部署而言,在将这样的数据库作为应用的一部分发布到应用市场后,执行一键安装可以达到即安即用的效果。

  • proxy

它是一个nginx反向代理,代理Notary client(镜像认证)、Docker client(镜像上传下载等)和浏览器的访问请求(Core Service)给后端的各服务;在这里对nginx的配置文件做了一些修改,将后端代理的core组件portal组件的连接地址更改为127.0.0.1,这样做的原因是因为proxy组件依赖了coreportal服务,他在连接后端服务时会通过代理连接,代理的连接地址为127.0.0.1

  upstream core {
    server 127.0.0.1:8080;
  }

  upstream portal {
    server 127.0.0.1:8081;
  }
  • registry部署

使用harbor官方的registry镜像作为基础镜像,修改了配置文件,特别需要注意的是auth:token模块,这里定义的仓库认证的方式及地址,地址必须填写proxy组件对外访问的地址,存储镜像的目录为/storage,这里将其持久化出来。

  • core部署

core使用harbor官方的core镜像作为基础镜像,环境变量EXT_ENDPOINT所定义的值是在UI界面快速复制pull命令时的值,所以需要手动修改,在配置文件中更改了默认的端口号为8080

appname = Harbor
runmode = dev
enablegzip = true

[dev]
httpport = 8080
EnableXSRF = true
XSRFKey = vwdR0JchXoOHwAkM7f9wDLAWsAwhKfqOW74rPR3F
XSRFExpire = 3600
  • jobservice

jobservice 是 harbor中用来处理 job 的组件,负责镜像复制工作的,依赖corepostgresqlredis三个组件,连接地址及相关配置都在config.yaml文件中定义

  • redis部署

直接使用harbor官方的redis镜像,未作修改

问题汇总

我在测试时创建了nginx的项目,将镜像tag修改为80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80/nginx:1.16,导致push时失败,报如下错误

[root@ docker]#: docker push 80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80/nginx:1.16
The push refers to repository [80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80/nginx]
37ec257a56ed: Retrying in 1 second
567538016328: Retrying in 1 second
488dfecc21b1: Retrying in 1 second
received unexpected HTTP status: 500 Internal Server Error

查阅资料得知是镜像目录不符合要求:必须是两级目录以上才可以, 如 80.grf9b616.iyl0r2oh.0196bd.grapps.cn:80/nginx/nginx:1.16

更多harbor使用请参阅用户指南

Harbor概述
Harbor官方网站
GitHub项目地址

1 Like