欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

Demo环境私有容器镜像仓库Harbor升级过程记录

程序员文章站 2022-05-23 08:22:02
Demo环境私有容器镜像仓库Harbor升级过程记录 在某朵月底即将随风飘散的云中,我搭建有一个Kubernetes环境,一个容器Demo环境。前段时间,看到VMware公司对其开源Dock...

Demo环境私有容器镜像仓库Harbor升级过程记录

在某朵月底即将随风飘散的云中,我搭建有一个Kubernetes环境,一个容器Demo环境。前段时间,看到VMware公司对其开源Docker镜像仓库实现Harbor做了许多升级,尤其增加了对镜像安全漏洞的扫描,因此就尝试着升了下级,现在整理下当时粗略记录的过程步骤。

因公司面向的主要客户目前对应用容器化还没有需求,对微服务的需求还集中于求业绩亮点,所以对容器及容器平台没有强烈需求,只做为技术探索及方案储备来源的Demo环境存在,因此下面描述的部署方案可能不够严谨,见谅!

Harbor简介

上面已经提到Harbor是开源的容器镜像仓库实现,它对Docker官方提供的Registry做了企业化功能扩展与增强,主要的特点包括 :

基于角色的访问控制 - 用户与Docker镜像仓库通过“项目”进行组织管理,一个用户可以对多个镜像仓库在同一命名空间(project)里有不同的权限。 镜像复制 - 镜像可以在多个Registry实例中复制(同步)。尤其适合于负载均衡,高可用,混合云和多云的场景。 图形化用户界面 - 用户可以通过浏览器来浏览,检索当前Docker镜像仓库,管理项目和命名空间。 AD/LDAP 支持 - Harbor可以集成企业内部已有的AD/LDAP,用于鉴权认证管理。 审计管理 - 所有针对镜像仓库的操作都可以被记录追溯,用于审计管理。 国际化 - 已拥有英文、中文、德文、日文和俄文的本地化版本。更多的语言将会添加进来。 RESTful API - RESTful API 提供给管理员对于Harbor更多的操控, 使得与其它管理软件集成变得更容易。 部署简单 - 提供在线和离线两种安装工具, 也可以安装到vSphere平台(OVA方式)虚拟设备。

具体的请参见其在GitHub上的文档:here,它的架构组成如下图:

Demo环境私有容器镜像仓库Harbor升级过程记录

Proxy:反射代理,将请求路由到相应功能模块,由Nginx实现;Registry:存储镜像并处理docker pull/push命令,与token服务交互控制访问权限,由Docker官方Register实现;UI:核心服务组件,Harbor的主要组成部分;Database:存储有关项目、用户、角色、复制策略与镜像元数据;Job Servers:最初版本中完成镜像复制任务,后面又增加了镜像安全漏洞描述任务;Log collector:这个就不用细说了吧,日志模块,以syslog服务形式收取其他模块日志内容,落地持久化。

部署方案

在我原有的Demo环境中,在两只虚拟机上各布置了一套Harbor,从其中一个Harbor向另一个Harbor做镜像复制,以防虚拟机意外损毁丢失镜像,正因为是个Demo环境,也就根本没有考虑太多其他高可用,只是利用Harbor默认的docker-compose配置脚本在每只虚拟机上启动全套的组件。
Demo环境私有容器镜像仓库Harbor升级过程记录
当初布置的版本中,并不包含镜像安全漏洞描述功能,这次升级主要是想体验下这个功能。当正视此功能时,才发现需要联接互联网获取安全漏洞元数据。也就是Clair需要联网,Clair也是个开源实现,Harbor集成进来实现安全漏洞描述功能:
Demo环境私有容器镜像仓库Harbor升级过程记录
而在布置Demo环境的这朵云上,默认是不开启互联网,整个环境中,只有一只虚拟机开启了连接互联网的权限,但,不是布置Harbor的两只虚拟机之一。为解决这个问题,考虑将Clair组件单独部署到那只能连接互联网的虚拟机上,在整个部署尝试中采用了两种方式:
1. Docker Swarm方式
Harbor 1 与 Clair 节点 组成docker Swarm集群,指定Clair应用及数据库部署在能连接外网的节点,指定Harbor原有组件部署在原有节点;
2. 容器端口宿主机暴露方式
Clair应用及数据库端口暴露成主机端口,Harbor 2的组件,通过暴露的端口连接Clair,需要Clair应用与数据库地址以Harbor指定的主机名引入容器/etc/hosts文件。
Demo环境私有容器镜像仓库Harbor升级过程记录

部署操作步骤

升级Harbor

升级主要过程参照于Harbor官方文档:migration_guide。

在原部署Harbor的节点上,拖取已经在私有仓库里准备好的Harbor升级镜像
work> docker pull oracle-1.udmp.git.com.cn/vmware/harbor-db-migrator:1.3

准备升级到哪一个版本,就准备那个版本的升级镜像,我准备升级到Harbor 1.3,就准备了harbor-db-migrator:1.3

停止并备份Harbor

work> cd harbor
work> docker-compose down 
work> cd ..

work> mv harbor harbor_bak

备份MySQL数据库数据

work> docker run -ti --rm -e DB_USR=root -e DB_PWD=root123 -v /data/database:/var/lib/mysql -v /home/work/harbor_bak/db_backup:/harbor-migration/backup oracle-1.udmp.git.com.cn/vmware/harbor-db-migrator:1.3 backup

其中:/home/work/harbor_bak/db_backup是宿主机上实际数据备份目录;

? /harbor-migration/backup是Docker容器内部目录,上面命令行将宿主机目录mount到了容器目录。

升级MySQL数据库Schema

work> docker run -ti --rm -e DB_USR=root -e DB_PWD=root123 -v /data/database:/var/lib/mysql oracle-1.udmp.git.com.cn/vmware/harbor-db-migrator:1.3 up head

其中:/data/database是原有Harbor部署时指定的MySQL数据存储目录

展开harbor离线安装包,并按照原有部署配置重新修改配置文件。离线安装包从here下载。

work> tar xvfz harbor-offline-installer-v1.3.0.tgz
work> cd harbor
work> vi harbor.cfg

以不带Clair功能模块方式,安装启动Harbor

work> sudo ./install.sh

在某只机器上启动时,发现容器内部解析hostname失败,通过docker info命令检视环境时,发现输出中有:

Registry: https://index.docker.io/v1/
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled

检查系统参数设置:

work> sysctl -a  | grep bridge-nf-call-ip
...
net.bridge.bridge-nf-call-ip6tables = 0
net.bridge.bridge-nf-call-iptables = 0
....

修改/etc/sysctl.conf,增加以下内容:

net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1

使参数生效:

work> sudo sysctl -p

重启Harbor:

work> cd harbor
work> docker-compose down
work> docker-compose up -d

Swarm方式部署带Clair的Harbor

为以Swarm集群方式部署Harbor 1,需要docker-composef支持version 3.0,因此需要保证docker-compse版本>=1.10.0

生成相应配置文件

在Harbor 1节点上:

work> cd harbor
work> docker-compose down
work> vi harbor.cfg #修改clair_db_password 
work> sudo ./prepare --with-clair

?

建立Docker Swarm集群

在Harbor 1节点上,执行以下命令使其成为集群主节点:

work> docker swarm init --advertise-addr 10.210.33.60
Swarm initialized: current node (jrfpz1voltljdrg5rohoh3dfv) is now a manager.
 To add a worker to this swarm, run the following command:
      docker swarm join \
      --token SWMTKN-1-243dskrvdqo07gfbaqaj8afit0oymp451inllzt2thcyvl0bi0-6w8ob2me68t4miv0u6akte4c1 \
      10.210.33.60:2377

在能连接互联网的节点上,以上面命令输出中的token加入swarm集群:

work> docker swarm join \
      --token SWMTKN-1-243dskrvdqo07gfbaqaj8afit0oymp451inllzt2thcyvl0bi0-6w8ob2me68t4miv0u6akte4c1 \
      10.210.33.60:2377

给Docker Swarm集群中两个节点分别打上角色标签,以便于在配置中以角色标签指定各组件在相应节点启动

在Harbor 1节点即Swarm主节点上,查看swarm集群节点列表:

work> docker node ls
ID                           HOSTNAME    STATUS  AVAILABILITY  MANAGER STATUS
jrfpz1voltljdrg5rohoh3dfv *  UDMP-RT-15  Ready   Active        Leader
p32iiasin4pnhi9hvn0qe11dc    UDMP-RT-13  Ready   Active

将两个节点分别打上标签,标明角色:

work> docker node update --label-add harbor-role=registry UDMP-RT-15
work> docker node update --label-add harbor-role=clair UDMP-RT-13

编辑docker-compose.yml

修改version为3.2, 并在每个服务配置节后面增加指定部署节点的内容,指定Harbor主要组件运行在角色为registry的节点上,即原来已有的Harbor 1节点:

deploy:
 placement:
   constraints:
   - node.labels.harbor-role == registry

修改log collector、proxy容器端口输出为本机,以免其以swarm ingress方式同时输出到其他节点,影响其他节点本地已有使用这些端口的应用,类似于:

log:
  ...
  ports:
  - target: 10514
    published: 1514
    protocol: tcp
    mode: host

完整的配置文件内容如下:

version: '3.2'
services:
log:
  image: vmware/harbor-log:v1.3.0
  container_name: harbor-log 
  restart: always
  volumes:
    - /var/log/harbor/:/var/log/docker/
    - ./common/config/log/:/etc/logrotate.d/
  ports:
    - target: 10514
      published: 1514
      protocol: tcp
      mode: host
  networks:
    - harbor
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
registry:
  image: vmware/registry:2.6.2-photon
  container_name: registry
  restart: always
  volumes:
    - /data/registry:/storage
    - ./common/config/registry/:/etc/registry/
  networks:
    - harbor
  environment:
    - GODEBUG=netdns=cgo
  command:
    ["serve", "/etc/registry/config.yml"]
  depends_on:
    - log
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:1514"
      tag: "registry"
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
mysql:
  image: vmware/harbor-db:v1.3.0
  container_name: harbor-db
  restart: always
  volumes:
    - /data/database:/var/lib/mysql
  networks:
    - harbor
  env_file:
    - ./common/config/db/env
  depends_on:
    - log
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:1514"
      tag: "mysql"
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
adminserver:
  image: vmware/harbor-adminserver:v1.3.0
  container_name: harbor-adminserver
  env_file:
    - ./common/config/adminserver/env
  restart: always
  volumes:
    - /data/config/:/etc/adminserver/config/
    - /data/secretkey:/etc/adminserver/key
    - /data/:/data/
  networks:
    - harbor
  depends_on:
    - log
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:1514"
      tag: "adminserver"
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
ui:
  image: vmware/harbor-ui:v1.3.0
  container_name: harbor-ui
  env_file:
    - ./common/config/ui/env
  restart: always
  volumes:
    - ./common/config/ui/app.conf:/etc/ui/app.conf
    - ./common/config/ui/private_key.pem:/etc/ui/private_key.pem
    - ./common/config/ui/certificates/:/etc/ui/certifates/
    - /data/secretkey:/etc/ui/key
    - /data/ca_download/:/etc/ui/ca/
    - /data/psc/:/etc/ui/token/
  networks:
    - harbor
  depends_on:
    - log
    - adminserver
    - registry
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:1514"
      tag: "ui"
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
jobservice:
  image: vmware/harbor-jobservice:v1.3.0
  container_name: harbor-jobservice
  env_file:
    - ./common/config/jobservice/env
  restart: always
  volumes:
    - /data/job_logs:/var/log/jobs
    - ./common/config/jobservice/app.conf:/etc/jobservice/app.conf
    - /data/secretkey:/etc/jobservice/key
  networks:
    - harbor
  depends_on:
    - ui
    - adminserver
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:1514"
      tag: "jobservice"
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
proxy:
  image: vmware/nginx-photon:1.11.13
  container_name: nginx
  restart: always
  volumes:
    - ./common/config/nginx:/etc/nginx
  networks:
    - harbor
  ports:
    - target: 80
      published: 80
      protocol: tcp
      mode: host
    - target: 443
      published: 443
      protocol: tcp
      mode: host
    - target: 4443
      published: 4443
      protocol: tcp
      mode: host
  depends_on:
    - mysql
    - registry
    - ui
    - log
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:1514"
      tag: "proxy"
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == registry
networks:
harbor:
  external: false

编辑docker-compose.clair.yml
修改version为3.2, 并在每个服务配置节后面增加指定部署节点的内容,指定Clair组件相关容器运行在角色标签为clair的节点上,即那台能连接互联网的机器:

deploy:
 placement:
   constraints:
   - node.labels.harbor-role == clair

先注释到cpu_quota,因为在V3.0里已经被resource.cpu配置替代,并且增加本地log日志服务,并修改其他服务依赖的服务名为log-clair,log端口为2514。(为什么既然限制了端口输出为节点,为什么使用1514时还会在启动时报冲突?【 Harbor 节点上的log在使用1514端口】)

修改postgres、clair容器配置,分别输出其端口到宿主机,以供Harbor 2引入

完整的配置文件内容如下:

version: '3.2'
services:
ui:
  networks:
    harbor-clair:
      aliases:
        - harbor-ui
jobservice:
  networks:
    - harbor-clair
registry:
  networks:
    - harbor-clair
log-clair:
  image: vmware/harbor-log:v1.3.0
  container_name: harbor-log
  restart: always
  volumes:
    - /var/log/harbor/:/var/log/docker/
    - ./common/config/log/:/etc/logrotate.d/
  ports:
    - target: 10514
      published: 2514
      protocol: tcp
      mode: host
  networks:
    - harbor-clair
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == clair
postgres:
  networks:
    harbor-clair:
      aliases:
        - postgres
  container_name: clair-db
  image: vmware/postgresql:9.6.5-photon
  restart: always
  depends_on:
    - log-clair
  env_file:
    ./common/config/clair/postgres_env
  volumes:
    - ./common/config/clair/postgresql-init.d/:/docker-entrypoint-initdb.d
    - /data/clair-db:/var/lib/postgresql/data
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:2514"
      tag: "clair-db"
  ports:
    - target: 5432
      published: 5432
      protocol: tcp
      mode: host
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == clair
clair:
  networks:
    - harbor-clair
  container_name: clair
  image: vmware/clair:v2.0.1-photon
  restart: always
  #cpu_quota: 150000
  depends_on:
    - postgres
  volumes:
    - ./common/config/clair:/config
  logging:
    driver: "syslog"
    options:  
      syslog-address: "tcp://127.0.0.1:2514"
      tag: "clair"
  ports:
    - target: 6000
      published: 6000
      protocol: tcp
      mode: host
  deploy:
    placement:
      constraints:
        - node.labels.harbor-role == clair
networks:
harbor-clair:
  external: false

合并生成Docker Swarm部署配置文件

work> docker-compose -f docker-compose.yml -f docker-compose.clair.yml config > docker-with-clair.yml

将应用拷贝到能连接互联网的Clair节点,修改harbor.cfgj里的hostname,然后:

work> sudo ./install -with-clair
work> docker-compose -f docker-compose.yml -f docker-compose.clair.yml down

以上命令的用意,以离线方式导入相应Docker镜像,并启动一次,建立相应目录,并初始化Clair数据库

在Swarm主节点,即Harbor 1节点上,启动应用:

work> docker stack deploy -c docker-with-clair.yml harbor

登录页面,检查确认部署成功
Demo环境私有容器镜像仓库Harbor升级过程记录

Harbor直接连接Clair暴露的端口

在Harbor 2节点上,以上面描述的方式,首先升级Harbor到新版本,然后修改harbor.cfg里clair_db_password,设置成与Harbor 1节点上相同的口令,再通过命令重新生成配置:

work> sudo ./prepare --with-clair

手工修改docker-compose.yml,在ui、adminserver、jobserver配置里增加对clair相关主机名与地址映射到/etc/hosts的配置:

 extra_hosts:
   - "clair:10.210.33.58"
   - "postgres:10.210.33.58"

重启Harbor

work> docker-compose -f docker-compose.yaml