CloudNativePG 服务管理详解:rw/ro/r 三型 Service 的禁用、自定义与集群外暴露 📅 发布时间:2026/9/16 17:13:59 👁 浏览次数: CloudNativePG 服务管理详解rw/ro/r 三型 Service 的禁用、自定义与集群外暴露【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pgCloudNativePG 为每个 PostgreSQLCluster自动生成一组标准的 Kubernetes Service用于在集群内以稳定、统一的方式访问数据库。本文以 docs/src/service_management.md 为核心完整讲解rw读写、ro只读、r读三类默认 Service 的约定与生成逻辑演示如何通过managed.services配置禁用不需要的默认服务、基于标准 KubernetesServiceAPI 定义自己的服务模板并深入分析patch/replace两种更新策略及 DBaaS 场景下将数据库安全暴露到集群外的注意事项同时结合仓库源码给出实现级佐证。为什么只能通过 Kubernetes Service 访问 PostgreSQLCloudNativePG 的架构原则是一个 PostgreSQL 集群只应通过由 CloudNativePG 直接管理的标准 Kubernetes 网络 Service 进行访问。这一约束保证了访问入口与 Pod 生命周期解耦Pod 重建、滚动升级、故障切换都不会破坏客户端连接地址主从切换时客户端无需修改连接串rwService 的端点会自动跟随新的主节点对外暴露端口、负载均衡、网络策略等能力全部由 Kubernetes 原生的 Service 模型提供。Kubernetes 官方文档的 Service 页面Virtual IPs and Service Proxies 一节对 Service 的虚拟 IP 与代理机制有详细说明CloudNativePG 正是建立在这一标准网络抽象之上。三种默认服务rw、ro、rCloudNativePG 为每个Cluster资源定义三类 Service语义清晰、职责单一Service 类型命名指向目标用途rwCLUSTER_NAME-rw集群主实例primary读写访问同时承载 PostgreSQL 复制流量roCLUSTER_NAME-ro副本实例replicas如有只读访问负载均衡到各副本rCLUSTER_NAME-r集群内任意 PostgreSQL 实例只读访问可命中主实例或任意副本默认情况下CloudNativePG 会为每个Cluster创建以上全部三种 Service遵循两条约定命名格式CLUSTER_NAME-SERVICE_NAME类型全部为ClusterIP。重要默认服务名CLUSTER_NAME-rw、CLUSTER_NAME-ro、CLUSTER_NAME-r是 CloudNativePG 的保留名称用户自定义服务时不得占用。从源码看默认 Service 的生成逻辑三类默认 Service 的构建集中在 pkg/specs/services.go 中每个构造函数都完整定义了标签、端口与 selectorCreateClusterReadWriteServicepkg/specs/services.go#L132-L157selector 使用ClusterInstanceRoleLabelName: ClusterRoleLabelPrimary即只选中当前主节点 Pod保证读写流量永远落在主实例上CreateClusterReadOnlyServicepkg/specs/services.go#L104-L129selector 使用ClusterInstanceRoleLabelName: ClusterRoleLabelReplica只选中副本 Pod用于只读流量的水平扩展CreateClusterReadServicepkg/specs/services.go#L76-L101与CreateClusterAnyServicepkg/specs/services.go#L47-L73selector 使用PodRoleLabelName: PodRoleInstance命中全部实例 Pod其中CreateClusterAnyService还设置了PublishNotReadyAddresses: true。三者统一通过buildInstanceServicePorts()pkg/specs/services.go#L35-L44暴露端口协议为 TCPPort与TargetPort均为 PostgreSQL 服务端口由postgres.ServerPort定义即 5432并自动附加cnpg.io/cluster、app.kubernetes.io/name、app.kubernetes.io/component: postgres等标准标签便于用户基于标签做网络策略或监控筛选。禁用默认服务disabledDefaultServices默认的三服务方案覆盖了绝大多数集群内访问场景但某些场景下你可能希望减少暴露面或避免多余的资源开销。CloudNativePG 允许通过managed.services.disabledDefaultServices选项禁用ro和/或r默认服务# snip managed: services: disabledDefaultServices: [ro, r]重要rw服务是不可禁用的因为 CloudNativePG 依赖它保证 PostgreSQL 主从复制replication正常工作。ro与r可以单独或同时禁用也可以都不禁用即保持默认行为。源码级验证禁用逻辑如何生效该选项在 api/v1/cluster_types.go#L2614-L2623 中定义为DisabledDefaultServices []ServiceSelectorType合法取值来自ServiceSelectorType枚举rw/r/ro见 api/v1/cluster_types.go#L2588-L2601。实际的启用判断实现在 api/v1/cluster_funcs.go#L1464-L1491 的IsReadWriteServiceEnabled、IsReadOnlyServiceEnabled、IsReadServiceEnabled三个方法中当Spec.Managed或Spec.Managed.Services为 nil 时默认返回true即不配置就等于全部启用否则用slices.Contains检查对应类型是否出现在禁用列表中。对应的单元测试位于 api/v1/cluster_funcs_test.go#L1499-L1576逐一验证了未配置时启用空禁用列表时启用列表包含ro/r/rw时对应服务禁用等分支同时 api/v1/cluster_funcs_test.go#L533-L541 验证了禁用ro与r后集群备用 DNS 名集合中不再包含对应服务名。添加自定义服务managed.services.additional当默认服务无法满足需求时CloudNativePG 允许通过managed.services.additional配置段定义一组自定义 Service且可以与禁用默认服务组合使用——你可以同时禁用默认ro/r并新增符合自身规范的只读服务。自定义服务需要三个字段selectorType服务要匹配的实例类型合法值为rw、r、ro决定 operator 为该服务生成何种 selectorupdateStrategy可选服务更新策略默认patchserviceTemplate标准 Kubernetes Service API 的模板可自由定义metadata与spec。重要自定义服务不能使用保留的默认服务名即CLUSTER_NAME-rw等且必须自行提供一个唯一的name并保证其在命名空间内不与其他 Service 冲突。注意不要在serviceTemplate中定义selector字段——selector 由 operator 根据selectorType自动管理。你在模板中配置的一切其他内容类型、端口、annotations、labels、externalTrafficPolicy 等都会被尊重。警告Service 模板在配置网络访问上给予了无限可能性也意味着更大的责任。除了遵循你指定的 selector 之外CloudNativePG 对 Service 配置没有控制能力最终服务是否按预期工作由你负责验证。完整示例为主实例创建一个 LoadBalancer 服务在 DBaaS 等需要从集群外访问数据库的场景下常见做法是为rw类型创建LoadBalancer类型的自定义服务# snip managed: services: additional: - selectorType: rw serviceTemplate: metadata: name: mydb-lb labels: test-label: true annotations: test-annotation: true spec: type: LoadBalancer上述示例同时演示了如何为创建出的 Service 附加 labels 与 annotations。selectorType: rw保证该 Service 的端点始终指向当前主实例type: LoadBalancer则由 Kubernetes 环境云厂商 LoadBalancer 或 MetalLB 等实现分配外部 IP/负载均衡器。从源码看自定义服务如何被构建自定义服务的构建入口是BuildManagedServicespkg/specs/services.go#L176-L227流程如下根据selectorType调用buildDefaultServicepkg/specs/services.go#L229-L240复用上文的三个默认服务构造函数以默认服务的 selector 和端口为基准通过servicespec.NewFrom以用户提供的serviceTemplate为起点追加cnpg.io/managed: true标签、cnpg.io/updateStrategy注解并用默认服务的 selector覆盖模板中的 selector端口采用用户优先策略WithServicePortNoOverwrite仅在模板中不存在同名或同端口的情况下才补入默认端口对应源码注释中的 issue #6389最后将默认服务的标准标签合并进模板并调用cluster.SetInheritedDataAndOwnership继承集群的继承数据与所有权owner reference。模板构建器Builder的具体实现见 pkg/servicespec/builder.go#L42-L120其中WithServiceType(serviceType, overwrite)的第二参数控制是否允许模板覆盖默认类型SetSelectors则强制写入由selectorType推导出的选择器——这印证了文档selector 由 operator 管理的约定。updateStrategypatch 与 replace 的选择updateStrategy字段控制 operator 在检测到服务定义与期望状态不一致时如何更新现有 Service合法取值为patch与replace枚举定义见 api/v1/cluster_types.go#L2603-L2612patch默认基于当前实际 Service 与期望状态的差异以 JSON Merge Patch 方式增量修改尽量不中断服务replace删除现有 Service 并依据模板重建。警告replace策略每次变更都会造成一次服务中断。它仅在需要修改只能在 Service 创建时设置的字段例如某些云厂商的LoadBalancerClass、特定IPFamilyPolicy组合等不可原地修改的参数时才有必要使用。源码级验证两种策略的落地点更新策略的读取与执行位于 internal/controller/cluster_create.go#L384-L412 的serviceReconciler它从 Service 注解cnpg.io/updateStrategyutils.UpdateStrategyAnnotation中读取策略缺省回退到patch若 Service 不存在且需要启用则调用servicespec.SetLastApplied写入期望 spec 的 JSON 快照后直接创建。patch路径的核心是 pkg/servicespec/reconcile.go#L48-L87 的ApplyProposedChanges利用LastAppliedSpecAnnotation中保存的上次应用 spec 与当前期望 spec 计算 RFC 7386 JSON Merge PatchbuildPatchJSON再合并到现存服务上实现三路合并合并后preservePortDefaults会恢复由 Kubernetes 自动分配/默认化的NodePort、Protocol、TargetPort等字段避免误覆盖平台侧赋值。replace路径则按文档语义删除并重建服务保证仅创建时可配置的字段能随模板生效。完整的差异合并逻辑与端口保护行为均有测试覆盖见 pkg/servicespec/reconcile_test.go。将 PostgreSQL 服务暴露到集群外默认的ClusterIP服务仅在集群内部可达。managed.services.additional配合type: LoadBalancer或NodePort、ExternalName等类型即可将数据库暴露到集群外。典型场景主要有三类临时暴露测试阶段临时对外开放验证通过后应立即关闭DBaaS 场景的永久暴露以数据库即服务的方式向用户提供连接入口遗留应用长期访问无法或不适合容器化的遗留应用驻留在 Kubernetes 之外的虚拟机或物理机上需要长期访问数据库——该场景与 DBaaS 高度类似。安全警告将数据库暴露到公网会使其面临恶意攻击者的潜在威胁。务必遵循以下原则在授予外部访问权限之前先加固数据库安全启用 TLS/SSL 连接参见 docs/src/ssl_connections.md、配置严格的认证与最小权限角色参见 docs/src/declarative_role_management.md或确保 Kubernetes 集群仅从私有网络可达结合 NetworkPolicy、云安全组、LoadBalancerSourceRanges白名单等手段限制来源网段对访问链路启用审计与监控参见 docs/src/monitoring.md及时发现异常流量。实践自检清单配置完服务管理后建议按以下清单核验默认服务名CLUSTER_NAME-rw/-ro/-r未被自定义服务占用未在serviceTemplate中填写selector字段自定义服务指定了唯一的name仅在必要时使用replace更新策略并知悉其会引发服务中断对外暴露前已确认数据库与网络层安全措施就位通过kubectl get svc与kubectl get endpoints验证 Service 的端点是否符合预期主实例/副本/全部实例。更多配置项字段说明可参考 API 参考文档 docs/src/cloudnative-pg.v1.md 中的ManagedService/ManagedServices章节完整 CRD 定义见 config/crd/bases/postgresql.cnpg.io_clusters.yaml可直接使用的集群样例见 docs/src/samples/cluster-example-full.yaml。【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考