PostgreSQL · data 类目下的主从流复制关系型数据库

PostgreSQL 是 data 类目下的关系型数据库,以两个独立的单副本 StatefulSet(postgres-primary 读写、postgres-replica 只读)运行在 postgres 命名空间,通过 PostgreSQL 原生流复制(wal_level = replica + pg_basebackup)从主库向从库同步数据。NetworkPolicy 放行来自 app / platform / game / gitea / argo-workflows / glitchtip 等多个命名空间的入站连接,说明它是集群里被多方应用复用的共享数据库。

部署形态

主从是两个分开的 StatefulSet,资源、调度、存储各自独立。

  • Name
    命名空间
    Description
    postgres(namespace.yaml 显式声明)
  • Name
    工作负载类型
    Description
    两个 StatefulSet —— postgres-primary(replicas: 1,serviceName: postgres-primary)与 postgres-replica(replicas: 1,serviceName: postgres-replica)
  • Name
    镜像
    Description
    postgres:18-alpine(主、从、replica 的 init 容器统一同一镜像)
  • Name
    primary 调度
    Description
    nodeSelector: node-role=database,落在 worker3(pve3)
  • Name
    replica 调度
    Description
    nodeSelector: kubernetes.io/hostname=k8s-worker2(pve2),另加一条 soft podAntiAffinity 避免与 primary 同节点
  • Name
    端口
    Description
    5432(TCP,容器端口名 postgres)
  • Name
    存储
    Description
    两库各一个 volumeClaimTemplates,申请 200Gi,storageClassName: local-path,ReadWriteOnce,挂载到 /var/lib/postgresql/data,PGDATA=/var/lib/postgresql/data/pgdata
  • Name
    primary 资源
    Description
    requests cpu 500m / memory 1Gi,limits cpu 2000m / memory 2Gi
  • Name
    replica 资源
    Description
    requests cpu 250m / memory 512Mi,limits cpu 1000m / memory 1Gi
  • Name
    安全上下文
    Description
    runAsUser: 999 / fsGroup: 999 / runAsNonRoot: true
  • Name
    探针
    Description
    primary 与 replica 的 liveness / readiness 均为 pg_isready exec 探针(primary 带 -d $POSTGRES_DB)

replica 的 initContainers(init-replica)在数据目录为空时,先 pg_isready 等待 primary 就绪,再用 pg_basebackup -h postgres-primary... -Fp -Xs -P -R 从主库做基础备份初始化;若数据目录已存在则跳过,直接复用现有数据。

命名空间级还配有 LimitRange(容器 default 100m / 128Mi、defaultRequest 50m / 64Mi、max 2 cpu / 2Gi、min 10m / 16Mi)与 ResourceQuota(pods 10、requests.cpu 1 / requests.memory 2Gi、limits.cpu 4 / limits.memory 8Gi)兜底资源边界。

配置与依赖

配置由 ConfigMap postgres-config 提供,以 subPath 单文件挂载。primary 挂载 primary.conf(作为 postgresql.conf)、pg_hba.conf 与初始化脚本 init-primary.sh;replica 只挂载 pg_hba.conf。容器以 -c config_file=... / -c hba_file=... args 指定使用这些文件。

primary.conf 关键项:

配置项
listen_addresses'*'
wal_levelreplica
max_wal_senders10
wal_keep_size256MB
hot_standbyon
shared_buffers256MB
effective_cache_size1GB
max_wal_size4GB
log_timezone'UTC'
log_connections / log_disconnections / log_durationon

pg_hba.conf 对本地与 127.0.0.1 用 trust,对 0.0.0.0/0 的复制连接和普通连接均用 md5

init-primary.sh 在主库首次初始化时执行:创建带 REPLICATION 权限的复制角色,并创建业务用户 xiaomo(授予目标库全部权限 + CREATEDB)。

密码通过 ExternalSecret postgres-secret 从 ClusterSecretStore vault-backend 拉取,remoteRef.key: database/prod/postgres,refreshInterval: 1h,映射出的 key:

Secret keyVault property
POSTGRES_USERpostgres_user
POSTGRES_PASSWORDpostgres_password
POSTGRES_DBpostgres_db
REPLICATION_USERreplication_user
REPLICATION_PASSWORDreplication_password
XIAOMO_PASSWORDxiaomo_password

primary 注入全部六个 env;replica 容器只用 POSTGRES_USER / POSTGRES_PASSWORD,其 init 容器用 REPLICATION_USER / REPLICATION_PASSWORD(后者经 PGPASSWORD)做 pg_basebackup

访问与监控

services.yaml 定义三个 ClusterIP Service:postgres-primary(读写,选 role: primary)、postgres-replica(只读,选 role: replica)、postgres-headless(clusterIP: None,供 StatefulSet 稳定网络标识,选所有 app: postgres),均暴露 5432。应用按读写分离接入:写走 postgres-primary.postgres.svc.cluster.local:5432,读走 postgres-replica...:5432。无 Ingress,仅集群内访问。

监控由独立的 postgres-exporter Deployment(replicas: 1,镜像 prometheuscommunity/postgres-exporter:v0.19.1,端口 9187)承担,DATA_SOURCE_URI 指向 postgres-primary:5432/postgres?sslmode=disable,凭据复用 postgres-secret。ConfigMap postgres-exporter-queries 提供自定义查询,包含复制延迟(pg_replicationlag)、postmaster 启动时间、pg_stat_user_tables 表级统计。Service postgres-exporter(9187)由 ServiceMonitor postgres(selector app: postgres-exporter,interval: 30s,path /metrics)被 Prometheus 抓取,relabel 后 service/job 统一标为 postgres。本目录未见 PrometheusRule、HPA、VPA、PDB。

NetworkPolicy 采用默认拒绝 ingress(default-deny-ingress.yaml)+ 按需放行的模型,放行来源包括:同命名空间、app、platform、game、gitea、argo-workflows、glitchtip、LAN,以及 Prometheus 抓取;egress 放行 DNS。

注意事项

CLAUDE.md 没有 postgres 专属踩坑段,以下为 manifest 与目录 README 中可验证的运维要点。

  • 主从是手动 HA,无自动 failover。README 的故障恢复流程:主库故障时进 replica pod 执行 pg_ctl promote -D /var/lib/postgresql/data/pgdata 手动提升;从库数据损坏时 kubectl delete pod postgres-replica-0,重建时 init 容器会自动 pg_basebackup 重新初始化。
  • replica 注释说明它被刻意从 node-role: database(worker3,与 primary 同节点、无 HA 价值)改钉到 worker2(pve2),即一个不同物理主机,使 replica 能在 worker3/pve3 整机故障时存活并被手动提升;podAntiAffinity 是防止与 primary 同调度的软性兜底。
  • 存储用 local-path,数据绑定到所在节点的本地盘,pod 重启后会回到同一节点。
  • 从库处于 hot_standby,对其写入会报错;读负载分散应显式连 postgres-replica Service。
  • 监控复制延迟用 exporter 暴露的 pg_replication lag 指标(单位秒)。

返回 data 类目总览

评论