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.core
和expose.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
andnotary.signer.replicas
ton(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
,那么节点如何解析kubernetes
的service
域名呢?对,通过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 .