CloudNativePG 应用连接指南:通过 Kubernetes Services 与 Secrets 接入 PostgreSQL 集群
2026/9/16 19:49:17 网站建设 项目流程

CloudNativePG 应用连接指南:通过 Kubernetes Services 与 Secrets 接入 PostgreSQL 集群

【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg

本指南面向希望在 Kubernetes 集群内让应用接入 CloudNativePG 所管理 PostgreSQL 集群的开发者与运维人员,系统讲解 Operator 为每个集群自动生成的服务发现机制(DNS 解析与环境变量)、凭据 Secrets 的字段结构,以及如何遵循最佳实践安全、稳定地建立数据库连接。阅读本文后,你将掌握rw/ro/r三类服务的选择方法、-app-superuser两类凭据的正确使用场景,并能基于仓库源码理解其底层实现,在真实集群中直接落地可运行的连接配置。

应用接入的核心原则:通过 Operator 管理的服务而非直连实例

CloudNativePG 假定应用与其托管的 PostgreSQL 集群位于同一个 Kubernetes 集群内,并通过 Operator 为每个Cluster资源创建的标准 Kubernetes 网络服务(Service)来暴露数据库访问。官方文档明确建议:

强烈推荐在应用中使用这些服务,避免直接连接某个具体的 PostgreSQL 实例,因为实例(尤其主节点)在集群生命周期内会发生切换、滚动更新或故障恢复,直连实例将导致连接中断与应用不可用。

以 CloudNativePG 的集群pg-database为例,其 Pod 名称形如pg-database-1pg-database-2……如果应用硬编码连接pg-database-1,一旦该实例因故障被替换、或因提升/降级改变角色,应用将失去可用端点。而通过服务名连接,Kubernetes 会持续将流量转发到当前满足条件的实例上。

CloudNativePG 为集群创建的三类(四类)服务

从仓库中的服务实现源码可以确认,CloudNativePG 为每个集群默认创建以下服务(见 pkg/specs/services.go 中的CreateClusterReadWriteServiceCreateClusterReadOnlyServiceCreateClusterReadServiceCreateClusterAnyService四个构造函数):

服务名(以集群pg-database为例)作用底层 Selector 依据对应源码函数
pg-database-rw指向集群主实例(Primary),支持读写role=primary标签CreateClusterReadWriteService
pg-database-ro指向全部热备副本(Replica),只读role=replica标签CreateClusterReadOnlyService
pg-database-r指向集群内任意一个实例(含主实例),只读role=instance标签(含主与备)CreateClusterReadService
pg-database-any指向所有实例(包括未就绪的 Podrole=instance标签,且publishNotReadyAddresses: trueCreateClusterAnyService

服务命名遵循<CLUSTER_NAME>-<SERVICE_NAME>约定,该约定定义于 api/v1/cluster_types.go 的ServiceAnySuffix-any)、ServiceReadSuffix-r)、ServiceReadOnlySuffix-ro)、ServiceReadWriteSuffix-rw),并由 api/v1/cluster_funcs.go 中的GetServiceAnyNameGetServiceReadNameGetServiceReadOnlyNameGetServiceReadWriteName四个方法拼接生成。

其中rw服务在保证 PostgreSQL 复制上不可或缺,不能被禁用ror服务可通过managed.services.disabledDefaultServices选项关闭(详见下文"服务管理")。上述默认服务名均被 CloudNativePG 保留,用户自定义服务时不可占用。

这些服务默认均为ClusterIP类型,端口映射为postgres.ServerPort(5432),且-any服务设置了publishNotReadyAddresses: true,确保实例在尚未就绪时也能被解析到——这对需要等待所有实例建立联系的运维工具很有用,但对一般业务应用请使用rw/ro/r

服务在读写分离中的典型用法

  • 读写应用(ORM、业务主流程):连接pg-database-rw,始终打到主实例,保证写一致性。
  • 只读报表/分析查询:连接pg-database-ro,流量分散到各热备副本,减轻主实例负载;集群无副本时该服务不暴露端点。
  • 容忍读主节点(如既想负载均衡又不介意主实例参与只读):连接pg-database-r

服务发现方式一:Kubernetes DNS 解析(推荐)

Kubernetes 集群 DNS 是 CloudNativePG 正常运行所依赖的基础设施,也是最推荐的发现方式。应用可通过服务名直接解析到对应 Service 的 ClusterIP:

  • 同命名空间:直接使用服务名,例如pg-database-rwpg-database-ro
  • 跨命名空间:使用完整限定名(FQDN 短形式)service-name.namespace-name,例如pg-database-rw.apps

更进一步,Kubernetes 会为每个 Service 生成形如pg-database-rw.default.svc.cluster.local的完整 DNS 名(cluster.local为默认集群域)。CloudNativePG 在生成凭据时使用的正是此类 FQDN,细节见下文 Secrets 章节。

在 Deployment 中通过 DNS 使用服务的示例

apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: template: spec: containers: - name: app image: my-app:latest env: # 同命名空间,直接使用服务名 - name: PGHOST value: pg-database-rw - name: PGPORT value: "5432"

服务发现方式二:环境变量(同命名空间)

如果应用与 PostgreSQL 集群部署在同一个命名空间,Kubernetes 会自动为同命名空间内每个 Service 注入一组<SERVICE_NAME>相关的环境变量到应用 Pod 中。假设集群名为pg-database,应用 Pod 中可直接使用:

环境变量指向的服务说明
PG_DATABASE_R_SERVICE_HOSTpg-database-r指向集群全部 PostgreSQL 实例(含主实例)的只读服务 IP
PG_DATABASE_RO_SERVICE_HOSTpg-database-ro指向全部热备副本的只读服务 IP
PG_DATABASE_RW_SERVICE_HOSTpg-database-rw指向主实例的读写服务 IP

这些变量名由 Kubernetes 依据"服务名中的连字符替换为下划线 +_SERVICE_HOST后缀"的规则自动生成(pg-database-rwPG_DATABASE_RW_SERVICE_HOST)。应用启动时读取这些变量即可获得对应服务的 ClusterIP,无需硬编码地址。注意:环境变量方式仅在同命名空间生效,跨命名空间时请优先使用 DNS 解析。

凭据管理:Operator 自动生成的 basic-auth Secrets

对于每个部署的 PostgreSQL 集群,CloudNativePG 会生成最多两个kubernetes.io/basic-auth类型的 Secret,用于携带连接凭据(源码见 pkg/specs/secrets.go 的CreateSecret函数,Secret 类型为corev1.SecretTypeBasicAuth):

  1. <cluster-name>-app(如pg-database-app):应用连接使用的凭据,对应用户是数据库的属主(owner)。除非通过.spec.bootstrap.initdb.secret.name指定了已存在的 Secret,否则 Operator 一定会生成。
  2. <cluster-name>-superuser(如pg-database-superuser):仅用于管理目的的超级用户凭据,对应postgres用户。仅在.spec.enableSuperuserAccesstrue且未通过.spec.superuserSecret指定其他 Secret 时生成。

重要:默认情况下,通过网络禁用超级用户访问.spec.enableSuperuserAccess默认关闭)。应用应一律使用-app凭据,-superuser凭据仅限管理员在需要时启用。

Secret 的字段清单

每个生成的 Secret 都包含以下字段(对应 pkg/specs/secrets.go 中的StringData):

字段名内容说明
username/user数据库用户名两个字段值相同,兼容不同客户端读取习惯
password数据库密码
dbname数据库名称通常与集群名一致的默认数据库
host主机名指向rw服务的短主机名(不带端口)
port端口号postgres.ServerPort(5432)
pgpass.pgpass文件格式内容可直接写入~/.pgpass供 libpq 工具链使用
uriPostgreSQL 连接 URIpostgresql://user:pass@host:port/dbname形式,主机为短名
jdbc-uriJDBC 连接 URI供 Java/JVM 生态的 JDBC 驱动使用
fqdn-uri基于 FQDN 的 PostgreSQL URI主机为完整域名
fqdn-jdbc-uri基于 FQDN 的 JDBC URI主机为完整域名

其中uri/jdbc-uri使用命名空间限定的主机名(host.namespace:port),而fqdn-uri/fqdn-jdbc-uri使用完整域名(host.namespace.svc.<cluster-domain>:port)。

FQDN 与集群域配置

Secret 中 FQDN 形式 URI 所使用的主机名,依据 Kubernetes 集群域计算而来:<service>.<namespace>.svc.<kubernetes-cluster-domain>。集群域通过 Operator 配置参数KUBERNETES_CLUSTER_DOMAIN指定(环境变量同名),其默认值为cluster.local,定义于 internal/configuration/configuration.go 的DefaultKubernetesClusterDomain。非默认集群域(如k8s.example.com)的集群需调整该参数,否则fqdn-*系列连接串无法解析。更多细节见 Operator 配置文档。

在应用中挂载 Secret 的示例

apiVersion: apps/v1 kind: Deployment metadata: name: my-app spec: template: spec: containers: - name: app image: my-app:latest env: - name: DB_USER valueFrom: secretKeyRef: name: pg-database-app key: username - name: DB_PASSWORD valueFrom: secretKeyRef: name: pg-database-app key: password - name: DB_NAME valueFrom: secretKeyRef: name: pg-database-app key: dbname # 也可直接使用完整连接串 - name: DATABASE_URL valueFrom: secretKeyRef: name: pg-database-app key: uri

对于 Python(psycopg2/SQLAlchemy)、Go(pgx/lib/pq)、Node.js(pg)等支持 libpq 连接串的驱动,直接使用uri字段即可;Java 应用则使用jdbc-uri;需要走.pgpass的 CLI 工具链(psqlpg_dump等)可使用pgpass字段内容。

高级话题:服务管理、连接池与外部访问

通过managed.services自定义服务

CloudNativePG 在 服务管理文档 中提供了对服务的高级定制能力:

  • 禁用默认服务:通过managed.services.disabledDefaultServices可关闭ror服务;但rw服务因承载复制关键路径而不可禁用
  • 新增自定义服务:通过managed.services.additional段,以serviceTemplate定义任意 KubernetesService(如LoadBalancer类型对外暴露),通过selectorTyperw/ro/r)指定其选中的实例角色,updateStrategy控制更新策略(默认patch直接修改,replace则删除重建但会引发短暂中断)。

例如为数据库主实例创建一个对外LoadBalancer服务:

# <snip> managed: services: additional: - selectorType: rw serviceTemplate: metadata: name: "mydb-lb" labels: test-label: "true" annotations: test-annotation: "true" spec: type: LoadBalancer

上述能力的实现位于 pkg/specs/services.go 的BuildManagedServicesbuildDefaultService函数:Operator 依据selectorType构造对应的默认服务,再以用户的serviceTemplate覆盖元数据与 spec,并强制写入由 Operator 管理的 Selector 与端口。

连接池:PgBouncer 接入层

对于高并发应用,CloudNativePG 支持通过 PgBouncer 构建连接池,作为应用与 PostgreSQL 集群之间的访问层,以降低连接开销并提升吞吐。详细的部署与配置方法参见 Connection Pooling 章节。

将服务暴露到集群外的安全须知

CloudNativePG 服务默认是集群内可见的ClusterIP。如需对外暴露(如 DBaaS 场景、遗留虚拟机应用迁移),需自行创建LoadBalancerNodePort类型的服务。需要强调的是,将数据库暴露到公网会使其面临恶意攻击风险,请务必在对外暴露前完成数据库加固,或确保 Kubernetes 集群仅从私有网络可达。

小结:推荐的连接组合

综合上述内容,一个遵循 CloudNativePG 最佳实践的应用连接方案是:

  1. 发现方式:优先使用服务名进行 DNS 解析(同命名空间直接用<cluster>-rw,跨命名空间用<cluster>-rw.<namespace>),让 Kubernetes 负责实例切换时的流量重定向;
  2. 凭据来源:从<cluster>-appSecret 读取usernamepassworddbnamehost/port或现成的uri/jdbc-uri/pgpass字段,杜绝硬编码密码;
  3. 读写分离:按需在rwror三类服务中选择合适的端点;
  4. 高并发场景:引入 PgBouncer 连接池(连接池文档);
  5. 对外暴露:通过managed.services.additional自定义服务,并做好安全加固。

这样组合既保证了连接的稳定与高可用,也让应用代码天然适配主备切换、滚动升级等运维动作,充分发挥 CloudNativePG 的自动化能力。可进一步阅读 服务管理完整文档 与 Cluster CRD 参考 获取全部配置项。

【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询