跳至正文

cloudnative-pg1.29/1.30安装部署

1.收集ceph s3的地址

rook-ceph 方式

export AWS_HOST=$(kubectl -n default get cm ceph-bucket -o jsonpath='{.data.BUCKET_HOST}')
export PORT=$(kubectl -n default get cm ceph-bucket -o jsonpath='{.data.BUCKET_PORT}')
export BUCKET_NAME=$(kubectl -n default get cm ceph-bucket -o jsonpath='{.data.BUCKET_NAME}')
export AWS_ACCESS_KEY_ID=$(kubectl -n rook-ceph get secret rook-ceph-object-user-s3-store-s3-admin -o jsonpath='{.data.AccessKey}' | base64 --decode)
export AWS_SECRET_ACCESS_KEY=$(kubectl -n rook-ceph get secret rook-ceph-object-user-s3-store-s3-admin -o jsonpath='{.data.SecretKey}' | base64 --decode)

ceph方式

radosgw-admin bucket list  --rgw-realm s3-store
radosgw-admin bucket stats --bucket=ceph-bkt-aad0791f-76df-43d3-9313-cca489d46ead --rgw-realm s3-store
rados -p s3-store.rgw.meta ls --namespace root
rados -p s3-store.rgw.meta --namespace root getxattr .bucket.meta.ceph-bkt-aad0791f-76df-43d3-9313-cca489d46ead:2cf54eee-cb43-4937-a385-87fb7a5fc689.473844.1 user.rgw.iam-policy
radosgw-admin user info --uid=s3-admin --rgw-realm s3-store
kubectl -n rook-ceph get httproutes.gateway.networking.k8s.io 
 kubectl -n rook-ceph get service

2.安装cloudnative-pg

创建ceph-s3-creds secret

kubectl create namespace postgresql

kubectl create secret generic ceph-s3-creds -n postgresql   --from-literal=ACCESS_KEY_ID=5XQ8OBGZWG8MNO6M52Y2   --from-literal=ACCESS_SECRET_KEY=3negGAxSrskJ0OediH3osHLEAhs36AAoE8sD9nRt

kubectl apply --server-side -f https://github.com/cloudnative-pg/cloudnative-pg/releases/download/v1.29.0/cnpg-1.29.0.yaml

如果是生产系统,需要修改cnpg-1.29.0.yaml加入反亲和性,并将replicas改为3

在 spec.template.spec 下加入
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app.kubernetes.io/name
                operator: In
                values:
                - cloudnative-pg
            topologyKey: kubernetes.io/hostname

查看哪个pod是主库(leader)

kubectl get lease -n cnpg-system

注意:默认监控所有namesapce,如果需要监控特定namespace,请加以下参数,但是未验证

args:
- --leader-elect
- --watch-namespace=pg-prod
- --watch-namespace=pg-staging
- --watch-namespace=postgresql

和prometheus对接

# kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: cnpg-controller-manager-metrics
  namespace: cnpg-system
  labels:
    app.kubernetes.io/name: cloudnative-pg
spec:
  selector:
    app.kubernetes.io/name: cloudnative-pg
  ports:
  - port: 8080
    name: metrics
    targetPort: 8080
EOF
service/cnpg-controller-manager-metrics created

# kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: cnpg-controller-manager
  namespace: cnpg-system
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: cloudnative-pg
  endpoints:
  - port: metrics
    interval: 15s
EOF
servicemonitor.monitoring.coreos.com/cnpg-controller-manager created

# kubectl get svc -n cnpg-system
NAME                              TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
cnpg-controller-manager-metrics   ClusterIP   172.23.6.167   
<none>        8080/TCP   9s
cnpg-webhook-service              ClusterIP   172.23.7.171   
<none>        443/TCP    14m

3.安装postgresql

cat pg-prod-final.yaml 

# cat pg-prod-final.yaml 
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: pg-prod
  namespace: postgresql
spec:
  # 关闭自动创建(废弃警告消失)
  monitoring:
    enablePodMonitor: false

  instances: 3
  imageName: ghcr.io/cloudnative-pg/postgresql:17.2

  bootstrap:
    initdb:
      database: prod_db      # 自定义初始数据库名称
      owner: admin_user      # 自定义初始数据库所属用户/用户名
#      secret:
#        name: pg-prod-custom-creds # 自定义生成的 Secret 名称(不填则默认为 pg-prod-app)

  storage:
    size: 30Gi
    storageClass: openebs-hostpath-mysql-data2

  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: openebs-storage
            operator: In
            values:
            - enabled

    podAntiAffinityType: required
    tolerations:
    - key: ceph-taint
      operator: Equal
      value: "osd"
      effect: NoSchedule

  failoverDelay: 30

  postgresql:
    synchronous:
      method: any          # quorum模式,等价旧版min/maxSyncReplicas=1
      number: 1
      dataDurability: required  # 副本不足时阻塞写入,强数据安全
      failoverQuorum: true      # v1.28+ 切换时校验多数派,防脑裂丢数据
    parameters:
      # --- 数据安全 ---
      max_slot_wal_keep_size: "1GB"
      synchronous_commit: "on"           # 开启同步提交,保证零数据丢失
      wal_level: "logical"               # 开启逻辑日志,支持 CDC
      archive_timeout: "300s"            # 每 5 分钟强制切换一次 WAL,保证 RPO

      # --- 内存分配 (按 8GB 节点内存优化,如内存更大请按比例调大) ---
      shared_buffers: "2GB"              # 核心缓存
      work_mem: "16MB"                   # 排序操作内存
      maintenance_work_mem: "512MB"      # 管理维护操作内存
      max_connections: "200"             # 最大连接数

      # --- 存储与查询优化 ---
      random_page_cost: "1.1"            # 适配 Ceph/SSD 存储的随机 IO 开销
      effective_cache_size: "6GB"        # 操作系统可用作缓存的总量
      checkpoint_completion_target: "0.9" # 平滑检查点写入压力
      max_wal_size: "2GB"                # 增大 WAL 空间减少检查点频率
      min_wal_size: "512MB"

  # [备份策略 - 对接您的 Ceph S3]
#  backup:
#    retentionPolicy: "30d"               # 备份在 S3 中保留 30 天
#    barmanObjectStore:
#      serverName: "pg-prod"
#      destinationPath: s3://ceph-bkt-aad0791f-76df-43d3-9313-cca489d46ead/
#      endpointURL: http://rook-ceph-rgw-s3-store.rook-ceph.svc:80
#      # 引用上面创建的 Secret
#      s3Credentials:
#        accessKeyId:
#          name: ceph-s3-creds
#          key: ACCESS_KEY_ID
#        secretAccessKey:
#          name: ceph-s3-creds
#          key: ACCESS_SECRET_KEY
#      wal:
#        compression: gzip                # 日志压缩后再上传,节省带宽和空间

kubectl create -f pg-test-final.yaml

和prometheus对接

kubectl create -f cnpg-pg-full-alerts.yaml

# kubectl apply -f - <<EOF
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: pg-test-podmonitor
  namespace: postgresql
spec:
  selector:
    matchLabels:
      cnpg.io/cluster: pg-test
  podMetricsEndpoints:
  - port: metrics
    interval: 15s
EOF
podmonitor.monitoring.coreos.com/pg-test-podmonitor created
查看postgresql默认用户和密码,注意postgres没有密码  

默认数据库名 (dbname):app  
默认用户名 (user / username):app  
默认 Secret 名称:<cluster-name>-app(本次测试就是 pg-prod-app)  
# kubectl get secret -n postgresql pg-test-app -o jsonpath='{.data.password}' | base64 -d
s5gA8FtG57tQxkl1bmAONk8uc0GcCgsIrmROZ4XhOdrdDYbeMVhKXr4EqNT9ZSqI

# kubectl get secret -n postgresql pg-test-app -o jsonpath='{.data.username}' | base64 -d
app

登录postgresql

kubectl exec -it -n postgresql pg-test-1 --   psql "host=pg-test-rw user=app password=s5gA8FtG57tQxkl1bmAONk8uc0GcCgsIrmROZ4XhOdrdDYbeMVhKXr4EqNT9ZSqI dbname=app"

以超级管理员直连默认库

kubectl exec -it -n postgresql pg-test-1 -- \
  psql -U postgres -d postgres

kubectl exec -it -n postgresql pg-prod-1 -- psql -U postgres

4.查看数据同步关键参数

查看哪个pod是主库

# kubectl get endpointslice -n postgresql -l kubernetes.io/service-name=pg-test-rw
NAME               ADDRESSTYPE   PORTS   ENDPOINTS       AGE
pg-test-rw-v78lq   IPv4          5432    10.110.46.198   66m

切换主库测试

kubectl delete pod pg-test-1 -n postgresql

kubectl exec -it pg-test-1 -n postgresql -- psql -c "show synchronous_commit;"
Defaulted container "postgres" out of: postgres, bootstrap-controller (init)
 synchronous_commit 
--------------------
 on
(1 row)

# kubectl exec -it pg-test-1 -n postgresql -- psql -c "show synchronous_standby_names;"
Defaulted container "postgres" out of: postgres, bootstrap-controller (init)
    synchronous_standby_names    
---------------------------------
 ANY 1 ("pg-test-2","pg-test-3")
(1 row)

查看同步状态,确保sync_priority为1,sync_state为quorum或者sync,但不能是async,该指令只能主库执行

kubectl exec -it -n postgresql pg-test-2 -- psql -U postgres -c "select * from pg_stat_replication;"

 pid  | usesysid |      usename      | application_name |  client_addr  | client_hostname | client_port |         backend_start         | backend_xmin |   state   | sent_lsn  | write_lsn | flush_lsn | replay_lsn | write_lag | flush_lag | replay_lag | sync_priority | sync_state |          reply_time           
------+----------+-------------------+------------------+---------------+-----------------+-------------+-------------------------------+--------------+-----------+-----------+-----------+-----------+------------+-----------+-----------+------------+---------------+------------+-------------------------------
 3829 |    16386 | streaming_replica | pg-test-3        | 10.110.45.43  |                 |       49236 | 2026-04-08 08:30:14.91041+00  |              | streaming | 0/A000110 | 0/A000110 | 0/A000110 | 0/A000110  |           |           |            |             1 | quorum     | 2026-04-08 08:37:02.949663+00
 3957 |    16386 | streaming_replica | pg-test-1        | 10.110.49.106 |                 |       45990 | 2026-04-08 08:30:26.492283+00 |              | streaming | 0/A000110 | 0/A000110 | 0/A000110 | 0/A000110  |           |           |            |             1 | quorum     | 2026-04-08 08:37:02.950647+00
(2 rows)

kubectl exec -it -n postgresql pg-prod-1 -- psql -U postgres -d prod_db -c "show synchronous_standby_names;"
Defaulted container "postgres" out of: postgres, bootstrap-controller (init)
          synchronous_standby_names          
---------------------------------------------
 ANY 1 ("pg-prod-2","pg-prod-3","pg-prod-1")
(1 row)

dataDurability failoverQuorum两个参数验证方式 ① dataDurability: required(数据库层行为) 逻辑:在线可用同步副本 <1 时,所有写入阻塞,不提交事务防丢数据。 简易验证(业务低峰执行): 临时缩容删除 pg-prod-2、pg-prod-3,仅留主库 pg-prod-1; 主库执行 insert into xxx values(…); SQL 卡住无返回 = required 生效;立刻提交 = 未生效。

② failoverQuorum: true(CNPG Operator 控制器逻辑,库内无参数) 只能看 operator 日志校验,无 SQL 可查: 制造主库失联(停 pg-prod-1 pod / 隔离网络); 查看 cnpg-operator 日志,会打印多数派仲裁校验日志; 集群共 3 实例,必须至少 2 台存活才允许切换新主; 若只剩 1 台备存活,operator 拒绝切换,防止脑裂,代表该参数生效。

现在的状态已经是真正的生产级高可用了。

  1. 为什么现在的配置不会丢数据? 从你的 pg_stat_replication 输出看,状态发生了质变: synchronous_standby_names: 显示为 ANY 1 (“pg-test-2″,”pg-test-3”)。这意味着主库只有在收到 pg-test-2 或 pg-test-3 中至少一个副本的写入确认后,才会向你的应用程序返回“提交成功”。 sync_state 变为 quorum: 这代表 PostgreSQL 进入了法定人数同步模式。只要有一个从库在线并确认了日志,数据就是安全的。 sync_priority 为 1: 说明这两个从库都被正式纳入了同步选举名单。 结论:即使主库此刻突然断电,由于至少有一个从库(2号或3号)已经拿到了最新的日志,Operator 切换后数据是 100% 完整的。
  2. 为什么显示 quorum 而不是 sync? 这是 CloudNativePG 为了提高可用性的聪明做法: sync (Priority 模式):通常指定某个从库为同步,另一个为异步。如果同步从库挂了,主库会卡死。 quorum (Any 模式):你配置的是 minSyncReplicas: 1,所以只要副本集中有任意一个(Any 1)响应即可。这种模式在保证数据不丢的同时,容错性更高。

目前的同步延迟 (Lag) 全是空的,说明你的 Ceph 存储和网络性能非常好,完全跟得上主库的写入速度。

5.查看集群信息

查看集群名字

kubectl get cluster -n postgresql
NAME      AGE    INSTANCES   READY   STATUS                     PRIMARY
pg-test   128m   3           3       Cluster in healthy state   pg-test-1

查看集群节点信息

 kubectl get cluster pg-test -n postgresql -o jsonpath='{.status}' | jq

查看postgresql配置文件和参数

 kubectl get cluster pg-prod -n postgresql -o yaml

登陆主库

MAIN_PG=$(kubectl -n postgresql get cluster pg-prod -o jsonpath='{.status.currentPrimary}')
kubectl exec -it -n postgresql $MAIN_PG -- env PGPASSWORD="zStta53wvjUUEQYPOAfR4oBYCYvYd94dbjujsV5D3cgHI6po6lXl9RuBTknMjOih" psql -U admin_user -h 127.0.0.1 -d postgres

6.安装kubectl-cnpg插件

wget https://github.com/cloudnative-pg/cloudnative-pg/releases/download/v1.29.0/kubectl-cnpg_1.29.0_linux_x86_64.tar.gz
tar zxvf kubectl-cnpg_1.29.0_linux_x86_64.tar.gz 

chmod +x kubectl-cnpg
mv kubectl-cnpg /usr/local/bin/

通过kubectl-cnpg插件查看集群状态

立即查看同步状态

kubectl cnpg status pg-test -n postgresql
Cluster Summary
Name                     postgresql/pg-test
System ID:               7626286829348511765
PostgreSQL Image:        ghcr.io/cloudnative-pg/postgresql:17.2
Primary instance:        pg-test-2
Primary promotion time:  2026-04-08 08:30:12 +0000 UTC (20m51s)
Status:                  Cluster in healthy state 
Instances:               3
Ready instances:         3
Size:                    175M
Current Write LSN:       0/B000000 (Timeline: 2 - WAL File: 00000002000000000000000B)

Continuous Backup status
First Point of Recoverability:  Not Available
Working WAL archiving:          OK
WALs waiting to be archived:    0
Last Archived WAL:              00000002000000000000000A   @   2026-04-08T08:40:14.209077Z
Last Failed WAL:                00000002.history           @   2026-04-08T08:30:12.134846Z

Streaming Replication status
Replication Slots Enabled
Name       Sent LSN   Write LSN  Flush LSN  Replay LSN  Write Lag  Flush Lag  Replay Lag  State      Sync State  Sync Priority  Replication Slot
----       --------   ---------  ---------  ----------  ---------  ---------  ----------  -----      ----------  -------------  ----------------
pg-test-1  0/B000000  0/B000000  0/B000000  0/B000000   00:00:00   00:00:00   00:00:00    streaming  quorum      1              active
pg-test-3  0/B000000  0/B000000  0/B000000  0/B000000   00:00:00   00:00:00   00:00:00    streaming  quorum      1              active

Instances status
Name       Current LSN  Replication role  Status  QoS         Manager Version  Node
----       -----------  ----------------  ------  ---         ---------------  ----
pg-test-2  0/B000000    Primary           OK      BestEffort  1.29.0           node174
pg-test-1  0/B000000    Standby (sync)    OK      BestEffort  1.29.0           node172
pg-test-3  0/B000000    Standby (sync)    OK      BestEffort  1.29.0           node173

重点看输出中的这两项: Continuous Archiving: 应该显示 OK(代表 WAL 日志正成功传往 Ceph S3)。 Ready instances: 3:代表你有 3 个活跃副本。 Sync State: quorum:代表它们处于法定人数同步状态。 Standby (sync):代表两个从库都是同步节点。

这份状态报告非常完美,说明你的集群已经处于最高级别的生产就绪状态。 核心状态解读(为什么它是“零丢失”的) Sync State: quorum: 这证实了你之前的配置已完全生效。主库 pg-test-2 只有在 pg-test-1 或 pg-test-3 至少其中一个确认收到日志后,才会提交事务。 Standby (sync): 注意底部的实例状态,pg-test-1 和 pg-test-3 都被标记为 sync。这意味着它们都有资格在主库挂掉时被选为新主,且数据是 100% 同步的。 Working WAL archiving: OK: 你的 Ceph S3 备份通道是通的。日志正在源源不断地传往 S3(Last Archived WAL 就在几分钟前)。

7.备份

kubectl apply -f pg-backup-schedule.yaml
或者
# kubectl apply -f - <<EOF
apiVersion: postgresql.cnpg.io/v1
kind: ScheduledBackup
metadata:
  name: pg-test-daily-backup
  namespace: postgresql
spec:
  # 1. 立即执行一次
  immediate: true      

  # 2. 定时策略:每天凌晨 2:00 执行全量备份 (Cron 格式: 秒 分 时 日 月 周)
  schedule: "0 0 2 * * *" 

  # 3. 指定目标集群
  cluster:
    name: pg-test

  # 4. 备份保留策略(1.29 版本建议在这里也写一份,双重保险)
  # 配合 Cluster 定义中的 retentionPolicy: "30d" 使用
  backupOwnerReference: self
EOF

查看备份状态和进度

kubectl get backup -n postgresql 

或者用aws-cli查看s3 bucket

aws s3 ls s3://ceph-bkt-aad0791f-76df-43d3-9313-cca489d46ead   --endpoint-url https://s3.infraserviceonline.com   --recursive   --human-readable

查看 Operator 的日志来确认清理动作: kubectl logs -n cnpg-system -l app.kubernetes.io/name=cloudnative-pg | grep -i “retention”

8.Grafana

dashboard ID:20417

9.避免数据库和crds被误删除

最安全、最标准、CNPG 专用的锁死命令!只锁:postgresql.cnpg.io/v1 Cluster(你的 pg-test)

  1. 只锁死你这个 pg-test(单独命令)
    kubectl patch cluster pg-test -n postgresql --type=merge -p '{"metadata":{"finalizers":["do-not-delete"]}}'
  2. 锁死 CNPG 的 CRD(防止删 CRD 触发删库)
    kubectl patch crd clusters.postgresql.cnpg.io --type=merge -p '{"metadata":{"finalizers":["do-not-delete"]}}'
    ``
    3.验证

    kubectl get cluster pg-test -n postgresql -o yaml | grep finalizers -A 5

    
    10.各个组件职责分工
    组件名称    对应本次测试的实体   核心职责
    存储底座    Rook-Ceph (Block)   提供具备多副本、跨节点冗余的块存储。即使节点挂了,数据依然在。
    数据库管家   CNPG Operator   负责监控 PG 进程、自动选主(Failover)、滚动升级和配置下发。
    数据库实例   PostgreSQL Pods 运行真实的 PG 17 进程。1主2从,通过 Quorum 同步 确保数据不丢。
    备份大脑    Barman (内置模式)   负责将 WAL 日志和全量数据压缩并上传到你的 Ceph S3。
    定时器 ScheduledBackup 像 Linux 的 Crontab 一样,在每天凌晨自动踢一下 Operator 去做备份。
    流量调度    RW / RO Service RW 始终指向主库,RO 把查询压力分流给两个从库,实现读写分离。
    监控哨兵    Prometheus + PodMonitor 深入 Pod 内部 9187 端口抓取 cnpg_collector_up 等指标。

🔒 原创版权声明

本文标题:cloudnative-pg1.29/1.30安装部署

原文链接:https://www.infraserviceonline.com/cloudnative-pg1-29-1-30%e5%ae%89%e8%a3%85%e9%83%a8%e7%bd%b2/

版权来源:Infraservicenow

⚠️ 重要声明:本站所有文章均为原创技术文档,未经作者书面正式授权,严禁任何形式转载、复制、摘抄、二次发布

如需转载、引用、整理发布,请务必提前联系作者获得授权,违者将依法追究侵权责任。

© 2026 Infraservicenow All Rights Reserved. 保留所有权利。


发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

error: Content is protected !!