Harbor高可用方案设计

1. 系统架构

本文档参照Harbor官方高可用方案说明,并且在Kubernetes集群通过helm来部署Harbor

Harbor的大部分组件都是无状态的应用,针对该种应用比如portal、core、nginx等只需要增加其相应的副本数量即可;在存储数据层面,需要提供高可用的Postgresql、redis集群,另外针对镜像和chart服务也需要提供可持久的存储(PVCs)。鉴于以上理论,也就有了下面的Harbor高可用方案设计架构图(摘自Harbor官网):

既然有了上图的系统架构设计,下面开始着手具体部署实现。

另外本文只针对Harbor高可用的设置,其它部署可参照Harbor NFS部署和Harbor CEPH部署。

2. 部署准备

2.1 Chart下载

首先下载Harbor Chart,参照如下操作即可:

# 添加helm harbor repo
helm repo add harbor https://helm.goharbor.io

# 下载chart
helm fetch harbor/harbor

# 解压缩
tar xvf harbor-xxx.tgz
cd harbor-xxx/

2.2 Harbor参数配置

跟常规部署一样,需要修改values.yaml文件:

  • 修改Harbor对外暴露方式:上面提到的两篇博文都是采用NodePort的暴露方式,此处建议采用Ingress,于是需要修改expose.ingress.hosts.coreexpose.ingress.hosts.notary这两个字段;
  • 修改externalURL:修改成expose.ingress.hosts.core字段的值,但是前面加上协议名称;
  • 修改PostgreSQL配置:首先修改database.type --> external,然后填入database.external区域的信息比如访问数据库的host、端口、用户名、密码等信息,另外注意:这一块需要提前手动创建四个空数据库:harbor Core、Clair、Notary Server、Notary Signer,然后把数据库的名称填入database.external区域,至于PostgreSQL高可用部署下文会进一步说明;
  • 修改Redis配置:首先修改redis.type --> external,然后填入redis.external区域信息,高可用方案下如果采用Redis Sentinal方案,因为Harbor上游项目代码的Redis客户端不支持Sentinal,所以可以考虑使用HAProxy
  • 持久化存储配置:这一块配置跟上面所提两篇博文一致,预先安装对应存储的驱动插件,然后依据StorageClass创建PVC进而提供PV方式;
  • 修改其他组件的副本数量:修改 portal.replicas , core.replicas , jobservice.replicas , registry.replicas , chartmuseum.replicas , clair.replicas , notary.server.replicas and notary.signer.replicas to n(n>=2,这里是3)

配置完之后,我们需要在环境中搭建高可用的数据库:PostgreSQL和Redis

3. PostgreSQL高可用部署

这里采用stolon来部署PostgreSQL的高可用,具体部署步骤可参考Stolon Inside Kubernetes。

一点说明:尽管helm hub上已经有stolon的chart,但是不建议使用,本人曾经尝试安装过几次,不过最后都没安装成功,原因未知。

3.1 下载源码和镜像

按如下操作即可:

# 源码下载
git clone https://github.com/sorintlab/stolon.git

# stolon镜像下载
docker pull sorintlab/stolon:v0.13.0-pg10  # 网上随便找的一个镜像,实际使用时可根据需求修改stolon/examples/kubernetes/image/docker/Dockerfile实现订制

# 进入kubernetes部署目录
cd stolon/examples/kubernetes/

3.2 初始化Stolon集群

# stolon集群初始化
kubectl run -i -t stolonctl --image=sorintlab/stolon:v0.13.0-pg10 --restart=Never --rm -- /usr/local/bin/stolonctl --cluster-name=kube-stolon --store-backend=kubernetes --kube-resource-kind=configmap init

3.3 参数配置

进入stolon kubernetes安装目录后,可以看到:

需要修改出不多:

  • 镜像信息:此处均修改成sorintlab/stolon:v0.13.0-pg10

  • postgres数据库用户名称:默认stolon,可通过修改stolon-keeper.yaml文件配置项完成设置;

  • postgres数据库访问密码:默认password1,在secret.yaml中存储,如需更改先base64转码后存入;

  • 后端存储配置:HA方案采用共享存储,这里提前预先安装ceph驱动插件只需在stolon-keeper.yaml文件做如下图示修改即可,至于容量大小按需填入;

  • 副本数量:按需填入,这里默认都是2

3.4 组件安装

下面开始stolon各个组件的部署,依次执行如下命令即可:

 kubectl create -f stolon-sentinel.yaml
 kubectl create -f secret.yaml
 kubectl create -f stolon-keeper.yaml
 kubectl create -f stolon-proxy.yaml 
 kubectl create -f stolon-proxy-service.yaml

# RBAC相关
kubectl create -f role.yaml
kubectl create -f role-binding.yaml

如果出现如下结果说明安装基本上是ok了:

并且我们还可以通过kubectl logs命令发现两个keeper一个是master,而另一个则是standby

3.5 Harbor高可用准备及相关参数调整

3.5.1 Harbor参数调整

更新values.yaml文件:

  • database.external.host --> stolon-proxy-service即stolon-proxy的service名称;
  • database.external.username --> stolon
  • database.external.password --> password1

3.5.2 Postgres初始化

如上面所说,需要预先在Postgres集群中创建几个空数据库,可借助kubernetes Job来完成。因为Postgres客户端命令行工具支持以文件传入SQL命令的方式,所以只需把创建数据库的命令放入几个文件里,然后通过一个脚本调用它们即可:

  • 几个sql命令文件:
  • 初始化脚本程序

#!/bin/bash
# postgresql.sh

host="stolon-proxy-service"
user="stolon"
db="postgres"
export PGPASSWORD="password1"

args=(
        # force postgres to not use the local unix socket (test "external" connectibility)
        --host "$host"
        --username "$user"
        --dbname "$db"
        --quiet --no-align --tuples-only
)

if select="$(echo 'SELECT 1' | psql "${args[@]}")" && [ "$select" = '1' ]; then
   psql -h stolon-proxy-service -p 5432 postgres -U stolon -f "/docker-entrypoint-initdb.d/notary_server.sql"
   psql -h stolon-proxy-service -p 5432 postgres -U stolon -f "/docker-entrypoint-initdb.d/notary_signer.sql"
   psql -h stolon-proxy-service -p 5432 postgres -U stolon -f "/docker-entrypoint-initdb.d/registry.sql"
   psql -h stolon-proxy-service -p 5432 postgres -U stolon -f "/docker-entrypoint-initdb.d/clair.sql"   
   exit 0
fi
exit 1
  • Job yaml文件
apiVersion: batch/v1
kind: Job
metadata:
  name: stolon-init-database-job
spec:
  template:
    spec:
      containers:
      - name: stolon-proxy
        image: sorintlab/stolon:master-pg10
        command:
          - "/bin/bash"
          - "/docker-entrypoint-initdb.d/postgresql.sh"
        volumeMounts:
        - mountPath: /docker-entrypoint-initdb.d
          name: database
      restartPolicy: OnFailure     #失败重启
      volumes:
        - name: database
          hostPath:
            path: /postgres_init  # 把之前准备的sql和脚本文件放置这个目录下,总共5个文件
  activeDeadlineSeconds: 600   #10分钟没有complete,不再重启并移除Pod

把之前准备好的sql和脚本文件拷贝到各个worker节点/postgres_init目录,然后再master执行批处理任务即可完成数据库的初始化工作,另外如果新建的数据库名称跟Harbor配置不一致注意更新,自此Postgresql高可用部署完成。

4. Redis高可用部署

4.1 Redis哨兵集群部署

直接采用helm部署即可,操作步骤可参考如下:

helm repo add stable `https://kubernetes-charts.storage.googleapis.com` 
helm fetch stable/redis-ha
tar xvf redis-ha-xxx.tgz
cd redis-ha

修改values.yaml配置,修改的地方不多绝大部分默认配置即可,其中有两处额外注意一下:

  • redis访问密码设置:需提前创建一个包含redis密码信息的secret对象,比如下面这样:

然后通过kubectl create -f redis-secret.yaml创建,之后根据secret修改values.yaml对应认证信息即可:

(secret中密码都是base64转码之后的结果,此处redis密码: password1 )
注意:如果如本文redis集群最终要对接Harbor且采用haproxy tcp-check来侦测redis master,此处auth--> false

  • 持久化存储设置:因为数据库后端采用共享存储,设置好PVC对应的storageclass和容量即可:

然后开始部署:

# 可以先检查下配置
helm install --name vienfu-redis-cluster . --debug --dry-run
# 正式安装
helm install --name vienfu-redis-cluster .

等待一会而便会发现部署完成了:


下面做个简单测试:


4.2 Harbor高可用准备及参数调整

一般情况下只需访问redis-sentinal集群服务便可对redis master进行读写,但是由于Harbor内置的redis客户端不支持sentinal,所以直接访问redis sentinal服务是不行的。那么直接访问redis-server的服务可以吗?答案也是不可以的,因为这有可能后端最终访问到redis slave节点,而slave节点却是只读的,所以需要其他一种方式能够从redis server节点中找出redis master,根据官方文档提示采用HAProxy,仔细查阅下HAProxy配置官方文档,可以通过haproxy tcp-check功能来锁定redis master,如下是可参照的haproxy配置:

# cat /etc/haproxy/conf.d/redis-ha.conf

frontend ft_redis
 bind 10.0.2.15:6379 name redis
 default_backend bk_redis

backend bk_redis
 option tcp-check
 tcp-check connect
 tcp-check send PING\r\n
 tcp-check expect string +PONG
 tcp-check send info\ replication\r\n
 tcp-check expect string role:master
 tcp-check send QUIT\r\n
 tcp-check expect string +OK
 server R1 vienfu-redis-cluster-redis-ha-server-0.vienfu-redis-cluster-redis-ha.default.svc.cluster.local:6379 check inter 1s
 server R2 vienfu-redis-cluster-redis-ha-server-1.vienfu-redis-cluster-redis-ha.default.svc.cluster.local:6379 check inter 1s
 server R3 vienfu-redis-cluster-redis-ha-server-2.vienfu-redis-cluster-redis-ha.default.svc.cluster.local:6379 check inter 1s

然后设置开机启动及重启haproxy服务即可。

注意此处也要对应调整Harbor参数配置:redis.external.host --> 上面haproxy配置的VIP:10.0.2.15

4.2.1 其它说明

此外如你所见,此处haproxy后端server的配置采用的是对应server的域名,直接使用POD IP也可以,不过考虑到该IP可能会变,所以建议使用域名来配置haproxy后端server,那么节点如何解析kubernetesservice域名呢?对,通过CoreDNS

首先,需要获取CoreDNS对应的nameserver,很简单执行如下命令即可:

kubectl get svc -n kube-system

把结果dns服务对应的CLUSTER-IP作为新增的nameserver配置到节点的域名配置文件中(一般默认/etc/resolve.conf),不过高版本的linux一般都是通过systemd来控制域名解析服务,如果直接修改该文件重启域名服务是不生效的,在此提供一个简单方法直接关掉systemd-resolved并且禁用开机启动,这样直接修改/etc/resolve.conf就立刻生效了,其他方法可参照Ubuntu 18.04修改DNS。

之后,重启haproxy服务的过程中可能会碰到如下问题:提示后端server的域名无法解析,但是执行nslookup命令却能解析域名,发现也ping不通,最终参照网上nslookup works but can not ping问题最终得以解决。

5. Harbor HA安装

按照如下命令执行完成最终部署:

# 可先检查下Harbor配置
helm install --name harbor-ha . --debug --dry-run

# 正式部署
helm install --name harbor-ha . 

你可能感兴趣的:(Harbor高可用方案设计)