ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

K8s上基于Bitnami的PostgreSQL+pgpool高可用集群部署实战

K8s上基于Bitnami的PostgreSQL+pgpool高可用集群部署实战 前阵子在 K8s 里搭了一套基于 Bitnami 的 PostgreSQL pgpool 集群从选型、部署到故障演练踩了不少坑也把整个流程跑顺了。今天把这套完整方案写出来包括为什么要用 pgpool、Helm values 到底怎么配、故障转移怎么触发以及我实际遇到过的典型问题。那段时间把 Helm、Bitnami、postgres、pgpool、集群这几个词反复查了好几遍这篇就当是给当时的自己存个档也给后来的人抄作业用。先说清楚这套方案解决的痛点应用需要读写分离和高可用但不想自己手写一个 Patroni 或 repmgr 那套复杂逻辑也不想把数据库迁到云厂商 RDS 上。用 Bitnami 的 postgresql chart 先拉起异步流复制的主从库再部署一个 pgpool 作为智能代理连接池、读写分离、故障转移都由 pgpool 统一接管。适合已经跑了 K8s、希望数据库也能上容器、并且愿意接受“数据库还是有状态服务”这套心智的团队。如果你只想跑个测试环境或者对可用性要求极高那可以再斟酌一下后面我会说清楚边界。1. 方案选型为什么是 Bitnami 的 chart pgpool1.1 自建数据库上 K8s 的几个现实问题很多人第一反应是PostgreSQL 有官方镜像我自己写个 StatefulSet 不就完了理论上是但你要处理的问题非常琐碎。首先是数据持久化StatefulSet 的 PVC 要设计好存储类和回收策略然后是主从复制PostgreSQL 的异步流复制虽然配置不复杂但主库挂了以后谁来提升从库如果自己写脚本又要处理脑裂、权限、通知应用切换一大堆事情再加上连接管理应用端的连接池、读写路由、健康检查全部自己造轮子。我见过不少团队就是从“一个 Pod 跑 Postgres”开始发展到后来发现运维成本越来越高最后被迫换成云数据库。与其这样不如一开始就把高可用和读写分离考虑进去。但直接上云数据库也有顾虑成本是一方面另一方面是不想被某个云厂商绑定。所以就有了这种组合K8s 部署、开源组件、Bitnami 打包。1.2 pgpool 在整个架构里的角色pgpool 不是一个简单的连接池它本质上是 PostgreSQL 前面的一个代理层。应用连接的是 pgpoolpgpool 根据 SQL 类型把请求转发给背后的主库或从库。它做几件关键事情。连接复用后端 Postgres 的连接数是有限的pgpool 把应用的大量短连接复用到底层有限的数据库连接上能明显缓解连接数压力。读写分离SELECT 基本走从库INSERT、UPDATE、DELETE 走主库。控制粒度由 loadBalancingMode 配置决定可以做到查询在所有节点间负载均衡也可以只发往从库。故障转移定期对后端 PostgreSQL 节点做健康检查发现主库不可用时执行 failover 脚本把从库提升为新的主库并更新 pgpool 内部的节点状态。应用无需感知这个过程。自动恢复如果从库恢复或者新的从库重新加入pgpool 能探测到并把节点状态重新标记为可用。理解这一点很重要pgpool 承担了高可用切换的编排角色而 Bitnami 的 postgresql chart 只是负责把主从数据库实例跑起来、配置好流复制、初始化好账号。两者配合才能形成完整方案。1.3 为什么选 Bitnami 而不是其他方案社区里做 PostgreSQL 高可用的方案不少粗列一下大概有四类。官方 chart 只做单实例高可用能力约等于零。Crunchy Data 和 CloudNativePG 很强它们把 operator 模式发挥到极致自动管理备份、克隆、Switchover但学习曲线陡对新手不友好而且很多公司不一定想引入一个 operator 来占资源。Zalando 的 operator 是 Patroni 那一派复杂度和灵活性并存。Bitnami 的 chart 属于典型的“配置多但心智简单”路线它用 StatefulSet 跑 PostgreSQL用 percona 或 pgpool 之类的组件补全外围能力values.yaml 几乎能覆盖所有常见需求社区文档和 Stack Overflow 上的案例也很多。Bitnami 的 postgresql chart 默认支持 architecturereplication一条命令就能拉起主从结构甚至内置了 pgpool 相关的 subchart 支持。虽然我后来是分开部署 PostgreSQL 和 pgpool 的但你如果只想快速验证直接用一张 values.yaml 把两个 chart 一起渲染出来也可以。分开部署的好处是职责更清晰升级和替换也更灵活。1.4 整体架构和流量走向我用的是 Helm 3 Bitnami postgresql chart 部署了一个带两个从库的集群1 primary 2 replicas然后用独立的 Bitnami pgpool chart 部署了两个 pgpool Pod。应用不直接访问数据库 Pod IP而是访问后端的 Service。从流量角度看一条 SELECT 请求从应用发出后会先到达 pgpool 的 Service然后由 pgpool 转发到某个 PostgreSQL 后端节点。如果当前后端有两个从库pgpool 会按负载均衡策略分摊读取。DML 请求则强制发往主库。主库故障后pgpool 会把某个从库提升为主库后续请求自动切到新主库。这个架构看起来简单实际部署时要注意一个细节pgpool 必须能通过 K8s Service 访问到所有 PostgreSQL 节点。Bitnami 的 helm chart 默认会给 primary 和 replicas 各生成一个无头服务和一个聚合服务pgpool 的配置里填写的 host 通常是聚合服务名让 DNS 解析出多个 A 记录。这里踩坑的地方是如果只填了 primary 的 headless servicepgpool 就只探测到主节点读写分离完全失效。方案核心思路优点缺点官方 postgresql chart单实例简单无高可用CloudNativePGOperator自动备份、切换强学习曲线高Crunchy DataOperator企业级特性多资源占用高Bitnami chart pgpool代理层配置透明部署快故障切换依赖脚本2. 部署前的准备版本、资源、存储2.1 版本选型Helm、K8s、PostgreSQL、pgpool 怎么搭配部署前先确定版本别随手 latest。我用的时候环境是这样的Kubernetes 1.26Helm 3.11Bitnami postgresql chart 版本 15.5.x对应 PostgreSQL 15.xBitnami pgpool chart 版本 13.x对应 pgpool 4.4.x。目前这些版本号比我当时新不少但选型原则是一样的。选择 chart 版本时可以去 Bitnami 的 README 或 Artifact Hub 查看兼容性矩阵注意几点。K8s 旧版本能不能跑新 chart很多时候跟 RBAC 资源和 API 版本有关。PostgreSQL 16/17 虽然新但 pgpool 和后端 PostgreSQL 的大版本兼容性要确认特别是认证方式默认值的变化。还要看 chart 里主从复制用的方式Bitnami 的老版本支持基于 WAL 文件的归档新版本默认是流复制配置项名字也有变化。我可以给你一个简单的选型策略如果没有特殊需求PostgreSQL 用 15 或 16pgpool 用 4.4 或 4.5。不要追最新也不要停在 11。PostgreSQL 15 后默认有 public schema 权限收紧之类的安全改进16 的流复制参数更宽松但从高可用角度看15 的生态最稳。至于 pgpool4.4 之后新增了更多健康检查配置4.5 对 SCRAM 认证支持更友好。表格整理起来就是下面这样你可以按自己的实际情况调整组件推荐版本备注Kubernetes1.24低于 1.24 建议先升集群Helm3.83.x 都可Bitnami postgresql chart15.x / 16.x注意 chart 里 PostgreSQL 版本PostgreSQL15 / 1615 优先Bitnami pgpool chart13.x / 14.x注意 pgpool 版本号与 chart 号不同pgpool4.4 / 4.54.4 够用4.5 更稳2.2 资源评估和容量规划有状态服务部署前不做资源评估后面出问题的概率极大。我给的参考是比较保守的PostgreSQL primary 需要 2C4G 起步你要是跑的是重业务4C8G 更安心。从库可以比主库低配但别低太多因为 failover 后从库要立刻扛起全部业务流量。我这里生产环境用的是 4C16G 的节点各三台CPU 水位平时 30%扛得住业务峰值。pgpool 属于轻量代理但它要处理连接池和健康检查一般 1C2G 一个 Pod两个副本就够。连接数大的场景注意给 pgpool 调大内存因为它会缓存一定量的查询结果或者保存会话状态。存储类这块是重点。数据库吃 IOPS本地机械盘基本可以放弃。你要确保 StorageClass 的 provisioner 是 SSD 或者高性能云盘且回收策略是 Retain。如果存储类用的是 Delete那 Helm uninstall 时 PVC 可能被连带删除这是很多人的噩梦数据直接就没了。我用的云厂商块存储默认是 Retain但很多自建 Rook Ceph 环境把默认改成 Delete所以 values.yaml 里必须显式写一遍 persistence.storageClass 和 volumeAttributes。参数建议如下资源项Primary 节点Replica 节点pgpool 节点最小 CPU2 核2 核1 核最小内存4 GB4 GB2 GB推荐磁盘SSD 100 GBSSD 100 GB本地盘即可副本数122这里补一个容易被忽略的问题Pod 调度时要考虑跨可用区或跨节点。StatefulSet 默认调度是随机的如果你没配 topologySpreadConstraints主库和从库可能落在同一个节点上。节点一挂整个集群跟着挂。所以部署前要在 values.yaml 里加至少一条 nodeAffinity 或者 PodTopologySpreadConstraints让不同角色分散到不同物理节点。2.3 安装 Helm 并添加 Bitnami 仓库这个步骤不复杂但经常会有人在这翻车。如果你还没安装 Helm可以这样操作curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 chmod 700 get_helm.sh ./get_helm.sh装完验证一下版本helm version --short然后添加 Bitnami 的 chart 仓库并更新索引helm repo add bitnami https://charts.bitnami.com/bitnami helm repo update这一步之后你可以先查一下有哪些版本可用方便后面精确指定版本helm search repo bitnami/postgresql --versions helm search repo bitnami/pgpool --versions注意网络环境如果不太稳定repo update 可能超时。这时候可以设置 Helm 的 UA 或者换用代理加速但那个属于通用调优不是这套方案的必需操作。版本列表拉下来之后建议把要用的版本号记下来部署时带 --version 参数不要用最新版。因为新 chart 升级有时会改 values 结构你在旧版本里跑通的配置在新版本上可能会直接报错。2.4 创建命名空间和初始 Secret 规划我习惯单独建一个 namespace避免数据库相关对象和应用混在一起。同时 PostgreSQL 和 pgpool 之间的认证信息最好用 Secret 管理不要直接写在 values.yaml 里防止仓库泄露密码。先创建命名空间kubectl create namespace database然后我们需要规划几种账号。postgres 超级用户对应 postgresqlUsername 和 postgresqlPassword。你还需要一个 replicator 账号用于流复制。再准备一个专门给 pgpool 健康检查用的账号因为 pgpool 要周期性地执行 SELECT 1 之类的心跳查询。这个账号的权限不需要太高但必须能从 pgpool Pod 所在网络访问数据库。如果再加上应用账号最好也建好但 Bitnami chart 只支持建一个自定义用户默认是 postgres。我们要的这几个账号要么在 values.yaml 里配置要么用 postgres 超级用户登录后在数据库里手动建。手动建账号在后面的故障转移章节是必备技能因为 pgpool 的 failover 脚本需要连接新主库执行一些操作。建议提前把 SQL 存成运维文档我就是没提前存后来某次切换时手忙脚乱。3. 核心实操用 Helm 部署 PostgreSQL 主从集群3.1 先搞定 PostgreSQL chart 的 values.yaml我这边把部署拆成两个步骤先部署 PostgreSQL再部署 pgpool。这样排查问题的时候边界清晰数据库连接不上是数据库的问题pgpool 连接池报错是 pgpool 的问题。部署 PostgreSQL 的 values.yaml 大致如下architecture: replication auth: enablePostgresUser: true postgresPassword: YourStrongPostgresPassword username: appuser password: YourAppPassword database: appdb replicationUsername: repluser replicationPassword: YourReplicationPassword primary: persistence: enabled: true storageClass: managed-premium size: 100Gi resources: requests: memory: 4Gi cpu: 2 limits: memory: 8Gi cpu: 4 nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - zone-a readReplicas: replicaCount: 2 persistence: enabled: true storageClass: managed-premium size: 100Gi resources: requests: memory: 4Gi cpu: 2 limits: memory: 8Gi cpu: 4 nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: topology.kubernetes.io/zone operator: In values: - zone-b - zone-c metrics: enabled: true extraEnvVars: - name: PG_EXPORTER_DISABLE_DEFAULT_METRICS value: true这里要解释几个关键点。architecture: replication 是核心它让 chart 生成一个 primary StatefulSet 和若干个 read replica StatefulSet。auth 块里面的 replicationUsername 和 replicationPassword 是流复制专用账号必须单独设置不能跟 appuser 混淆。primary 和 readReplicas 的资源设置要尽量贴近实际。别在测试环境配 8C16G也不要生产环境只配 1C2G。存储这块我再强调一次storageClass 必须显式指定而且要确保该 StorageClass 的 reclaimPolicy 是 Retain。你可以用 kubectl 查kubectl get sc managed-premium -o yaml | grep reclaimPolicy如果不是 Retain去存储类配置里改掉或者选另一个存储类。刚才那个 values 里 nodeAffinity 用的是 zone 标签目的是把主从分散到不同可用区。如果你的集群不支持 zone 标签可以换成 rack 或 hostname 标签但无论如何都得加。执行部署helm upgrade --install postgres bitnami/postgresql \ -n database \ -f postgresql-values.yaml \ --version 15.5.20等待 Pod 就绪kubectl -n database get pods -l app.kubernetes.io/namepostgresql你看到的输出应该是这样的NAME READY STATUS RESTARTS AGE postgres-postgresql-0 1/1 Running 0 5m postgres-postgresql-1 1/1 Running 0 4m postgres-postgresql-2 1/1 Running 0 4m要注意的是Bitnami chart 中的 readReplicas 的 Pod 名也是 postgres-…只是编号不同。到底哪个是 primary别凭记忆猜用下面的命令确认kubectl -n database exec postgres-postgresql-0 -- bash -c psql -U postgres -c SELECT pg_is_in_recovery();返回 f 说明是主库返回 t 说明是备库。3.2 创建 pgpool 前置账号并配置认证在部署 pgpool 之前需要先确保数据库里有健康检查账号。Bitnami 的 pgpool chart 默认会尝试用 postgresql 用户做健康检查但生产环境最好单独建一个。用超级用户登录 primary执行下面这些 SQLCREATE USER pgpool_health WITH PASSWORD HealthCheckPass; GRANT CONNECT ON DATABASE appdb TO pgpool_health; GRANT SELECT ON pg_stat_replication TO pgpool_health;这里 GRANT SELECT ON pg_stat_replication 非常关键。pgpool 在做节点状态检查时需要读取 pg_stat_replication 来判断主从身份权限不够直接报错pgpool 会认为所有节点都异常。接下来部署 pgpool 的 values.yamlreplicaCount: 2 service: type: ClusterIP port: 5432 pgpool: postgresql: # 这里填的是 PostgreSQL 聚合 Service 名称 host: postgres-postgresql port: 5432 username: appuser password: YourAppPassword database: appdb loadBalancingMode: read_write healthCheckPeriod: 10 healthCheckTimeout: 5 healthCheckUser: pgpool_health healthCheckPassword: HealthCheckPass enablePooling: true maxPoolSize: 50 connectionLifeTime: 300 logConnections: true logDisconnections: true resources: requests: cpu: 500m memory: 512Mi limits: cpu: 2 memory: 2Gi这里 host 字段的值很多人配错。我填的是 postgres-postgresql这是 Bitnami postgresql chart 默认生成的聚合 Service 名称。它背后的 Endpoints 同时包含 primary 和 read replica 的 IP。pgpool 启动时通过 DNS 查询这个服务名拿到多个后端节点 IP然后挨个探测。loadBalancingMode 有三个值read_write、read_only 和 none。要读写分离就用 read_write。healthCheckPeriod 是健康检查的间隔秒数不要太短否则数据库压力大也不要太长否则故障转移不迅速我用的 10 秒。healthCheckUser 就是刚才建的 pgpool_health 账号。然后执行部署helm upgrade --install pgpool bitnami/pgpool \ -n database \ -f pgpool-values.yaml \ --version 13.2.0查看 Podkubectl -n database get pods -l app.kubernetes.io/namepgpoolpgpool Pod 起来以后我们可以登录验证它是否已经正确识别了所有后端节点。进入 Pod 内执行kubectl -n database exec -it pgpool-pgpool-0 -- bash psql -h localhost -U appuser -d appdb -c SHOW POOL_NODES;正常输出里应该有三个节点每个都有 ip 字段、节点角色和状态。如果只看到两个甚至一个说明 pgpool 没有探测到全部 replica排查方向先看 Service DNS 解析是否正常再去看 pgpool 日志里的连接错误。3.3 配置应用的统一入口和连接参数应用连接数据库不应该直接连 pgpool 的一个 Pod而应该通过 pgpool 的 Service。刚才 values.yaml 里我配置的是 ClusterIP应用在集群内部访问 pgpool-pgpool:5432 即可。如果你是本地调试可以用 port-forwardkubectl -n database port-forward svc/pgpool-pgpool 5432:5432然后本地就能用 localhost:5432 连接了psql -h localhost -p 5432 -U appuser -d appdb -c select 1;连接参数上有几个优化点可以分享。应用端的 JDBC 连接串里加上连接池参数比如 hikari 的 maximumPoolSize 可以保持 10 到 20 之间。pgpool 的 maxPoolSize 控制的是每个 pgpool 后端到 PostgreSQL 的连接缓存不代表应用能无限复用连接。你把 psql 连接上去以后在 PostgreSQL 一侧可以查询 pg_stat_activity看 appuser 产生的连接数。如果连接数高于预期调大 pgpool 的 maxPoolSize 或者让应用侧减少连接建立。3.4 验证读写分离是否真正生效读写分离有没有生效不能靠猜。一个简单的验证方式是这样的先在主库建一张测试表插入一行数据然后通过 pgpool 连接反复执行 SELECT 和 INSERT再看这些请求分别落在哪个节点上。登录 pgpool 容器开启日志追踪psql -h localhost -U appuser -d appdb然后执行CREATE TABLE test_rw (id int primary key, note text); INSERT INTO test_rw VALUES (1, primary write); SELECT * FROM test_rw;执行完以后我们去 PostgreSQL 各个节点上看这些连接来自哪里。每个节点执行SELECT datname, usename, client_addr, state, query FROM pg_stat_activity WHERE datnameappdb;你会发现 INSERT 那条连接的 client_addr 指向的是 pgpool Pod IP而且这个连接在 primary 节点上SELECT 那条可能在某个 replica 节点上。如果你看到 SELECT 也跑到了 primary先检查 loadBalancingMode 是不是 set 到了 none或者 replica 节点是不是已经处于 down 状态。再给你一个更直接的命令在 psql 里执行SHOW POOL_NODES;看 node_type 列primary 会是 primaryothers 是 standby。再看 role 列如果 standby 节点显示 standby说明后端连接没问题。还有一个 backend 状态如果 standby 显示 down那读写分离肯定失配。3.5 用 pgbench 做压测可选生产环境部署完最好跑一下 pgbench确认读写在分流后性能没有断崖。进入 pgpool Pod用 pgbench 做一轮短测试pgbench -h localhost -U appuser -d appdb -c 10 -j 2 -T 30 -S -P 1上述命令是全 SELECT 的只读压测可以看到 TPS 大致是多少。再写压测pgbench -h localhost -U appuser -d appdb -c 10 -j 2 -T 30 -P 1两者对比能看出读扩展的效果。如果只读 TPS 比写 TPS 高很多说明负载均衡生效了如果只读 TPS 异常低极有可能请求全打在主库上从库完全没接入。还可以用 pgbench 的 init 步骤先建测试数据pgbench -h localhost -U appuser -d appdb -i -s 10压测期间观察 PostgreSQL 各个节点的 CPU如果所有节点都有波动读写分离分布基本正常。4. 故障转移、运维排查与常见问题4.1 pgpool 的高可用和故障转移原理现在集群跑起来只是第一步真正要验证的是故障转移。pgpool 的 failover 机制是它周期性地对每个后端节点执行健康检查检查方式就是连接数据库并执行一个查询比如 SELECT 1。如果在 healthCheckTimeout 内没有响应节点就会被标记为 down。如果 down 的节点是 primarypgpool 会触发 failover。Bitnami 的 pgpool chart 默认带了一个辅助 Pod 角色pgpool 容器里面包含了一个 failover 脚本它做的事情本质上是在数据库侧提升某个从库为新的主库。这里有一个非常重要的概念——pgpool 本身不执行 PostgreSQL 的 promoted它只是调用脚本去执行 promotion。具体流程是pgpool 检测到 primary 不可用。pgpool 从候选从库中挑一个通常是恢复最快的或者第一个 Pod。pgpool 在新主库上执行类似pg_ctl promote的动作或者通过trigger_file触发提升。之后 pgpool 更新内部节点状态新的 primary 开始接受写流量。Bitnami 的 postgresql chart 在初始化 replica 时配置了trigger_file机制所以从库只要看到某个路径出现文件就会自动 promote。pgpool 的 failover 脚本会远程在从库容器里创建这个 trigger 文件从而实现提升。这个设计有几个坑。pgpool 执行 failover 脚本时需要 ssh 或 kubectl exec 到 PostgreSQL Pod 里面。Bitnami 的 pgpool chart 在做高可用配置时需要在 values.yaml 里指定一个 ssh 密钥让 pgpool 可以无密登入 PostgreSQL Pod。否则 failover 根本执行不了。我见过太多人只部署了主从和 pgpool看起来一切正常结果一拔主库 Pod整个服务彻底不可用。做个实验来验证。找到 primary Pod模拟宕机kubectl -n database delete pod postgres-postgresql-0注意StatefulSet 控制器会立刻重新创建一个同名 Pod但这个时候它的数据卷还是原来的启动后可能仍然是主库也可能因数据恢复机制变成从库。为了更接近真实故障最好同时做网络隔离实验比如用 NetworkPolicy 阻断 primary Pod 与其他节点的通信这样内部状态更混乱更能看出 pgpool 的抗压能力。观察 pgpool 日志kubectl -n database logs -l app.kubernetes.io/namepgpool -f正常流程下你会在日志里看到检测到主库 down然后执行 failover 脚本最后确认新的主库。这时候用 psql 连上 pgpool 执行 SHOW POOL_NODES会看到原来的 postgres-postgresql-1 变成了 primary。建议把故障演练脚本化放到 CronJob 或者运维平台上每月跑一次。不然真到故障发生时你根本不知道这个流程能不能跑通。4.2 手动提升和降级处理有些场景不需要自动故障转移比如机房维护时想主动切换主库。pgpool 提供了一个知名命令 pcp_promote_node。你可以用它在不触发健康检查的情况下主动提升某个从库kubectl -n database exec -it pgpool-pgpool-0 -- bash pcp_promote_node -h localhost -p 9898 -U pgpool_pcp_admin -n 1 -w这条命令里的 n 是节点 ID需要通过 pcp_node_info 查出。用 pcp 命令之前要确认 pcp 用户和密码已经在 pgpool 的配置里设置好。Bitnami chart 默认创建一个 pgpool_pcp_admin 用户密码在 Secret 里可以查到。主动切换的流程和自动故障转移不同它通常要求先把原主库降级避免双主写冲突。低版本的 pgpool 在这块控制得比较粗糙高版本 4.5 会好一些。我建议主动切换前先看下原主库的 wal log 是否都已经发送到目标从库执行SELECT pg_last_wal_receive_lsn(), pg_last_wal_replay_lsn();在两个节点上对比 LSN确保新主库 lag 为 0。然后再 promote。4.3 常见问题速查表照着排查就行这部分直接上表格都是我实际遇到过的按频率和影响程度排序。症状可能原因排查和修复动作psql 连不上 pgpool Servicepgpool 容器启动失败或 Service 名不对看 pgpool 日志确认 postgres 主机名填写正确SHOW POOL_NODES 显示从库 down健康检查账号权限不足确认 pgpool_health 用户有 pg_stat_replication 读权限只能连接主库从库不承接查询loadBalancingMode 被设置为 none改成 read_write重启 pgpoolfailover 后新主库未提升trigger_file 路径不一致检查 postgresql chart 和 pgpool chart 的 trigger_file 配置是否一致认证失败 SCRAM密码哈希与 pgpool 服务端配置不匹配确认 pgpool 的 allowClearTextPassword 和 passwordEncryption 一致性数据丢失PVC 被自动删除检查 StorageClass reclaimPolicy修复为 Retainpgpool 日志大量连接超时后端 PG 连接数被打满调大 PostgreSQL 的 max_connections 与 pgpool maxPoolSizeHelm upgrade 失败values 结构不兼容先检查新 chart 的 breaking changes必要时 helm rollback4.4 日常巡检清单部署完不是结束日常巡检才是大头。我坚持每周看几项第一Pod 状态和节点分布确认 primary 和 replica 没有跑到同一个节点上使用kubectl -n database get pods -o wide看 Node 列。第二流复制延迟在 primary 上执行SELECT * FROM pg_stat_replication;重点看 replay_lag。如果延迟持续增长查网络和磁盘 IO。第三pgpool 节点状态周期性执行 SHOW POOL_NODES关注角色和状态列。第四节流复制状态变化如果某个 replica 掉过线看它是否已经追平最新 LSN。第五存储水位和使用率PVC 使用超 70% 就该扩容了。Bitnami chart 的 primary 和 replica 的 PVC 都是按 StatefulSet 名称命名的可以这样查看容量kubectl -n database get pvc -l app.kubernetes.io/namepostgresql还有一个运维细节升级 PostgreSQL chart 时Oracle 之类的版本发布说明会提醒你备份。在 K8s 里改配置时一定要小心helm upgrade可能会因为 StatefulSet 的 immutable 字段而报错。这时候的解决方案是用kubectl patch或直接编辑 StatefulSet但我不建议在数据库类工作负载上频繁做这种热修改。最稳妥的做法是加一次 value 修改就 release 一次但升级前必须做备份。关于备份简单说一句。Bitnami postgresql chart 自带一个 backup 子命令可以跑kubectl exec执行 pg_dump但对大型数据库来说 pg_dump 太慢。更靠谱的方案是配置 wal-g 或使用云存储做 WAL 归档。这套方案的核心是高可用和读写分离但备份是你最后的救命稻草数据安全永远高于虚机可用性。4.5 移除和重装的正确姿势万一真的要把这套环境全部删掉重来直接helm uninstall前必须想清楚 PVC 的去向。前面提过如果存储类是 Delete数据会瞬间被删。所以卸载前先用以下命令把 PVC 状态保存住kubectl -n database get pvc -o yaml pvc-backup.yaml即使是 Retain 策略PVC 对象本身在 Helm release 卸载后也可能被删掉只是后端存储卷还在。想要恢复数据时你需要手动重建对应的 PVC 并绑定到底层卷上。这一步非常繁琐所以实际经验是不要轻易卸载 Database 的 Helm release尤其是生产环境。要改配置时尽量在原 release 上进行 upgrade。如果你想在同一个集群里跑多套环境注意命名空间隔离。Bitnami chart 生成的 Secret 名称是 release 名加后缀在不同的 namespace 里用同名 release 是可以的但 K8s 的 Service 解析规则是postgres-postgresql.namespace.svc.cluster.local。如果你配置 pgpool 的 host 时没带 namespace默认解析到 pgpool 所在 namespace 的同名 Service不同 namespace 下就会连错这也是挺隐蔽的坑。5. 我踩过的坑和调试心得最后分享几个真实的调试细节。有一次 pgpool 的 POOL_NODES 显示从库全红但 PostgreSQL 本身完全没有问题所有节点都能 log in。后来在 pgpool 日志里看到failed to check role of node查了一圈发现是健康检查账号没有对pg_stat_replication的 SELECT 权限。这个错误信息非常误导它看起来像是网络问题实际上是权限问题。加权限后一切正常。所以如果你是跟着这篇文章搭一定记得把那条 GRANT 语句执行了。另一次是 failover 演练时primary 删掉之后 pgpool 确实检测到了但迟迟没有提升新的从库。后来发现原因是 pgpool 在 failover 时用 ssh 密钥去登录从库触发脚本而 Bitnami 的 postgresql chart 默认没有给容器安装 ssh server。也就是说要让 Bitnami 的 pgpool failover 脚本生效必须在 postgresql values.yaml 里额外配置 sshd。否则就需要你自己提供脚本上下文。这个可以提前验证直接测试 pgpool 容器能否 ssh 到 postgres 容器不能的话所有自动化切换都是空谈。还有一次是密码认证问题。PostgreSQL 15 默认可能使用 SCRAM-SHA-256而 pgpool 如果还沿用 md5 配置认证会失败。Bitnami 的 chart 会协调这些但自建镜像或者手动改过 PG 配置的话就很容易踩雷。处理方式是在 PostgreSQL 的 postgresql.conf 里统一 password_encryption并在 pgpool 的 pool_hba.conf 里对应设置两边保持一致。遇到这种问题日志里通常有明确提示多抬头看日志比瞎试参数有用。度量指标方面如果你已经配了 metrics.enabled那 Prometheus 那边可以配上 postgresql exporter。简单一点的配置是给 pgpool 暴露一个监控端口或者通过kubectl exec配合SHOW POOL_STATUS去取数。我自己的巡检脚本核心就是三件事连接数是否接近上限、流复制延迟是否低于阈值、pgpool 节点角色是否与预期一致。用 CronJob 定时跑输出到日志有问题就在群里告警基本够用。现在这套方案已经稳定跑了一段时间。当初那个纠结要不要上云数据库的团队最终保留了这套自建方案原因无非是成本和灵活性。相比云数据库百 GB 每月的账单自建这套在同等配置下成本低不少。但这不代表自建是唯一正确答案。如果你所在团队只有两三个人还要兼顾应用开发那直接买云数据库可能是更明智的选择。运维精力是自己搭数据库时最大的隐形成本这一点一定要算进去。最后随手记一个有用的命令吧。想知道 pgpool 和 PostgreSQL 之间的实时连接情况直接在 pgpool Pod 里执行show pool_status; \ show pool_processes;这两条命令会比看官方文档更让你真切感受到“我现在站在数据库代理的视角”。把这些命令存进自己的运维手册后面维护起来会轻松很多。
返回列表