← LeisureLinux 文章索引
LeisureLinux · 微信公众号文章

【译】Kubernetes 之美,止于有状态负载(Stateful Workloads)

AI/Agent 阅读原文(微信)↗

作者:Akhilesh Mishra (@livingdevops)

你的 Leader 刚刚要求你在 Kubernetes (K8s) 上运行 Postgres 数据库。

起初,这听起来完全合情合理。你的应用程序已经运行在 K8s 上,部署已经自动化,团队也习惯了使用 kubectl (Kubernetes Control)。在同一个环境中运行数据库似乎是顺理成章的下一步。

但正是从这里开始,Kubernetes 变得复杂起来。

1. 临时存储(Ephemeral Storage)的陷阱

你将 Postgres 作为 Deployment(部署)运行。 设置三个副本(Replicas),执行 Apply,Postgres 启动了。你连接数据库,插入了几行数据,一切表现如预期。接着,Pod 崩溃并重启。当你重新连接时,发现数据全丢了。

容器的文件系统是临时的(Ephemeral)。它仅在 Pod 的生命周期内存在,当 Pod 死亡时,文件系统也随之销毁。每次重启都丢失数据库不是极端情况,而是其默认行为。

解决方案: 引入 PersistentVolume (PV,持久化卷)。 PV 是独立于 Pod 存在的存储。它可以是 EBS (Elastic Block Store) 卷、云硬盘或 NFS (Network File System) 共享。当 Pod 崩溃且新 Pod 启动时,它会重新挂载到同一个卷上,数据得以保留。

2. 管理规模的挑战

手动配置存储无法扩展。 每当有人需要存储时,都必须手动创建 PV。无论是 AWS 里的 EBS 还是其他存储,总需要人工干预。如果你有一个 DevOps 工程师、四个环境和六个服务,这很快就会变成一个以"Slack 账号"为瓶颈的流程。

解决方案: 转向 PersistentVolumeClaim (PVC,持久化卷声明)StorageClass (SC,存储类)。 开发者现在只需声明他们的需求(例如:10GB,ReadWriteOnce/单节点读写访问),Kubernetes 就会通过 StorageClass 自动配置实际的卷。基础设施层实现了自服务化(Self-service)。无需工单,无需等待,无需操作 AWS 控制台。

3. Deployment 的局限性

存储持久化了,但数据库依然是破碎的。 你将一个 PVC 挂载到具有三个副本的 Postgres Deployment 上,期望实现高可用。结果你得到了数据损坏(Corruption)。三个 Pod 试图同时写入同一个磁盘,没有协调机制,没有角色感知,也没有顺序性。它们冲突、损坏,数据库崩溃。

问题不在于存储,而在于 Deployment 本身。Deployment 将每个 Pod 视为完全相同且可互换的。它们可以以任何顺序启动或关闭。但 Postgres 不支持这种模式:Pod 0 是 Primary(主节点)负责写入,Pod 1 和 Pod 2 是 Replicas(副本节点)负责读取并跟随主节点。它们有严格的启动顺序和不同的角色。如果 Pod 0 崩溃并以随机名称重启,Postgres 将无法识别谁才是主节点。

解决方案: 使用 StatefulSet (STS,有状态副本集) 替代 Deployment。 StatefulSet 为每个 Pod 提供稳定的永久标识。Pod 0 永远是 Pod 0。它最先启动,最后关闭。当它重启时,会带着相同的名称、角色和网络标识回归。

StatefulSet 还使用 volumeClaimTemplates (卷声明模板)。你只需定义一次模板,它就会为每个 Pod 自动创建独立的卷。Pod 0 拥有自己的磁盘,Pod 1 和 Pod 2 亦然。没有共享,没有冲突,没有损坏。

4. 环境漂移(Environment Drift)

数据库稳定了,但你现在面临多个环境。 开发(Dev)、测试(Staging)和生产(Production)环境各需要不同的配置:不同的副本数、存储大小和资源限制。于是你复制了 YAML 文件,修改数值并应用。

随着时间推移,这些文件会产生偏差(Diverge)。有人更新了生产环境的 StatefulSet 却忘了测试环境。开发环境的变更从未同步。微小的差异不断累积,直到调试变成"盲猜",测试环境不再是生产环境的可靠镜像。

解决方案: 引入 Helm (Kubernetes 包管理器)。 你只需编写一次 YAML 模板,将环境间变化的值设为变量(Variables)。每个环境拥有独立的数值文件(如 values-prod.yaml),但底层模板保持一致。Helm 将模板与数值合并生成最终的 YAML,确保了单一真理源(Single Source of Truth)。当升级出错时,一条命令即可回滚。

5. 安全与资源争夺

团队在壮大,新问题出现了。 多个团队部署各自的服务,且每个人都有集群访问权限。如果没有严格的界限,错误不可避免:一个团队读取了另一个团队的 Secrets (机密信息);一个写得烂的查询耗尽了节点的所有 CPU,导致旁边的所有工作负载"饿死"。没人设置限制,也没人划分权限。

解决方案: 实施 RBAC (Role-Based Access Control,基于角色的访问控制)。 访问权限现在被限定在角色和 Namespace (命名空间) 中。支付团队只能操作支付命名空间,订单团队操作订单。双方无法触碰对方的资源,消除了意外干扰。

以及: 引入 ResourceQuotas (资源配额)LimitRanges (限制范围)。 ResourceQuota 为每个命名空间设定了"硬上限"(例如:最高 8 核 CPU,16GB 内存)。LimitRange 设置了默认值,未声明限制的 Pod 会自动获取。从此,没有任何单个工作负载能垄断整个集群。

总结:Kubernetes 的进化逻辑

  • 临时存储导致重启丢数据 -> PersistentVolume 解决了它。

  • 手动配置存储无法扩展 -> PVCStorageClass 解决了它。

  • Deployments 损坏了有状态负载 -> StatefulSet 解决了它。

  • 重复的 YAML 导致环境漂移 -> Helm 解决了它。

  • 无限制的访问带来安全风险 -> RBAC 解决了它。

  • 无约束的命名空间耗尽资源 -> QuotasLimitRanges 解决了它。

Kubernetes 并非特性的堆砌,而是一系列你在生产环境中必然会遇到的问题的解决方案。

提示: 如果你想在真实的 EKS (Elastic Kubernetes Service) 集群上实践这些内容,可以关注我的 bootcamp 课程。

原版电子书免费下载:Ansible for DevOps & Kubenetes

AI 时代的"容器化时刻":CNCF 祭出大招,要终结 AI 基础设施乱象!

【技术白皮书】基于 Podman + Kata Containers 构建免费商用 AI 代理安全沙箱

本文整理自微信公众号 LeisureLinux 的原创内容(Linux / AI / 安全 硬核技术)。

· 阅读原文(微信公众号)

· 关注公众号 LeisureLinux,第一时间获取技术深度内容。

LeisureLinux 公众号二维码(微信扫一扫关注)