CloudNativePG 集群 Kubernetes 升级与节点维护完全指南
【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg
本文以 CloudNativePG 的官方文档为骨架,系统讲解如何在不中断 PostgreSQL 业务的前提下完成 Kubernetes 集群的升级与节点维护:从维护窗口的规划、drain/uncordon的标准流程,到节点本地存储场景下集群的临时降级、PodDisruptionBudget(PDB)的管理策略,以及nodeMaintenanceWindow这一为本地存储而生的维护机制及其在新版本中的演进。读完本文,你将能够根据集群存储类型与实例拓扑,为生产、开发/测试集群分别制定正确的维护策略,并正确使用kubectl drain、enablePDB、nodeMaintenanceWindow.inProgress/reusePVC等关键开关完成一次安全的节点维护。
为什么必须重视 Kubernetes 的定期升级
保持 Kubernetes 集群处于最新状态,是保证性能与安全的基础要求,这一点对自管(self-managed)集群、尤其是运行在裸金属(bare metal)基础设施上的集群尤为关键。定期升级能够:
- 消除技术债:Kubernetes 控制面与节点组件的迭代非常快,长期停留在旧版本会积累大量配置、API 与依赖层面的历史包袱;
- 降低业务风险:安全补丁、硬件故障替换、控制面版本升级等维护操作,都是降低基础设施整体风险的必要投入。
需要正视的是,升级过程往往伴随着有计划的停机窗口——例如需要将某个节点临时移出集群进行维护。官方文档在介绍这一话题时引用了 Google SRE 经典书籍中的 "Embracing Risk" 章节,其核心思想是:运维不是消除所有风险,而是有意识地接受并管理可控风险。将风险量化为可接受的停机时间与数据风险,正是规划维护窗口的前提。
集群中的标准维护流程
Kubernetes 的节点维护通常每次只针对一个节点进行,遵循一套标准化的三步流程(详见 Kubernetes 官方 kubeadm 升级指南):
- 驱逐工作负载(
drain):使用kubectl drain <node>优雅地将目标节点上的工作负载迁移走,确保平滑过渡; - 执行维护操作:在节点上执行实际维护,例如应用系统更新、替换故障硬件、升级 kubelet 版本等;
- 让节点重新加入集群(
uncordon):维护完成后使用kubectl uncordon <node>将节点重新接入集群,恢复其调度职责。
这一流程的代价是:要么在整个升级期间停止工作负载,要么将工作负载迁移到集群中的其他节点。对于 PostgreSQL 这类有状态工作负载,后者是否可行,高度取决于存储类型——这正是 CloudNativePG 相关设计(PDB、维护窗口)的出发点。
节点本地存储下的临时降级:一种可接受的状态
标准流程依赖 Kubernetes 的自愈能力保证服务可靠性,但在某些场景下,允许 PostgreSQL 集群临时处于降级状态是完全可以接受的。这一论断特别适用于依赖节点本地存储(node-local storage,即 local storage)的 PostgreSQL 集群——数据存放在运行 PostgreSQL 的 Kubernetes 工作节点自身的磁盘上,以换取更高的 I/O 性能。
:::note 何时可以跳过本文其余章节? 如果你的数据库文件位于可通过网络访问的共享存储上,那么在drain之后,卷可以被不同节点上的 Pod 重新使用,此时 operator 的默认自愈行为已经能高效处理,可以跳过本文后续内容。本文剩余部分专门针对本地存储场景。 :::
Pod Disruption Budget:默认的守护机制
默认行为:为每个 Cluster 创建两个 PDB
默认情况下,CloudNativePG 会在后台守护 PostgreSQL 集群的可用性:
- 如果要被
drain的节点上运行着集群的primary实例,operator 会在drain之前先执行一次 switchover(切换),把该节点上的实例降级为 replica 后再继续驱逐; - 对于单实例集群,由于无法切换,CloudNativePG 会阻止驱逐该实例所在的节点;
- 对于3 个及以上实例的集群,CloudNativePG 保证在
drain过程中同一时刻最多只有一个 replica 被优雅关闭。
这一行为的实现机制是:每个 PostgreSQLCluster都会自动关联两个PodDisruptionBudget资源,你可以通过kubectl get pdb立即确认:
kubectl get pdb -n <namespace>从源码看,这两个 PDB 在 pkg/specs/poddisruptionbudget.go 中分别构建:
BuildPrimaryPodDisruptionBudget:保护 primary 实例,避免其被随意驱逐(对应上文"primary 所在节点先切换、单实例阻止驱逐"的行为);BuildReplicasPodDisruptionBudget:通过MinAvailable = instances - 2保证 n 实例集群中始终至少有 n-2 个 replica 可用,从而实现"一次只优雅关闭一个 replica";该函数在cluster.Spec.Instances < 3时返回nil(见 poddisruptionbudget.go)。
二者会在集群调和过程中被统一管理(见 cluster_create.go 的reconcilePodDisruptionBudget函数)。
生产建议:保持 PDB 开启
官方建议:对每个生产 PostgreSQL 集群都保持 Pod disruption budget 开启。这一开关由.spec.enablePDB字段控制,其语义定义在 cluster_types.go:默认值为true,此时 PDB 会保护 primary 节点不被终止;置为false时不会创建任何 PDB 资源(若之前已创建则会被删除),允许关闭所有承载 PostgreSQL 集群的节点——后者正是为开发/预发(staging)用途推荐的配置。
从实现上看,enablePDB的默认值逻辑在 cluster_funcs.go 的GetEnablePDB()中:当字段未设置(nil)时返回true,即默认开启。
开发/测试集群:禁用 PDB 以便顺利排空节点
对于开发用途的 PostgreSQL 集群(通常为单实例),必须禁用 pod disruption budgets——否则该集群所在节点将永远无法被drain。
下面的示例展示了如何为一个单实例的开发集群禁用 PDB:
apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: dev spec: instances: 1 enablePDB: false storage: size: 1Gi该配置可确保开发期间的维护流程不受限制,drain操作可以顺利进行。
Node Maintenance Window:面向本地存储的维护窗口
:::info 重要提示 CloudNativePG 会继续支持节点维护窗口机制,但目前官方建议改用上一节直接管理 pod disruption budgets 的方式。本节内容主要为向后兼容而保留。 :::
演进背景:1.23 之前的唯一声明式手段
在 release 1.23 之前,当处理本地存储场景时,CloudNativePG 只有一种声明式机制来管理 Kubernetes 升级:通过nodeMaintenanceWindow选项临时将集群置入维护模式,以避免标准的自愈流程介入——典型场景包括在物理节点上扩容分区、或者更新节点本身。
:::warning 谨慎使用 请将维护窗口的持续时间限制到最短。在该阶段,Kubernetes 的部分预期行为会被禁用或以受限方式运行,包括自愈(self-healing)、滚动更新(rolling updates)和 Pod disruption budget。 :::
两个子选项:inProgress与reusePVC
nodeMaintenanceWindow包含两个设置(字段定义见 cluster_types.go):
| 字段 | 类型 | 默认值 | 含义 |
|---|---|---|---|
inProgress | Boolean | false(文档原文记为off) | 是否处于节点维护窗口进行中。仅在为true时,operator 才会评估下面的reusePVC选项 |
reusePVC | Boolean | true(文档原文记为on) | 维护期间是否复用现有 PVC |
两者在 cluster_funcs.go 中都有对应的判定方法:
IsNodeMaintenanceWindowInProgress()(L844-L847):维护窗口是否激活;IsReusePVCEnabled()(L859-L866):默认reusePVC = true,仅当显式设置为false时才返回false。
reusePVC启用时(默认):Kubernetes 等待节点重新上线,然后复用现有 PVC;在此期间PodDisruptionBudget策略会被临时移除。
reusePVC禁用时:Kubernetes 强制在其他节点上以全新的 PVC 重新创建 Pod,借助 PostgreSQL 的物理流复制恢复数据,随后连同 Pod 一起销毁旧 PVC。这一场景通常不推荐,除非数据库体积很小,且重新克隆一个新的 PostgreSQL 实例比等待原节点恢复更快。需要注意:该行为不适用于单实例且reusePVC为false的集群(详见下文)。
维护窗口下 PDB 的临时移除逻辑
从 cluster_create.go 的调和逻辑可以确认:
- 当维护窗口进行中且
reusePVC开启时,replica 的 PDB 不会被强制执行; - 若此时集群为单实例,primary 的 PDB 也会一并移除——否则用户无法把工作负载从底层节点驱逐出去。
别忘了--delete-emptydir-data
:::note 执行kubectl drain时,需要附加--delete-emptydir-data选项。 不必担心:它指向的是 operator 内部使用的另一个卷,并非 PostgreSQL 数据目录。 :::
即正确用法为:
kubectl drain <node> --delete-emptydir-data --ignore-daemonsets用enablePDB完全接管 PDB 管理
:::info 重要提示 PodDisruptionBudget 的管理可以通过将.spec.enablePDB字段设为false来整体禁用。此时 operator 不再创建PodDisruptionBudget,并且会删除之前已创建的资源。 :::
这一行为由 cluster_create.go 中的deletePodDisruptionBudgetsIfExist路径保证:GetEnablePDB()返回false时直接进入删除逻辑。
单实例集群 +reusePVC: false:数据安全的红线
:::info 重要提示 官方建议始终创建多于一个实例的集群,以保证高可用(high availability)。 :::
在单实例集群中删除唯一一个 PostgreSQL 实例,意味着所有数据丢失。因此,即使处于维护模式,CloudNativePG 也会阻止用户 drain 这类实例所在的节点——这是 operator 主动守护数据安全的硬性边界。
不过,当确实需要对这类节点进行维护时,你有两个选择:
- 启用
reusePVC,接受停机时间; - 在其他节点上复制实例,并执行一次 primary 切换(switchover)。
方案一:接受停机
只要你的环境能够接受数据库服务的停机,操作就很简单:将nodeMaintenanceWindow设置为inProgress: true且reusePVC: true。这样实例会被删除,并在原始 PVC 可用时立即重建(例如节点本地存储场景下,节点一恢复即可复用 PVC)。对应的 YAML 示意如下:
apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: single-instance spec: instances: 1 nodeMaintenanceWindow: inProgress: true reusePVC: true storage: size: 20Gi方案二:无停机(仅切换耗时)
否则,你需要扩容集群:在其他节点创建新实例,将新实例提升为 primary,然后关闭正在维护节点上的原实例。此方案唯一的停机时间就是switchover 的耗时。推荐的操作步骤如下:
- **Cordon(封锁)**当前实例所在的节点:
kubectl cordon <node>; - 扩容集群到 2 个实例(耗时取决于数据库大小),例如编辑 Cluster 将
spec.instances从1改为2; - 新实例运行起来后,由于当前 primary 运行在已被 cordon 的节点上,operator 会自动执行 switchover;
- 缩容集群回到单实例,此时旧实例会被删除;
- 原 primary 所在节点现在可以成功 drain,而新 primary 已运行在新节点上。
整个过程把停机窗口压缩到一次切换的时间,是本地存储、单实例场景下的推荐路径。
总结:一张维护策略决策表
结合前文,可以为不同场景总结出如下决策要点:
| 集群类型 | 存储类型 | 推荐配置 | drain 可行性 |
|---|---|---|---|
| 生产集群(≥3 实例) | 网络共享存储 | 保持默认,enablePDB: true | 直接 drain,operator 自愈 |
| 生产集群(≥3 实例) | 节点本地存储 | 保持 PDB,逐节点 drain,必要时使用维护窗口 | 一次关闭一个 replica,primary 先切换 |
| 生产集群(单实例) | 节点本地存储 | 扩容→自动切换→缩容,或reusePVC: true接受停机 | 需先处理 primary,否则被阻止 |
| 开发/测试集群 | 任意 | enablePDB: false | 可直接 drain |
维护的最终目标,是在Kubernetes 自愈能力、PostgreSQL 高可用与可控的停机风险之间取得平衡。理解 PDB 的默认行为、enablePDB开关以及nodeMaintenanceWindow(含inProgress/reusePVC)的语义,是安全执行每一次节点升级的基础。更多字段细节可查阅 CloudNativePG API 参考 中关于ClusterSpec的说明,以及仓库中的类型定义 cluster_types.go 与控制器实现 cluster_create.go。
【免费下载链接】cloudnative-pgThe most popular Kubernetes Operator for PostgreSQL.项目地址: https://gitcode.com/GitHub_Trending/cl/cloudnative-pg
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考