在Kubernetes中部署Postgres HA集群,避免由于Kubernetes Node下线造成的单点故障。

访问模式造成的故障

Kubernetes支持以下四种访问模式(accessModes):

  • ReadWriteOnce:允许一个Node的Pod同时读写卷
  • ReadOnlyMany:允许多个Node的Pod同时读卷
  • ReadWriteMany:允许多个Node的Pod同时读写卷
  • ReadWriteOncePod(v1.22):只允许单个Pod读写卷

当使用ReadWriteOnce模式的PVC部署服务时,如果出现节点宕机,会出现新副本阻塞的情况,服务不可用的情况。

原因是:卷无法从宕机节点上正常Detach,由于卷访问模式设置成ReadWriteOnce,新副本所在的节点无法Attach该卷,新副本一直处于ContainerCreating状态。

此时用户需要手工强制删除Terminal状态的旧副本,并且等待6min后Kubernetes attachDetachController对PVC执行强制Attach操作。

Postgres HA

为了避免ReadWriteOnce磁盘模式造成的单点故障,以及保证Postgres服务平滑的发生主备切换,在Kubernetes中需要部署多副本模式的Postgres。

目前开源社区现有的成熟方案包括:

  • PGO:crunchydata 提供的Postgres Operator工具,可以提供多副本的Postgres环境部署以及监控等能力。
  • Postgres-HA:Bitnami提供的基于Repmgr和Pgpool实现的Helm包

PGO

pgo是crunchydata公司提供的一款 Postgres Operator 工具,通过该工具用户可以在k8s上部署一个完整的,具备高可用性、灾难恢复和监控、以及TLS通信能力的生产级Postgres集群。

Crunchydata提供了自己的商业Postgres发行版,但是开源了Postgres对应的K8S运维管理工具PGO,用户可以通过Chart快速在K8S部署PGO。

1
2
3
git clone --depth 1 "https://github.com/CrunchyData/postgres-operator-examples.git"
cd postgres-operator-examples
kubectl apply -k kustomize/install

CrunchyData/postgres-operator-examples 仓库中提供了PGO基于Helm和Kustomize的安装包,以及多个PostgresCluster实例的Yaml配置

PostgresCluster

安装PGO后可以通过定义PostgresCluster在K8S中部署Postgres集群

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
apiVersion: postgres-operator.crunchydata.com/v1beta1
kind: PostgresCluster
metadata:
  name: postgres-cluster
spec:
  image: registry.hci.io/crunchydata/crunchy-postgres:centos8-13.4-1
  postgresVersion: 13
  instances:
    - name: ins1
      replicas: 3
      dataVolumeClaimSpec:
        accessModes:
          - "ReadWriteOnce"
        resources:
          requests:
            storage: 50Gi
      affinity:
        # 通过亲和性配置使不同的Postgres实例部署在不同的节点上
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 1
              podAffinityTerm:
                topologyKey: kubernetes.io/hostname
                labelSelector:
                  matchLabels:
                    postgres-operator.crunchydata.com/cluster: postgres-cluster
                    postgres-operator.crunchydata.com/instance-set: ins1
  # 初始化数据库的用户,并且创建相应数据库,同时指定用户的SUPERUSER权限
  users:
    - name: yoaz
      databases:
        - registrydb
        - notarydb
      options: "SUPERUSER"
  # 定制化postgresql的相关配置
  patroni:
    dynamicConfiguration:
      postgresql:
        parameters:
          ssl: "off"
  # 备份配置,每个实例PostgresCluster强制需要配置Backup,当前支持4中类型的备份 azure/gcs/s3/volume(PVC)
  # 参考:https://access.crunchydata.com/documentation/postgres-operator/v5/tutorial/backups/
  backups:
    pgbackrest:
      configuration:
        - secret:
            # 指定对应Sceret其中存放访问的Key
            name: s3-creds
      global:
        repo1-path: /pgbackrest/postgres-cluster/repo1
      repos:
        - name: repo1
          s3:
            bucket: "postgresql"
            endpoint: "minio.kubesphere-system.svc:9000"
            region: "us-east-1"

默认情况下使用minio作为pgbackrest后端时,无法正常备份数据官方提到需要修改PGO的特殊

详细可以参考:https://github.com/CrunchyData/postgres-operator/issues/1228

连接数据库

创建上述CR后,PGO的控制器会在指定命名空间中启动三个副本的postgres-cluster实例以及相应的Secret和Svc,用户需要从指定Secret中获取对应用户的密码以及SSL证书。

用户需要关注-pguser-格式的Secret其中包含以下信息:

  • user: 用户名
  • password: 用户密码
  • dbname: 用户可以访问的数据(如果指定了多个,默认是第一个)
  • host: 数据库连接地址,通常为名称为-primary的SVC
  • port: 连接端口号
  • uri: 连接串
  • verifier: 密码通过 SCRAM-SHA-256 计算后的结果

需要注意一下几点:

  • 创建集群时,用户没有手段显示指定Password,如果有修改需求用户需要在集群创建完成后手动修改上述Secret中的password和verifier的值
  • 默认情况下PGO创建的集群基于TLS通讯,并且使用的是自签名的证书(PS:证书的CA应该也是保存在secret中的),可以像上述配置中一样关闭ssl配置

如何设置自定义密码,参考:https://access.crunchydata.com/documentation/postgres-operator/5.0.3/architecture/user-management/

自定义TLS配置,参考:https://access.crunchydata.com/documentation/postgres-operator/5.0.3/tutorial/customize-cluster/

HA

PostgresCluster 提供了多副本、自动故障切换的能力,并且该能力独立于 PGO 官方文档中提到PostgresCluster基于Raft算法进行主备选举,并且将信息存储在Kubernetes的etcd中。

同时PostgresCluster类似Pod等原生资源,支持Affinity、Tolerations、Pod Topology Spread Constraints等能力。

关于HA的架构参考:https://access.crunchydata.com/documentation/postgres-operator/5.0.3/architecture/high-availability/

关于HA相关配置参考:https://access.crunchydata.com/documentation/postgres-operator/v5/tutorial/high-availability/

备份

PGO基于pgbackrest对每个实例进行备份(强制配置的),用户可以在azure/gcs/s3/PVC四种类型中选择一个存放备份数据。

如何配置备份,参考:https://access.crunchydata.com/documentation/postgres-operator/v5/tutorial/backups/

当前PGO支持手动或者定时备份,以及以下备份策略:

  • full:全量备份
  • diff:基于上一次全量备份进行增量备份
  • incr:增量备份

如何配置备份策略,参考:https://access.crunchydata.com/documentation/postgres-operator/v5/tutorial/backup-management/

克隆&Restore

PGO 支持以下能力:

  • 在现有实例上快速克隆出全新PostgresCluster,并且支持Clone实例恢复到目标集群指定时间点的状态(PITR)。
  • 实例数据丢失时,支持从Backup数据中恢复到任意时间点的数据
  • 支持跨Kubernetes集群的只读Standby Cluster

参考:https://access.crunchydata.com/documentation/postgres-operator/v5/tutorial/disaster-recovery/

Postgres-HA

该方案基于将Postgres和Repmgr部署在同一个Pod中,通Shell脚本控制副本之间的集群状态(对应Github仓库:bitnami-docker-postgresql-repmgr)。

用户通过Pgpool连接服务,并且在实例故障时自动切换。

Chart地址:bitnami/charts

1
2
helm repo add bitnami https://charts.bitnami.com/bitnami
helm pull bitnami/postgresql-ha

关键配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
postgresqlImage:
  # 日志debug开关
  debug: true

pgpoolImage:
  # 日志debug开关
  debug: true

postgresql:
  # postgresql副本数
  replicaCount: 3
  repmgrLogLevel: DEBUG
  repmgrConfiguration: ""
  # postgresql的自定义配置
  extendedConf: |-
        huge_pages = off
  # PS:部分场景下需要关闭livenessProbe探针,防止由于pg初始化时间太长造成初始化中途pod被kill
  livenessProbe:
    enabled: false

pgpool:
  # pgpool副本数
  replicaCount: 3

连接数据库

1
2
3
4
5
6
7
8
export REPMGR_PASSWORD=$(kubectl get secret --namespace harbor postgresql-ha-postgresql -o jsonpath="{.data.repmgr-password}" | base64 --decode)
export POSTGRES_PASSWORD=$(kubectl get secret --namespace harbor postgresql-ha-postgresql -o jsonpath="{.data.postgresql-password}" | base64 --decode)
kubectl run postgresql-ha-client --rm --tty -i --restart='Never' \
--namespace harbor \
--image registry.hci.io/bitnami/postgresql-repmgr:11.13.0-debian-10-r0 \
--env="PGPASSWORD=$POSTGRES_PASSWORD"  \
--command \
-- psql -h postgresql-ha-pgpool -p 5432 -U postgres -d postgres

参考

宕机处理:Kubernetes 集群高可用实战总结

CSI中Force Detach逻辑

bitnami/bitnami-docker-postgresql-repmgr

bitnami/charts

crunchydata

PGO