前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >搭建一个高可用的镜像仓库,这是我见过最详细、最简单的教程

搭建一个高可用的镜像仓库,这是我见过最详细、最简单的教程

作者头像
我的小碗汤
发布2022-01-14 13:54:42
1.4K0
发布2022-01-14 13:54:42
举报
文章被收录于专栏:我的小碗汤我的小碗汤

大家好,我是小碗汤,今天分享一篇搭建一个高可用镜像仓库的教程。详细中夹杂着简单~。篇幅较长,兄弟们不妨耐心看完~

Harbor 部署架构图

  • harbor 使用 helm 部署在 k8s 集群中,通过 ingress-nginx 代理。
  • pgsql 采用 Pgpool-II 代理,做主从切换、通过同步流式复制进行数据复制,客户端请求通过 Pgpool-II 路由。
  • pgpool 无状态部署在 k8s 集群中。
  • pgsql 主从实例部署在集群外虚拟机上。
  • redis 哨兵模式部署在集群外虚拟机上。

这里假设示例主机信息如下

  • VM1:172.0.0.1
  • VM2:172.0.0.2
  • VM3:172.0.0.3

版本信息

  • harbor-helm 1.5.0
  • harbor 2.1.0
  • redis 4.0.12
  • Pgsql 9.6.16
  • Pgpool 4.2.6

harbor-helm 1.5.0 chart 包自带的 harbor 版本为 2.1.0

redis

Redis 为哨兵模式,架构图如下:

Redis 实例拓扑分布:

至于 Redis 集群在虚拟机上的部署,我使用的是Cymbal 项目[1]

Cymbal 秉承开箱即用的原则,整个部署过程十分简单,最小化版本只需要一个 runnable jar 及 mysql 服务的支持即可。

Cymbal 是当当网架构部孵化并开源的 Redis PaaS 平台,基于 Spring Boot2 开发。目标是帮助技术团队以简单,低成本的方式管理大规模 Redis 集群。目前当当网内部使用 Cymbal 管理的 Redis 实例数量达到 1000+。

Cymbal 采用 DevOps 的设计思想,以多租户的方式,最大程度上赋予开发人员运维权限,从而加快团队运转。同时,Cymbal 上面集成了丰富的运维功能:从监控、报警到在线扩缩容等,力求最大程度上消除运维门槛。

假设用 Cymbal 部署之后 redis 哨兵信息如下:172.0.0.1:9381,172.0.0.2:9381,172.0.0.3:9381

哨兵 Master 为: mymaster-EC4Fy7DJ

密码为: harborpwd

下面会用到这些信息。

Pgsql

基于 PGpool 中间件实现 postgresql 一主一从集群部署,架构图实例如下:

PGPool、Pgsql 实例拓扑分布:

Pgpool 在 k8s 集群中多实例部署,Pgsql 主从实例在虚拟机中用 docker 容器启动。

docker 部署 pgsql

在虚拟机上直接部署 pgsql 集群在时间成本上,还是不太容易的。我们这里使用 docker 去管理,会轻松一点。

创建 volume,由于复制管理器映像的 PostgreSQL 是非 root 用户,因此您还需要为主机中的挂载目录设置适当的权限:

代码语言:javascript
复制
# 主实例
# docker volume create pg-0
# chgrp -R root /var/lib/docker/volumes/pg-0
# chmod -R g+rwX /var/lib/docker/volumes/pg-0
# 从实例
# docker volume create pg-1
# chgrp -R root /var/lib/docker/volumes/pg-1
# chmod -R g+rwX /var/lib/docker/volumes/pg-1

我们这里将主从部署在不同的主机上,所以两组命令应该在两台主机上执行。从而保证不同时挂掉。

启动 pgsql 实例的脚本:

代码语言:javascript
复制
#!/bin/bash

set -o errexit

node=$1
if [[ -z "${node}" ]]; then
        echo "Error: need node argument, example: pg-0"
        exit -1
fi


existUp=$(docker ps -f name=${node} -q)

if [[ -n "${existUp}" ]]; then
        # nothing
        echo "node: ${node} is Up"
        exit 0
fi

existNotUp=$(docker ps -a -f name=${node} -q)

if [[ -n "${existNotUp}" ]]; then
        # start
        echo "node: ${node} is not Up, will start it"
        docker start ${existNotUp}
        exit 0
fi

# create
docker run --detach --name ${node} \
--network host \
--env REPMGR_PARTNER_NODES=pg-0,pg-1 \
--env REPMGR_NODE_NAME=${node} \
--env REPMGR_NODE_NETWORK_NAME=${node} \
--env REPMGR_PRIMARY_HOST=${node} \
--env REPMGR_USERNAME=repmgrharbor \
--env REPMGR_PASSWORD=repmgrpwd \
--env POSTGRESQL_POSTGRES_PASSWORD=pgpwd \
--env POSTGRESQL_USERNAME=pgharbor \
--env POSTGRESQL_PASSWORD=pgpwd \
--env POSTGRESQL_DATABASE=pgharbor \
--env BITNAMI_DEBUG=true \
--env TZ=Asia/Shanghai \
-v ${node}:/bitnami/postgresql \
-v /neworiental/pgsql/custom-conf/:/bitnami/repmgr/conf/ \
bitnami/postgresql-repmgr:9.6.16

启动时,用:

代码语言:javascript
复制
# start-pg.sh {容器名}

容器名为 pg-0(主)或者 pg-1(从)。

pgsql 挂掉自启动

docker 容器挂掉后,用 crontab 保证容器可以重新启动,30s 为间隔去执行 start-pg.sh 脚本。

执行 crontab -e 在最后新增以下内容,然后:wq 保存退出即可:

代码语言:javascript
复制
# Need these to run on 30-sec boundaries, keep commands in sync.
* * * * *              /pgsql/start-pg.sh pg-1
* * * * * ( sleep 30 ; /pgsql/start-pg.sh pg-1 )

创建 Pgpool

代码语言:javascript
复制
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app.kubernetes.io/component: pgpool
    app.kubernetes.io/instance: pgsql
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: postgresql-ha-doc
    helm.sh/chart: postgresql-ha-8.0.2
  name: pgpool-for-docker-dp-pgsql
  namespace: harbor
spec:
  progressDeadlineSeconds: 600
  replicas: 2
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app.kubernetes.io/component: pgpool
      app.kubernetes.io/instance: pgsql
      app.kubernetes.io/name: postgresql-ha-doc
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app.kubernetes.io/component: pgpool
        app.kubernetes.io/instance: pgsql
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/name: postgresql-ha-doc
        helm.sh/chart: postgresql-ha-8.0.2
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - topologyKey: kubernetes.io/hostname
            labelSelector:
              matchLabels:
                app.kubernetes.io/component: pgpool
                app.kubernetes.io/instance: pgsql
      containers:
      - env:
        - name: BITNAMI_DEBUG
          value: "false"
        - name: PGPOOL_BACKEND_NODES
          value: 0:172.0.0.1:5432,1:172.0.0.2:5432,
        - name: PGPOOL_SR_CHECK_USER
          value: repmgrharbor
        - name: PGPOOL_SR_CHECK_PASSWORD
          value: repmgrpwd
        - name: PGPOOL_SR_CHECK_DATABASE
          value: postgres
        - name: PGPOOL_ENABLE_LDAP
          value: "no"
        - name: PGPOOL_POSTGRES_USERNAME
          value: pgharbor
        - name: PGPOOL_POSTGRES_PASSWORD
          value: pgpwd
        - name: PGPOOL_ADMIN_USERNAME
          value: pgpooladmin
        - name: PGPOOL_ADMIN_PASSWORD
          value: pgpoolpwd
        - name: PGPOOL_ENABLE_LOAD_BALANCING
          value: "yes"
        - name: PGPOOL_DISABLE_LOAD_BALANCE_ON_WRITE
          value: transaction
        - name: PGPOOL_ENABLE_LOG_CONNECTIONS
          value: "no"
        - name: PGPOOL_ENABLE_LOG_HOSTNAME
          value: "yes"
        - name: PGPOOL_ENABLE_LOG_PER_NODE_STATEMENT
          value: "no"
        - name: PGPOOL_CHILD_LIFE_TIME
        - name: PGPOOL_ENABLE_TLS
          value: "no"
        image: docker.io/bitnami/pgpool:4.2.6-debian-10-r7
        imagePullPolicy: IfNotPresent
        livenessProbe:
          exec:
            command:
            - /opt/bitnami/scripts/pgpool/healthcheck.sh
          failureThreshold: 5
          initialDelaySeconds: 30
          periodSeconds: 10
          successThreshold: 1
          timeoutSeconds: 5
        name: pgpool
        ports:
        - containerPort: 5432
          name: postgresql
          protocol: TCP
        readinessProbe:
          exec:
            command:
            - bash
            - -ec
            - PGPASSWORD=${PGPOOL_POSTGRES_PASSWORD} psql -U "pgharbor" -d "pgharbor"
              -h /opt/bitnami/pgpool/tmp -tA -c "SELECT 1" >/dev/null
          failureThreshold: 5
          initialDelaySeconds: 5
          periodSeconds: 5
          successThreshold: 1
          timeoutSeconds: 5
        resources: {}
        securityContext:
          runAsUser: 1001
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext:
        fsGroup: 1001
      terminationGracePeriodSeconds: 30
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app.kubernetes.io/component: pgpool
    app.kubernetes.io/instance: pgsql
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: postgresql-ha-doc
    helm.sh/chart: postgresql-ha-8.0.2
  name: pgpool-for-docker-dp-pgsql
  namespace: harbor
spec:
  ports:
  - name: postgresql
    port: 5432
    protocol: TCP
    targetPort: postgresql
  selector:
    app.kubernetes.io/component: pgpool
    app.kubernetes.io/instance: pgsql
    app.kubernetes.io/name: postgresql-ha-doc
  sessionAffinity: None
  type: ClusterIP

直接kubectl apply以上 yaml 即可。



连接 pgsql 手动创库

harbor 对接外部 pgsql 时,需要提前创建库,所以手动创建以下四个 database(一般 DBA 来做这件事), 可以直接连接 pgsql 主实例,也可以通过 Pgpool 连接:

代码语言:javascript
复制
# PGPASSWORD=pgpwd psql -h localhost -p 5432 -U pgharbor -d pgharbor
pgharbor=> CREATE DATABASE registry ENCODING 'UTF8';
pgharbor=> CREATE DATABASE notary_signer ENCODING 'UTF8';
pgharbor=> CREATE DATABASE notary_server ENCODING 'UTF8';
pgharbor=> CREATE DATABASE clair ENCODING 'UTF8';

harbor 物料

harbor-helm 仓库[2]

部署 harbor

下载 harbor-helm 包:

代码语言:javascript
复制
# wget https://github.com/goharbor/harbor-helm/archive/refs/tags/v1.5.0.tar.gz
# tar -zxf v1.5.0.tar.gz
# cd harbor-helm-1.5.0

# 创建ns
kubectl create ns harbor

创建域名证书 Secret,这里需要用到你的域名证书。

代码语言:javascript
复制
kubectl  create secret tls harbor-ingress -n harbor --cert=./product.cn.pem --key=./product.cn.key

如果没有域名证书,也可以使用自动生成证书,下面会讲到。

修改 values.yaml 中以下内容:

代码语言:javascript
复制
expose:
  type: ingress
  tls:
    enabled: true
    certSource: secret
    secret:
      # The name of secret which contains keys named:
      # "tls.crt" - the certificate
      # "tls.key" - the private key
      secretName: "harbor-ingress"
  ingress:
    hosts:
      core: harbor-pro.kubeinfo.cn
    controller: default
    annotations:
      ingress.kubernetes.io/ssl-redirect: "true"
      ingress.kubernetes.io/proxy-body-size: "0"
      nginx.ingress.kubernetes.io/ssl-redirect: "true"
      nginx.ingress.kubernetes.io/proxy-body-size: "0"
# If Harbor is deployed behind the proxy, set it as the URL of proxy
externalURL: https://harbor-pro.kubeinfo.cn
# The initial password of Harbor admin. Change it from portal after launching Harbor
harborAdminPassword: "Harbor678901"

persistence:
  enabled: true
  resourcePolicy: "keep"
  persistentVolumeClaim:
    registry:
      storageClass: "cephfs"
      accessMode: ReadWriteMany
      size: 200Gi
notary:
  enabled: false
database:
  # if external database is used, set "type" to "external"
  # and fill the connection informations in "external" section
  type: external
  external:
    host: "pgpool-for-docker-dp-pgsql.harbor.svc.cluster.local"
    port: "5432"
    username: "pgharbor"
    password: "pgpwd"
  maxOpenConns: 1000

redis:
  # if external Redis is used, set "type" to "external"
  # and fill the connection informations in "external" section
  type: external
  external:
    # support redis, redis+sentinel
    # addr for redis: <host_redis>:<port_redis>
    # addr for redis+sentinel: <host_sentinel1>:<port_sentinel1>,<host_sentinel2>:<port_sentinel2>,<host_sentinel3>:<port_sentinel3>
    addr: "172.0.0.1:9381,172.0.0.2:9381,172.0.0.3:9381"
    # The name of the set of Redis instances to monitor, it must be set to support redis+sentinel
    sentinelMasterSet: "mymaster-EC4Fy7DJ"
    password: "harborpwd"
  • values.yaml 中的域名修改为自己的域名,这里用到的是 harbor-pro.kubeinfo.cn
  • expose.tls.certSource 可以为 auto,即 chart 包会自动生成证书,我们这里用 secret
  • 域名对应的证书 secret 名,这里为 harbor-ingress,即上面创建的
  • 外部 redis 信息
  • 外部 pgsql 信息,这里连接到集群内 pgpool 的域名
  • storageClass 这里用 Rook 部署的 ceph 集群的文件存储,修改为 cephfs
  • harbor 密码自定义

安装 harbor

代码语言:javascript
复制
helm install pro -n harbor -f values.yaml .

正常情况,一段时间后,harbor 会启动成功,我们访问harbor 域名[3]即可看到 harbor 的界面。

升级

如果修改了 values.yaml 后,执行升级:

代码语言:javascript
复制
helm upgrade pro -n harbor -f values.yaml .

卸载

代码语言:javascript
复制
helm uninstall pro -n harbor

参考资料

[1]Cymbal 项目: https://github.com/dangdangdotcom/cymbal

[2]harbor-helm 仓库: https://github.com/goharbor/harbor-helm

[3]harbor 域名: https://harbor-pro.kubeinfo.cn

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-01-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 进击云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Harbor 部署架构图
  • 版本信息
  • redis
  • Pgsql
  • docker 部署 pgsql
  • pgsql 挂掉自启动
  • 创建 Pgpool
  • 连接 pgsql 手动创库
  • harbor 物料
  • 部署 harbor
  • 安装 harbor
  • 升级
  • 卸载
    • 参考资料
    相关产品与服务
    云数据库 Redis
    腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档