Skip to main content

Command Palette

Search for a command to run...

Zalando 是如何管理 140 多个 Kubernetes 集群的

Updated
3 min read

原文:HOW ZALANDO MANAGES 140+ KUBERNETES CLUSTERS

作者:Henning Jacobs

最近我接到一个问题:“你是如何管理这么多 Kubernetes 的?”。本文试图揭示 Zalando 在 AWS 管理 140 多个 Kubernetes 集群的秘密。

我写过一篇文章:为什么需要多集群Mikkel 在 KubeCon EU 2018 上做了关于如何在 Kubernetes 基础设施上进行持续交付的精彩分享。这里基本是对现存信息的一个梳理。

背景

Zalando 有 200 多个开发团队,他们全权负责自己的应用,其中也包括 7*24 待命的支持工作。我们的 Kubernetes 平台团队为 1000 多个 Zalando 开发者提供 Kubernetes 即服务的支持工作,工作过程中我们遵循如下准则:

  • 杜绝手工操作:所有集群更新和运维都要全自动。

  • 没有宠物集群:集群应该整齐划一,无需任何额外的配置和微调。

  • 韧性:为交付团队提供稳固的基础设施,保障其关键应用的运行环境。

  • 自动伸缩:集群应该自动适应应用负载的规模,根据需求进行伸缩。

架构

我们的集群是成对供应的,例如给每个域或者“产品社区”提供一个生产、一个非生产环境。

每个集群都是属于一个全新的、隔离的 AWS 账号。我们使用一个自定义的 Python 工具(Seven Seconds)对 AWS 基础设施进行配置,对 Kubernetes 和非 Kubernetes 账号一视同仁(即将下线的 STUPS 基础设施)。

我们整个生产环境的配置都保存在 Github 上。集群使用 CloudFormation(CF)模板。每个集群至少有四个 CF 栈:

可以有多种工作节点池,例如 GPU 节点、EC2 Spot 实例等。

注意:我们没有使用 Terraform(从来没有)。

主节点和工作节点都运行在我们的自定义 AMI 上。这个 AMI 是从 Ubuntu 基础上构建出来的,并且包含了 Kubernetes 所需的所有 Docker 镜像。从前我们用过 ContainerLinux,后来还是决定采用更主流的发行版,以保证持续性。这个预制的 AMI 还帮我们减少了启动时间(集群伸缩更快)。

配置

所有的集群以及 AWS 账号,都注册在一个中央集群仓库中。集群仓库使用 PostgreSQL 为数据库,提供了一组 REST API。可以在 Github 上浏览这个 OpenAPI 的规范。每个集群都有如下属性:

  • 只读的集群 ID,例如 "aws:123123123123:us-east-1:kube-9"

  • 集群别名:例如 “foobarlab”

  • 所在的 AWS 账号(账号 ID 和 Region)

  • 环境(生产还是测试)

  • 配置成熟度(稳定、Beta、Alpha 或者 dev)

  • 生命周期(已供给、已分配或者已销毁)

  • 集群特定的键值对信息,例如外部 API Key 等。

  • 已配置好的节点池(也就是 EC2 实例类型)和针对节点池的键值对配置

我们的工具集(kube-resource-reportkube-web-view)能够查询集群仓库的 REST API,列出所有集群,比如 zkubectl 命令行工具能够列出集群:

$ zkubectl list
Id                                           │Alias                           │Environment│Channel│Version
aws:123740508747:eu-central-1:kube-1          foobarlab                        production  stable  5f4316c
aws:456818767898:eu-central-1:kube-1          foobarlab-test                   test        beta    9f1b369
aws:789484029646:eu-central-1:kube-1          abckub                           production  stable  5f4316c
aws:012345670034:eu-central-1:kube-1          abckub-test
...

你会看到两对集群(foobarlababckub),生产集群使用的是 stable,非生产集群则使用 beta 配置。Version 列显示的是当前集群配置的 git sha。

Kubernetes Web View 对类似的集群进行渲染:

还可以参考我的另一篇文章:缺乏多集群支撑案例的 Kubernetes Web UI

更新

集群生命周期管理器持续的对集群仓库以及 Git 仓库的变更进行监控。CLM 会在如下时机进行变更:

  • CloudFormation 更新

  • 节点必须进行滚动更新(例如 AMI 发生变化)

  • Kubernetes 自身发生了变更(多数时候的表现是 kube-system 中的 DaemonSet 和 Deployment 的变更)

通过对 dev 分支发起 PR 的方式来初始化一个更新动作(例如更新一些系统组件)。每个变更的 PR 都会自动的进行端到端测试。 只有通过测试并且由人手工批准的 PR 才能够合并。端到端测试过程会针对新建的集群运行官方的 Kubernetes 一致性验证,以及 Zalando 自己的测试案例。这个测试的范围包括:

  • 集群的创建和更新(端到端测试会用前一个版本创建一个新的集群,并用 PR 内容进行更新)

  • Kubernetes 的核心功能:Deployment、StatefulSet 等

  • Zalando 的准入控制器逻辑

  • 审计日志

  • Ingress、外部 DNS、AWS ALB 以及 Skipper

  • PodSecurityPolicy

  • 使用自定义指标进行自动伸缩

  • 测试 AWS IAM 集成

每个 e2e 测试目前需要 35-59 分钟。测试成功的 PR,只需要一个 +1,就能进行合并:

每个变更都会在不同的分支中迁移,一直到进入稳定分支。

在滚动更新集群节点以及集群的自动伸缩过程中,我们的基础设施必须对正在预备下线的服务器上运行的 Pod 进行驱逐。可以使用 Pod Disruption Budgets 的声明,来保障平稳的更新过程。我们为更新或类似行为定义了下面的 SLA:

SLA生产集群测试集群
更新期间强制终结的 Pod 的最小生存期3 天8 小时
在选定节点之后,需要等待多久才开始强行终结 Pod6 小时2 小时
同一个节点上强行终结 Pod 的时间间隔5 分钟5 分钟
同一个 PDB 中将被终止的就绪 Pod 的最小生存期1 小时1 小时
同一个 PDB 中将被终止的未就绪 Pod 的最小生存期6 小时6 小时

因此应用 Pod 会在 3 天之后被强行终止——即使定义了 PDB 的情况。这种行为模式让我们在部分应用配置失常的情况下也能持续更新。

注意:我们的用户(开发团队)可以在任何时间阻止集群更新(例如发现了问题)。

请参见 Miokkel 的 KubeCon 演讲

避免配置发散

所有的集群看起来都差不多,只有少量配置项目有些不同:

  • Secret:例如外部日志服务的凭据

  • 节点池以及其中的实例规格

Cluster Autoscaler 能根据资源需要对集群的节点池进行伸缩,无需手工配置节点池的大小。下图是我们一个集群在两天之内的伸缩情况:

有些组件需要根据集群大小进行纵向伸缩。我们使用 Vertical Pod Autoscaler(VPA)来避免对这些值进行手工调节。目前有如下系统组件在使用 VPA:

我们最小的 Prometheus 实例仅仅使用 512 MB,也有使用 9GB 的大户,例如下图:

监控

我们主要的监控系统是 ZMON,ZMON 中有个实体的概念,表达的是你要监控的对象——例如服务器、Pod 甚至是团队。

创建一个新的集群会自动注册新的实体(例如新的 AWS 账号、节点、Deployment、Pod 等)。从而为新的实体启用一些常用检查和告警。

ZMON 提供了指标、告警以及仪表盘。

我们的 Kubernetes 团队不会在 Pod 重启时候收到警告。开发团队负责应用的整个生命周期。

我们还使用 OpenTracing(LightStep)获得跨集群的可观察性,中心化应用日志(Scalyr)、kube-resource-reportkube-web-view)。

魔改 Kubernetes

我们的配置是否对 Kubernetes 进行了大量魔改呢?答案是:不很多:

非生产集群提供的是类似 GKE 或者 Digital Ocean 集群类似的普通集群的功能。生产集群有些容器:

  • 只能通过 CICD 进行 Kubernetes API 的操作

  • 用 Webhook 执行强制的合规措施,例如使用某些标签,或者允许用于生产的镜像

总结

我们的这种做法再过去几年中工作良好,让我们在无需扩张团队的情况下得到了成长:

  • 我们能够无缝的把我们一个老的 Kubernetes 1.4 在无停服的情况下,升级到 1.14

  • 我们能够跟进 Kubernetes 的季度发布,也就是说我们在每个季度都可以进行升级

  • 频繁的集群更新让大家开始接受一个观点:小的中断是正常的(目前的 Pod 最长寿 20 多天)

  • 我们尝试避免出现宠物集群:集群看起来差不多,VPA 协助我们避免人工调节

  • 我们的自动端到端测试救了我们不止一次(例如 最近 1.14.7 的 Issue(https://twitter.com/try_except_/status/1181602709155323905))

要进一步了解这方面的信息,可以看看 Zalando 的公开仓库,还可以在 Twitter 上找到我们的一些团队成员:

也欢迎和 ZalandoTech、和打个招呼。

More from this blog

龙虾恐慌:AIOps 又要改名了?

ChatGPT 开始,把 AI 拉近到普罗大众的面前,让无数人感受到 AI 的亲民魅力。而龙虾,则把大模型驱动的自动化能力,突然间变得水灵灵、活泼泼地走进千家万户。它不只是“风口上的猪”,而是风口本身。热度高到让 Mac mini 一度断货,不知道这在不在库克的预料之内。 每代人都有每代人的鸡蛋,春节期间,我就领了我的鸡蛋。翻出古老的 MacBook Air M1,充值各种大模型。当然了,这个工具

Mar 9, 20261 min read

再见 2025

我猜不少人以为这个号废了吧?并没有,只是今年变化有点大,一直有种抄起键盘,无从说起的感觉,所以一直偷懒到今天,2025 的最后一天。 今年是我的第四个本命年,去年末一期播客里,大内说本命年不是灾年,是变化年,有危也有机。可是讲真啊,只看到危,没看到机。 各种因缘际会,从鹅厂跳槽到前东家,已经接近四年,第一个合同期已经进入尾声。除了前两年还在云原生领域嗷嗷叫,后两年基本都是些鸡零狗碎的东西了,用老东家的术语说是——偏离主航道,可谓是前景暗淡了。 一旦确定要滚蛋,反倒心思轻松起来,每天骑着我的小红车...

Jan 5, 20261 min read

辅助编程?dora 说:我知道你很急可是请你别急

从 OpenGPT 把大模型的火烧旺了之后,这三年来,相信很多组织或摩拳擦掌、或躬身入局,希望借助聪明能干的大模型,或想偿还技术宅,或想降本增效,或想弯道超车。一时间,沉寂许久的 AIxx 又活过来了,LLM Ops、Vibe Coding、中医大模型、GPT 算命等等,全都老树发新芽,焕发了勃勃生机。那么视角拉回从业者最关注的饭碗相关的领域之一——AI 辅助开发,产生了什么触动,应该如何拥抱呢? DORA 的年度报告中给出了很有意思的结论——强者恒强。 执行摘要部分总结了几个有趣的点: 问题...

Oct 6, 20251 min read

[译]dora:ai 辅助软件开发状态报告

执行摘要 在 2025 年,科技领导者面临的核心问题已不再是“是否要采用 AI”,而是“如何实现其价值”。 DORA 的研究基于超过 100 小时的定性访谈和来自全球近 5,000 名技术专业人士的问卷调查。研究揭示了一个关键事实:AI 在软件开发中的主要角色是“放大器”。它会放大高效能组织的优势,也会凸显组织的缺陷。 关键结论:AI 是放大器 AI 投资的最大回报并非来自工具本身,而是来自组织底层系统的战略性建设: 高质量的内部平台 清晰的工作流 团队的协同能力 缺少这些基础,AI ...

Oct 2, 202514 min read

僭越了,有人在用 Rust 写 Kubernetes

一个新语言问世,最爱做的事情之一,就是重写存量软件了。 云原生喝酒 SIG 重点扶持项目——rk8s(https://github.com/rk8s-dev/rk8s) 也可以归在这个范畴里,只不过这个项目重写的东西比较大,是 Kubernetes。 从 2025 年 1 月第一个 Commit 开始,到现在有了 200 多次 Commit,十几万行代码。当然距离 Kubernetes 的几百万行代码还差得远——老马就是喜欢整这种大无畏项目。 另外该项目也是国内第一个脱离 Cargo 转向使用 ...

Sep 27, 20253 min read

【伪】架构师

342 posts