Kubernetes 终于解决了其最大的问题:管理数据库

 互联网   2025-07-31 11:01   19 人阅读  0 条评论

Kubernetes 终于解决了其最大的问题:管理数据库  第1张

在 Kubernetes 上运行和管理像数据库这样的有状态工作负载一直是非常困难的。Kubernetes 的声明式模型非常适合管理 Pod 和 Secret 等可以被替换和交换的资源,但对于那些不能关闭且需要持续演进的资源(比如你最喜欢的 PostgreSQL 实例)来说,这种模型就不那么适用了。幸运的是,Kubernetes 生态系统中最近的一些发展终于让管理这类工作负载成为可能。

资源管理的核心在于维持系统的期望状态。对于现代的云原生应用程序来说,这种状态可能非常复杂。即使是小型团队也可能需要管理数千种不同的资源,包括虚拟私有云(VPC)、安全组、EC2 实例、Kubernetes 对象、负载均衡器、机密信息、数据库、CI/CD 流水线等。这已经不仅仅是“在某台服务器上运行应用程序”了。它需要协调一个庞大且相互依赖的组件生态系统,每个组件都有自己的生命周期、配置和约束条件。

这种复杂性的爆炸式增长对于许多人来说是个坏消息。它放大了配置漂移的风险,使可观测性和故障排查变得更加复杂,并且增加了跨环境状态不一致的机会。随着规模的扩大,团队在保持所有这些活动部件同步方面遇到了困难。

这些挑战催生了如今在云原生领域占据主导地位的新范式。令人惊讶的是,这些现代实践的核心灵感竟然来自一个不太可能的地方:你的空调。

为什么之前 Kubernetes 无法管理数据库

乍一听可能有点奇怪,但空调实际上为现代基础设施管理中一个强大的模式提供了一个很好的思维模型。

让我们来分析一下。空调不仅仅吹冷风——它维持一个期望状态:目标温度。为了做到这一点,它运行一个简单但有效的反馈循环:

  • 温度传感器持续感知当前温度。

  • 控制器将此与期望温度进行比较。

如果存在差异,它就会触发系统进行更多、更少或根本不进行冷却。

没有人会每隔几分钟就手动调整旋钮。该系统自主运行,响应环境的变化,并持续努力使其恢复到目标状态。

这就是所谓的协调循环(reconciliation loop)的本质——它是大规模管理复杂基础设施的最成功模型之一的基础。

一旦你理解了空调的隐喻,你就会在云基础设施中到处看到协调循环:

  • 自动扩展组:持续监控 CPU 或内存使用等指标,并根据目标利用率添加或删除实例。

  • 断路器:跟踪服务调用中的错误率,并在超过故障阈值时调整路由或拒绝请求,然后在条件稳定时恢复。

  • Kubernetes 控制器:监控已声明资源(如 Deployment 或 StatefulSet)的变化,并自动协调系统以确保一致性。

这种模式——定义期望状态、观察实际状态并协调差异——非常具有可扩展性。

我见过拥有数千个节点和数万个 Pod 的集群,它们运行着生产工作负载,所有这些都通过协调循环连接在一起。没有人会通过 SSH 登录到节点上重启失败的服务。没有人会运行临时脚本来重新平衡流量。系统会持续地观察、反应并自我修复。

这就是控制循环的魔力:它们不仅仅是自动化。它们是自主的。

它们为我们提供了能够响应故障、安全处理变化并且无需在每个步骤中进行持续监督的基础设施。

空调模型:协调循环如何改变了一切

但就像软件中的所有好事一样……有一个问题。

协调循环对于无状态基础设施非常有效。这也是 Kubernetes 在管理 Pod、服务和配置等资源时表现出色的原因。需要更新你的应用程序吗?只需更改镜像标签,Kubernetes 就会启动新的 Pod,等待它们变为健康状态,然后优雅地替换掉旧的 Pod。滚动更新、回滚、健康检查——所有这些都内置其中。它优雅、安全且无需人工干预。

然而,当将这种模型应用于有状态资源时,它开始失效。

行业资深人士,如 Kelsey Hightower,长期以来一直警告过这一点。在 Kubernetes 上运行有状态资源,尤其是像生产数据库这样关键的有状态资源,会带来一系列不同的问题。

让我们来看一个例子:假设你有一个运行 PostgreSQL 16 实例的 Pod,现在你想升级到 17 版本。

你会怎么做?

  • 关闭旧 Pod?这会导致停机。

  • 启动一个带有 17 镜像的新 Pod 并将其指向同一个 PVC?风险很大——数据格式可能已经发生了变化。

寄希望于最好的结果?这可能不是你的 SRE 团队会支持的策略。

如果你深入研究 PostgreSQL 的升级说明——或者在生产环境中进行过此类升级——你会发现一个安全的零停机升级通常涉及一个精心编排的序列。一个常见的策略大致如下:

  1. 在现有的 PostgreSQL 16 实例旁边配置一个新的 PostgreSQL 16 实例。

  2. 在新实例上预先创建一个兼容的模式。由于逻辑复制要求模式匹配,因此必须在复制开始之前完成这一步。

  3. 设置从旧实例到新实例的逻辑复制,实时捕获更改。

  4. 监控复制延迟并等待其降至零。

  5. 将流量切换到新实例——通常通过更新连接字符串或在故障转移设置中提升新节点来实现。

这个过程是有意为之且高度受控的。试图将这种升级强行塞入无状态滚动更新模型——就像用新镜像替换 Pod 一样——不仅幼稚,而且危险。

再举一个例子:模式迁移。

每次你的应用程序演变时,你的数据模型很可能也需要随之发展。也许你要添加一个列、更改一个类型或重构一个表。如果模式与新应用程序版本不兼容,某些查询可能会开始失败,导致运行时错误、功能中断甚至停机。

那么,如果我们尝试将相同的无状态滚动更新模型应用于数据库模式更改会怎样呢?

让我们来想象一下:你修改了你的应用程序,现在你想要“推出”一个新的模式版本。你可能会像处理 Deployment 一样,启动一个带有更新模式的新数据库 Pod,等待它变为健康状态,然后切换流量并删除旧的 Pod。

但数据库不是无状态 Pod。

一个带有“正确”模式的新数据库可能看起来是健康的,直到你意识到它是空的,因为没有数据被迁移。

尝试直接将新模式应用于现有数据库?这通常会直接失败——也许表已经存在,或者列冲突阻止了更改的进行。即使它成功了,它也可能会默默地破坏东西:也许一个列被删除了或者一个约束被添加了,现在你的应用程序在真实流量下开始抛出运行时错误。

与无状态工作负载不同,你不能简单地重试一个失败的部署。数据库持有持久且不可逆的状态。模式迁移通常是不可幂等的,一个设计不当的迁移可能会使你的系统崩溃——或者更糟,它会在没有立即显示症状的情况下破坏数据。

更糟糕的是,传统的 Kubernetes 模式——比如在 init 容器中运行迁移或将它们打包到应用程序启动中——会引入竞争条件,创建脆弱的部署,并且很难观察、验证或回滚发生了什么。

即使做得很好,这些方法也依赖于预先脚本化的、线性的 DDL 语句序列——这是一个单向更改的固定计划。这与协调循环根本不同。这里没有感知、没有差异比较、没有对当前状态的反应。它是命令式的,而不是声明式的。

显然,我们需要一个不同的模型。

Kubernetes Operator:数据库管理的改变者

如果协调循环对于无状态基础设施如此有效,那么问题来了:我们能否将相同的想法扩展到有状态资源?

这正是 Kubernetes Operator 模式所要实现的。

Operator 是为管理复杂、特定领域、有状态资源(如数据库、消息代理或存储系统)而量身定制的控制器。它们将操作知识编码到软件中,使它们能够安装、配置、升级和监控这些系统,同时维持期望状态。

换句话说,它们将协调带入了有状态世界。

每个 Operator 的核心

Operator 模式的核心是两个 Kubernetes 原语:

  • 自定义资源定义(CRDs):这些扩展了 Kubernetes API,增加了新的资源类型。就像 Deployment 或 Service 一样,你可以定义一个 PostgresCluster、KafkaTopic,或者在我们的情况下,一个 DatabaseSchema。CRDs 让你可以描述 Kubernetes 本身并不理解的某种资源的期望状态。

  • 控制器:这些是监控自定义资源并采取行动的代理。它们监控系统的实际状态,将其与 CRD 中定义的期望状态进行比较,并执行必要的操作以使两者保持一致。

CRDs 和控制器共同为以前需要人工干预或脆弱脚本的任务形成了一个自我修复循环。

就像 Deployment 控制器协调 Pod 一样,一个 Operator 可以协调 PostgreSQL 集群、Kafka 主题甚至数据库模式的状态。

与 shell 脚本或 CI 作业不同,Operator 可以做出决策。它们不仅仅是执行——它们会观察、计划并根据环境做出反应。

CloudNativePG 和 Atlas:生产就绪的数据库解决方案

现在我们理解了 Operator 模式的力量,让我们来看看如何将其应用于一个真实世界的用例:在 Kubernetes 上以声明式、安全且零脚本的方式管理 PostgreSQL 模式更改。

我们将使用两个强大的 Kubernetes 原生工具:

  • CloudNativePG(CNPG):这是一个用于在 Kubernetes 上运行 PostgreSQL 集群的生产级 Operator。它负责配置、复制、故障转移甚至备份。

  • Atlas Operator:这是 Ariga 提供的一个模式管理 Operator,它引入了一个 AtlasSchema CRD,允许你声明期望的模式,并以安全、符合策略的方式自动应用更改。

通过这些工具,你可以以 GitOps 原生的方式管理你的数据库基础设施和模式生命周期。

让我们逐步了解设置过程。

逐步实施:在 Kubernetes 上实现声明式模式管理

步骤 0:安装 CloudNativePG 并创建集群

首先,安装 CloudNativePG Operator 并启动一个 PostgreSQL 集群。

添加 Helm 仓库并安装 Operator:



helm repo add cnpg  
helm repo update
helm install cnpg cnpg/cloudnative-pg
接下来,定义你的集群。将以下内容保存为 cluster.yaml


apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
  name: cluster-example
spec:
  instances: 1
  imageName: ghcr.io/cloudnative-pg/postgresql:15
  storage:
    storageClass: standard
    size: 1Gi
应用它:


kubectl apply -f cluster.yaml


这将:

  • 创建一个名为 app 的 PostgreSQL 数据库。

  • 配置一个名为 app 的用户。

  • 生成一个名为 cluster-example-app 的 Kubernetes Secret,其中包含凭据。

  • 在 cluster-example-rw.default 处暴露一个读写服务。

一旦 Pod(例如 cluster-example-1)启动并运行,你就可以继续下一步了。

步骤 1:安装 Atlas Operator

通过 Helm 安装 Atlas Operator:



helm install atlas-operator oci://ghcr.io/ariga/charts/atlas-operator
你应该现在可以在你的集群中看到 Atlas CRD 注册了:


kubectl get crd | grep atlas
输出:


atlasmigrations.db.atlasgo.io
atlasschemas.db.atlasgo.io


步骤 2:应用模式

使用 AtlasSchema 资源以声明式方式定义你的数据库模式。将以下内容保存为 atlas-schema.yaml




apiVersion: db.atlasgo.io/v1alpha1kind: AtlasSchemametadata:  name: atlasschema-pgspec:  credentials:    scheme: postgres    host: cluster-example-rw.default    user: app    passwordFrom:      secretKeyRef:        key: password        name: cluster-example-app    database: app    port: 5432  parameters:    sslmode: disable  schema:    sql: |      create table t1 (        id int      );
应用它:


kubectl apply -f atlas-schema.yaml


检查协调状态:



kubectl get atlasschemas.db.atlasgo.io


预期输出:



NAME                READY   REASONatlasschema-pg      True    Applied


步骤 3:验证并演化

你可以直接验证结果:



kubectl exec -ti cluster-example-1 -- psql app


在 psql shell 中:

要演化你的模式,只需编辑你的清单中的 sql: 字段——例如,添加一个列:



create table t1 (  id int,  name text);


然后重新应用:



kubectl apply -f atlas-schema.yaml


Atlas Operator 会检测到差异并安全地应用迁移。

这为你提供了完整的声明式模式管理,具有以下特点:

  • 通过 Kubernetes Secret 内置访问数据库凭据。

  • 模式协调由 Operator 持续处理。

  • 不需要命令式的迁移脚本或手动步骤。

这是一种真正以 GitOps 为原生的模式变更管理方法。

关键要点

  • 协调循环是云原生基础设施的支柱。它们对于无状态资源非常有效——并且借助 Operator 模式,它们也可以适用于有状态资源。

  • 传统的管理有状态系统(如数据库)的方法在 Kubernetes 中会失效。像 init 容器、CI 作业和手动脚本这样的工具并不符合我们所期望的声明式、自主模型。

  • Operator 将 Kubernetes 的强大功能带到了有状态系统。借助 CRDs 和控制器,你可以像管理 Deployment 和 Service 一样管理复杂的资源——比如 PostgreSQL 集群和模式。

  • Atlas 和 CloudNativePG 使得端到端的、以 GitOps 为友好的数据库管理成为可能。从配置到迁移,你现在可以通过完全的 Kubernetes 原生工作流来表达和演化你的数据库基础设施和模式。

为什么这很重要

随着 Kubernetes 成为一切的控制平面,状态不能成为例外。

长期以来,数据库一直被视为不可触碰的“雪花”——与我们的其他基础设施自动化隔离。然而,要实现真正现代的、可扩展的、可重复的系统,我们必须将它们整合到我们用于其他一切的相同工作流中。

Operator 模式——以及像 Atlas 这样的工具——有助于实现这一愿景。

是时候让所有(有状态的)事物都成为 Operator 了。

-END-



原文链接:https://thenewstack.io/kubernetes-finally-solves-its-biggest-problem-managing-databases/




本文地址:https://www.dockerworld.cn/?id=425
温馨提示:文章内容系作者个人观点,不代表Docker中文对观点赞同或支持。
版权声明:本文为转载文章,来源于 互联网 ,版权归原作者所有,欢迎分享本文,转载请保留出处!

 发表评论


表情

还没有留言,还不快点抢沙发?