Kubernetes首批用户的8年拓荒史:经历两次重大集群崩溃,却从未考虑替代品

Anders Jönsson 2024-03-04 10:43:11

图片

 

早在我加入 Urb-it 这家公司前,他们就决定使用 Kubernetes 作为云原生战略的基石。这一选择背后有两方面考虑:一是使用 Kubernetes 应对快速扩展的预期,二是利用它的容器编排功能为应用程序提供更动态、弹性和高效的环境。同时,Kubernetes 与我们的微服务架构非常契合。

 

早期决策

 

公司很早就决定选择 Kubernetes,这一选择受到质疑是合理的,因为初创公司(或任何公司)就要(对这一工具)产生深层依赖,同时需要学习大量相关的技术知识。除此之外,我们当时遇到过 Kubernetes 才能解决的问题吗?

 

也许有人会说,我们可以在最初使用一个相当大的单体,直到扩展及其他问题越发凸显,才转向 Kubernetes(或其他工具)。并且,Kubernetes 当时仍处于早期开发阶段。不过,我们下次再深入讨论这个问题吧。

 

8 年生产经验

 

我们在生产环境中运行 Kubernetes 已超过 8 年(每个环境都有单独的集群),在此期间做过的决策有好有坏。有些错误仅是因为“运气不好”,而有些错误则是因为我们部分(甚至可以说完全)没能理解底层技术。Kubernetes 功能强大,但也具有复杂性。

 

在没有任何大规模运行 Kubernetes 经验的情况下,我们只能迎难而上。

 

从 AWS 上的自托管迁移到 Azure 上的托管(AKS)

 

最初几年,我们在 AWS 上运行一个自管理集群。如果我没记错的话,我们最初没有选择使用 Azure Kubernetes Service(AKS)、Google Kubernetes Engine (GKE)、Amazon Elastic Kubernetes Service(EKS),是因为当时他们尚未提供官方的托管解决方案。正是在Amazon Web Services (AWS)自托管平台上,我们遭遇了 Urb-it 历史上第一次也是最可怕的一次集群崩溃,稍后再详述。

 

由于我们是小规模团队,所以完全掌握所需的所有新功能极具挑战性。同时,管理自托管集群需要持续关注及维护,这增加了我们的工作量。

 

当托管解决方案普遍可用时,我们花了些时间对比评估 AKS、GKE 和 EKS 。在我们看来,以上所有解决方案都比自己管理要好上数倍,而且我们能轻易预见迁移带来的快速投资回报。

 

当时,我们的平台 50% 是 .Net , 50% 是 Python,并且已经在使用 Azure Service Bus、Azure SQL Server 及其他 Azure 服务。因此,将集群迁移到 Azure 的好处不言而喻,我们不仅能更方便地集成使用这些服务,还可以利用 Azure 主干网络基础设施,节省因离开/进入外部网络和 VNET 相关的成本(在 AWS 和 Azure 混合设置的情况下,就无法避免这些成本)。此外,我们的许多工程师都熟悉 Azure 及其生态系统,学习成本较低。

 

意外之喜是,在 AKS 上进行初始设置时,我们无需为控制平面节点(主节点)付费,节省了节点费用。

 

2018 年冬天,我们进行了迁移,尽管这些年在 AKS 上也遇到过问题,但我们并未后悔过这次迁移。

 

集群崩溃 #1

 

使用 AWS 进行自托管期间,我们经历了一次大规模的集群崩溃,导致大部分系统和产品出现故障。根 CA 证书、etcd 证书和 API 服务器证书全部过期,导致集群停止工作、无法管理。当时,kube-aws 提供的解决支持非常有限。虽然我们请来一位专家指导,但最终还是不得不从零开始重建整个集群。

 

我们以为每个 git 仓库中都有所有制和 Helm 图表,但出乎意料的是,并非所有服务都是如此。最重要的是,库中没有存储创建集群的任何配置。我们与时间赛跑,重新建立集群并将我们所有服务及产品填充进去。其中有些服务需要重新制作 Helm 图表,以创建缺失的配置。有时会出现Dev1 问 Dev2 的情况:“你还还记得这个服务应该有多少 CPU 或RAM,或者有哪些网络和端口访问权限吗?”更不用说记得什么密钥,它们已随风而逝。

 

我们花了好几天才重新启动集群并将其运行起来。退一步说,这不是我们最骄傲的时刻。

 

得益于积极主动的沟通工作,我们使用了保持透明度、诚实的处理态度和客户关系维系等对策,没有失去任何业务或客户。

 

集群崩溃 #2

 

你可能会猜:第二次崩溃原因不可能是证书造成的,你们一定会从第一次崩溃中吸取教训,对吗?没错,但也不完全对。

 

不幸的是,在重新创建崩溃 #1 的集群时,我们使用的 kube-aws 的特定版本出现了问题。在创建新群集时,它没有将 etcd 证书的有效期设置为我们提供的有效期,而使用了一年的默认期限。因此,在第一次群集崩溃整整一年后,证书过期了,我们又经历了一次集群崩溃。不过这一次恢复就容易多了,我们不必重建一切,但这依旧是一个地狱般的周末。

 

  • 附注 1:其他公司也和我们一样受到了这个漏洞的影响,但这对我们的客户并没有什么帮助……

  • 附注 2:我们原计划在一年后更新所有证书,为了给自己留有余地,我们将过期时间设为两年(如果我没记错的话)。因此,虽然我们计划更新证书,但 bug 比我们早了一步。

 

自 2018 年以来,我们再也没有遇到过集群崩溃的情况……希望我没有乌鸦嘴。

 

经验教训

 

 
1.Kubernetes 很复杂

 

您需要任用对 Kubernetes 的基础设施和运营方面感兴趣并愿意参与其中的工程师。

 

就我们而言,我们需要几名工程师在日常工作之外研究 Kubernetes ,在必要时作为“首选专家”解决问题。如你所想,Kubernetes 特定任务的工作量各不相同,有时连着好几周差不多无事可做,有时几周需要保持高度注意力,比如集群升级期间。

 

将工作轮流分配给整个团队是不可能的,这项技术太过复杂,无法隔一周在不同工作之间“反复横跳”。当然,每个人都需要知道如何使用它(包括部署、调试等),但要在更具挑战性的方面表现出色,专门的学习时间必不可少。此外,拥有一个有远见、有集群发展战略的领导者也很重要。

 

 
2.Kubernetes 证书

 

经历过两次证书过期导致的集群崩溃,因此(我们意识到)精通 Kubernetes 内部证书及其过期日期的详细信息至关重要。

 

 
3.让 Kubernetes 和 Helm 保持更新

 

一旦落后,使用这两项工具成本就会增加,也出现问题。我们总是等待几个月才会升级到最新版本,以了解其他使用者会面临什么新版本问题。但即使保持更新版本,我们也会因为 Kubernetes 和 Helm 多样的新版本(Kubernetes API 从 alfa 到 beta,beta 到 1.0 等)而面临许多耗时的配置文件和图表重写工作。我知道Simon和Martin喜欢 Ingress 的所有变化。

 

 
4.集中式 Helm 图表

 

说到 Helm 图表,我们已经厌倦了每次版本变更都要更新全数超过七十个图表,因此我们采用了一种更通用的“一图统一所有”的方法。使用集中式 Helm 图表有利有弊,但最终这种方法更符合我们的需求。

 

 
5.灾难恢复计划

 

我再三强调:确保在需要时有办法重新创建集群。是的,你可以在用户界面中点击来创建新的群集,但这种方法在大规模或时间紧急的情况下是行不通的。

 

有不同的方法来处理这个问题,从简单的 shell 脚本到更高级的方法,如使用 Terraform(或类似方法)。Crossplane 还可用于管理基础设施即代码(IaC)等。对我们来说,由于团队带宽有限,我们选择了存储和使用 shell 脚本。无论选择哪种方法,都要确保不时测试流程,以确保在需要时可以重新创建集群。

 

 
6.备份密钥

 

制定密钥备份和存储策略。如果你的集群消失了,所有密钥都将丢失。相信我,我们亲身经历过这种情况,当你拥有多个不同的微服务和外部依赖关系时,需要花费大量时间才能重新恢复正常。

 

 
7.与供应商无关 VS“全部押进”

 

一开始,在迁移到 AKS 之后,我们试图不让集群与供应商绑定,这意味着我们将继续使用其他服务进行容器注册表、身份验证、密钥库等。我们的想法是,有朝一日我们可以轻松地迁移到另一个托管解决方案。虽然与供应商无关是个好主意,但对我们来说,机会成本很高。过了一段时间,我们决定全力开发与 AKS 相关的 Azure 产品,如容器注册表、安全扫描、身份验证等。对我们来说,这改善了开发人员的体验,简化了安全性(使用 Azure Entra Id 进行集中式访问管理)等,从而加快了产品上市速度并降低了成本(产生了效益)。

 

 
8.客户资源定义

 

是的,我们全面使用了 Azure 产品,但我们的指导原则是尽可能减少自定义资源定义,而是使用内置的 Kubernetes 资源。不过,我们也有一些例外,比如 Traefik,因为 Ingress API 并不能满足我们的所有需求。

 

 
9.安全性

 

见下文。

 

 
10.可观测性

 

见下文。

 

 
11.已知峰值期间的预缩放

 

即使用了自动缩放器,我们有时也会缩放得太慢。通过使用流量数据和常识(我们是一家物流公司,节假日会出现高峰),我们在高峰来临前一天手动扩大了集群(ReplicaSet),然后在高峰来临后一天缩容(慢慢缩小以应对可能出现的第二波高峰)。

 

 
12.集群内的无人机

 

我们在stage集群中保留了 Drone 构建系统,这样做有好有坏。因为在同一集群中,易于扩展和使用;但如果同时构建太多,会消耗几乎所有资源,导致 Kubernetes 急于启动新节点。最好的解决方案可能是将其作为纯 SaaS 解决方案,而不必担心产品本身的托管和维护工作。

 

 
13.选择正确的节点类型

 

选择节点类型与具体情况密切相关,但根据节点类型,AKS 会保留约 10-30% 的可用内存(用于 AKS 内部服务)。因此,我们发现使用较少但较大的节点类型是有益的。此外,由于我们要在许多服务上运行 .Net,因此需要选择具有高效、大容量 IO 的节点类型。(.Net经常向磁盘写入JIT和日志,如果这需要网络访问,速度就会变慢。我们还确保节点磁盘/缓存的大小至少与配置的节点磁盘总大小相同,以再次避免网络跳转)。

 

 
14.预留实例

 

你可能会认为这种方法有点违背云的灵活性,但对我们来说,将关键实例保留一两年可以节省大量成本。在许多情况下,与“即用即付”方法相比,我们可以节省 50%-60%的成本,相当可观。

 

 
15.k9s

 

对于想要比纯粹的 kubectl 更高一层抽象的用户来说,https://k9scli.io/是一个很好的工具。

 

图片

 

可观测性

 

 
1.监控

 

确保长期跟踪内存、CPU 等的使用情况,以便观察集群的运行情况,确定新功能是提高还是降低了集群性能。这样能更容易地为不同的 pod 找到并设置“正确的”限制(找到正确的平衡点非常重要,因为如果内存耗尽,pod 就会被杀死)。

 

图片

 

 
2.告警

 

完善告警系统需要一个过程,但最终我们将所有告警定向到 Slack 频道。当集群未按预期运行或出现意外问题时,我们能便捷地收到信息。

 

图片

 

 
3.日志记录

 

将所有日志整合到一个地方,同时采用强大的跟踪 ID 策略(例如 OpenTelemetry 或类似软件),对于任何微服务架构都至关重要。我们花了两三年时间才做到这一点。如果我们早点实施,就能节省大量时间。

 

图片

 

安全性

 

Kubernetes 中的安全问题是一个庞大的话题,我强烈建议对其进行深入研究,以了解所有细微差别(例如,请参阅 NSA、CISA 发布的《Kubernetes 加固指南》)。以下是我们的一些经验要点,但请注意,这些内容并不完备。

 

 
1.访问控制

 

简而言之,Kubernetes 默认限制并不过分。因此,我们投入了大量时间来收紧访问权限,对 pod 和容器实施最小权限原则。此外,由于存在特定漏洞,无权限攻击者有可能将其权限升级为 root 权限,从而规避 Linux 命名空间限制,在某些情况下,甚至可以逃离容器,获得主机节点上的 root 访问权限。这绝非好事。

 

您应该设置只读根文件系统、禁用服务帐户令牌自动挂载、禁用权限升级、放弃所有不必要的功能等等。在我们的具体设置中,我们使用 Azure Policy 和 Gatekeeper 来确保不会部署不安全的容器。

 

在 AKS 中的 Kubernetes 设置中,我们利用基于角色的访问控制(RBAC)的强大功能来进一步加强安全性和访问管理。

 

 
2.容器漏洞

 

有很多优质工具可以扫描和验证容器以及 Kubernetes 的其他部分。我们使用 Azure Defender 和 Azure Defender for Containers 来满足一些需求。

 

注:与其陷入“分析瘫痪”,即试图找到一个完美的、拥有各种花哨功能的工具,不如先选择工具,然后直接开始学习。

 

多年实践的长期设置

 

 
1.部署

 

与其他许多人一样,我们使用 Helm 来管理和简化 Kubernetes 上部署和打包应用程序。由于我们很久以前就开始使用 Helm,而且最初是 .Net/Go/Java/Python/PHP 混合使用,所以重写 Helm 图表的次数多得我都记不清了。

 

 
2.可观测性

 

我们开始使用 Loggly 和 FluentD 进行集中式日志记录,但几年后,我们转而使用 Elastic 和 Kibana(ELK 堆栈)。对我们来说,使用 Elastic 和 Kibana 更方便,因为它们的使用范围更广,而且在我们的设置中,它们的价格也更便宜。

 

 
3.容器注册表

 

我们最初使用的是 Quay,这是一款不错的产品。但随着向 Azure 迁移,使用 Azure 容器注册表变得很自然,因为它是集成的,因此对我们来说是更“原生”的解决方案。(随后,我们还将容器置于 Azure Security Advisor 下)。

 

 
4.管道

 

从一开始,我们就使用 Drone 构建容器。刚开始时,支持容器和 Docker 的 CI 系统并不多,也不提供代码配置。多年来,Drone 为我们提供了良好的服务。Harness 收购 Drone 后,它变得有点混乱,但在我们屈服并迁移到高级版本后,我们拥有了所需的所有功能。

 

改变游戏规则

 

过去几年,Kubernetes 改变了我们的游戏规则。它释放出的功能让我们能够更高效地扩展(应对流量波动)、优化基础设施成本、改善开发人员体验、更轻松地测试新创意,从而大大缩短了新产品和服务的上市时间/盈利时间。

 

我们开始使用 Kubernetes 有点太早了,在我们尚未真正遇到它能解决的问题之前。但从长远来看,尤其是最近几年,它已被证明能为我们带来巨大价值。

 

结语

 

回顾八年来的经历,我们有很多故事可以分享,其中很多已经淡出记忆。我希望我们的组建过程、所犯的错误以及一路走来所汲取的经验教训对您有所帮助。

 

感谢阅读。

 

特别感谢Matin、Simon和Niklas对本文提出的宝贵意见。

 

作者丨

Anders Jönsson

  编译丨onehunnit
来源丨medium.com/@.anders/learnings-from-our-8-years-of-kubernetes-in-production-two-major-cluster-crashes-ditching-self-0257c09d36cd
 
*本文为dbaplus社群编译整理,如需转载请取得授权并标明出处!欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn
最新评论
访客 2024年04月08日

如果字段的最大可能长度超过255字节,那么长度值可能…

访客 2024年03月04日

只能说作者太用心了,优秀

访客 2024年02月23日

感谢详解

访客 2024年02月20日

一般干个7-8年(即30岁左右),能做到年入40w-50w;有…

访客 2023年08月20日

230721

活动预告