如何在生产环境构建K8S

55次阅读
没有评论

共计 7445 个字符,预计需要花费 19 分钟才能阅读完成。

这篇文章给大家介绍如何在生产环境构建 K8S,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

在分布式系统上管理服务是运维团队面临的最困难的问题之一。在生产中突破新软件并学习如何可靠地运营是非常重要的。本文是一则实例,讲述为什么学习运营 Kubernetes 很重要,以及为什么很难。下面是关于 Kubernetes bug 导致的一小时中断故障的事后剖析。

为什么选择在 Kubernetes 之上构建?如何将 Kubernetes 集成到现有基础设施中?丸趣 TV 小编给出的方法是建立 (和改进) 对 Kubernetes 集群的可靠性的信任,以及构建在 Kubernetes 之上的抽象。

我们最近在 Kubernetes 之上构建了一个分布式的 cron 作业调度系统,这是一个令人兴奋的容器编排的新平台。Kubernetes 现在非常流行,并且有许多令人兴奋的承诺:最令人兴奋的是,程序员不需要知道或关心他们的应用程序运行的是什么机器。

什么是 Kubernetes?

Kubernetes 是一个分布式系统,用于调度程序在集群中运行。你可以告诉 Kubernetes 运行一个程序的 5 个副本,它将在工作节点上动态调度它们。容器自动调度以增加利用率,节省资金,强大的 deployment primitives 允许逐步推出新的代码,安全上下文和网络策略允许企业以安全的方式运行多租户的工作负载。

Kubernetes 有很多不同类型的调度能力。它可以调度长时间运行的 HTTP 服务、在集群中每台机器上运行的 daemonsets、每小时运行的 cron 作业等等。

为什么是 Kubernetes?

每个基础设施项目都是从业务需求开始的,我们的目标是提高现有分布式 cron 作业系统的可靠性和安全性。我们的要求是:

建立和运营一支小团队(只有 2 人在项目中全职工作)。

在 20 台机器上可靠地安排大约 500 个不同的 cron 作业。

我们决定在 Kubernetes 之上建立的几个原因:

希望构建一个现有的开源项目。

kubernetes 包含一个分布式 cron 作业调度器,不必自己编写。

kubernetes 是一个非常活跃的项目,经常接受捐赠。

kubernetes 是用 Go 写的,很容易学。几乎所有 Kubernetes 的 bug 都是由团队中没有经验的程序员做的。

如果我们能够成功地运营 Kubernetes,可以在未来的 Kubernetes 上构建,例如,目前正在开发基于 kubernet 的系统来训练机器学习模型。

我们以前使用 Chronos 作为 cron 作业调度系统, 但它不再是满足可靠性要求, 而且大部分都没有维护(在过去 9 个月中 1 次提交,  最后一次合并请求的时间是 2016 年 3 月))Chronos 未维护的, 我们认为不值得继续投资改善现有的集群。

如果你正考虑 Kubernetes,请记住: 不要仅仅因为其他公司在使用 Kubernetes 而使用它。建立一个可靠的集群需要花费大量的时间,使用它的业务案例并不是很突出。把你的时间用在聪明的方法上。

可靠性是什么意思?

说到运营服务,“可靠”这个词本身并没有什么意义。要讨论可靠性,首先需要建立一个 SLO(服务级别目标)。

我们有三个主要目标:

99.99% 的 cron 作业应该在预定运行时间的 20 分钟内开始运行。20 分钟是一个很宽的窗口,但是我们采访了内部客户,没有人要求更高的精确度。

Jobs 应该运行 99.99% 的时间(不被终止)。

向 Kubernetes 的迁移不会导致任何面向客户的事件。

这意味着:

Kubernetes API 的短暂停机时间是可以接受的(如果停机 10 分钟,只要在 5 分钟内恢复即可)。

调度错误 (cron 作业运行完全丢失并且根本无法运行) 是不可接受的。我们非常重视安排错误报告。

要谨慎对待 pod evictions  和安全终止实例,以免作业过于频繁地终止。

需要一个好的迁移计划。

建立一个 Kubernetes 集群

我们建立第一个 Kubernetes 集群的基本方法是从零开始构建集群,而不是使用 kubeadm 或 kops 之类的工具。使用 Puppet(常用的配置管理工具)调配了配置。从头开始构建很好,原因有两个:能够深入地集成 Kubernetes 在架构中,并且深入理解其内部。

我们希望将 Kubernetes 整合到现有的基础架构中。与现有系统无缝集成,以便进行日志记录,证书管理,加密,网络安全,监控,AWS 实例管理,部署,数据库代理,内部 DNS 服务器,配置管理以及更多。整合所有这些系统有时需要一点创造力,但总体上比试图让 kubeadm / kops 成为我们想要的更容易。

在信任并了解如何操作这些现有系统后,我们希望继续在新的 Kubernetes 群集中使用。例如,安全证书管理是一个非常棘手的问题,已经有办法颁发和管理证书。通过适当的整合,我们避免了为 Kubernetes 创建新的 CA。

准确了解设置的参数是如何影响 Kubernetes 设置的。例如,在配置用于身份验证的证书 /CAs 时,使用了超过 12 个参数。了解这些参数有助于在遇到身份验证问题时更容易调试设置。

对 Kubernetes 建立信心

在 Kubernetes 之初,团队中没有人使用过 Kubernetes。如何从“没有人用过 Kubernetes”到“我们有信心在生产中运行 Kubernetes”?

战略 0:与其他公司交谈

我们向其他公司询问了 Kubernetes 的经历。他们都以不同的方式或在不同的环境中使用 Kubernetes(运行 HTTP 服务,裸机,Google Kubernetes 引擎等)。

在谈到 Kubernetes 这样庞大而复杂的系统时,重要的是认真思考自己的用例,做自己的实验,建立对自己环境的信心,并做出决定。例如,你不该读这篇博客文章并得出结论:“Stripe 正在成功使用 Kubernetes,所以它也适用于我们!”

以下是我们在与几家运营 Kubernetes 集群的公司沟通后后学到的:

优先考虑企业 etcd 集群的可靠性(etcd 是存储所有 Kubernetes 集群状态的地方)。

某些 Kubernetes 功能比其他功能更稳定,因此请小心 Alpha 功能。一些公司只有在稳定后才能使用稳定特性(例如,如果某个功能在 1.8 版本中保持稳定,则在使用它之前会等待 1.9 或 1.10)。

考虑使用托管的 Kubernetes 系统,如 GKE / AKS / EKS。从头开始建立高可用性 Kubernetes 系统是一项巨大的工作。AWS 在此项目中没有托管的 Kubernetes 服务,所以这不适合我们。

注意由覆盖网络 / 软件定义网络引入的额外网络延迟。

策略 1: 阅读代码。

我们计划很大程度上依赖于 Kubernetes 的一个组件,即 cronjob 控制器。这个组件当时处于 alpha 阶段,这让我们有点担心。我们在一个测试集群中尝试了它,但是如何判断它在生产中是否适合我们呢?

值得庆幸的是,所有 cronjob 控制器的核心功能只有 400 行 Go。通过源代码快速读取显示:

cron 作业控制器是一个无状态的服务(与其他 Kubernetes 组件一样,除了 etcd)。

每 10 秒钟,这个控制器调用 syncAll 函数:go wait.Until(jm.syncAll,10 * time.Second,stopCh)

syncAll 函数从 Kubernetes API 中获取所有 cron 作业,遍历该列表,确定下一步应该运行哪些作业,然后启动这些作业。

核心逻辑似乎相对容易理解。更重要的是,如果在这个控制器中有一个 bug,它可能是我们可以修复的东西。

策略 2: 做负载测试

在开始认真构建集群之前,我们做了一些负载测试。我们并不担心 Kubernetes 集群能够处理多少节点(计划部署大约 20 个节点),但是确实想让某些 Kubernetes 能够处理我们希望运行的那么多的 cron 作业(大约每分钟 50 个)。

在一个 3 节点集群中运行了测试,创建了 1000 个 cron 作业,每个任务每分钟运行一次。这些工作中的每一个都简单地运行 bash -c echo hello world。我们选择简单的作业,是因为希望测试集群的调度和编排能力,而不是集群的总计算能力。

测试集群无法处理每分钟 1000 个 cron 作业。每个节点每秒最多只能启动一个 pod,而集群能够每分钟运行 200 个 cron 作业。由于我们只希望每分钟运行大约 50 个 cron 作业,所以我们认为这些限制不是阻碍因素。

策略 3: 优先构建和测试高可用性 etcd 集群。

在设置 Kubernetes 时,最重要的事情之一就是运行 etcd。Etcd 是 Kubernetes 集群的核心,它是存储集群中所有数据的地方。除了 etcd 之外,其他一切都是无状态的。如果 etcd 没有运行,不能对 Kubernetes 集群进行任何更改(尽管现有的服务将继续运行!)

这张图显示了 etcd 是 Kubernetes 集群的核心——API 服务器是 etcd 前面的无状态 REST/ 认证端点,然后其他组件通过 API 服务器与 etcd 对话。  在运行时,有两个要点需要牢记:

设置复制, 这样集群不会死如果你失去了一个节点。我们现在有三个 etcd 副本。

确保足够的 I / O 带宽。我们的 etcd 版本有一个问题,一个具有高 fsync 延迟的节点可能触发连续的 leader elections,导致集群无法使用。通过确保所有节点的 I / O 带宽都比 etcd 的写入数量多,从而弥补了这一点。

设置复制不是一个设置 - 忘记操作。我们仔细地测试后发现可能会丢失一个 etcd 节点,并且集群优雅地恢复了。

以下是为建立 etcd 集群所做的一些工作:

设置复制

监控 etcd 服务是可用的

写一些简单的工具, 以便轻松创建新的 etcd 节点,并加入到集群当中

编写一些简单的工具,以便我们可以轻松创建新的 etcd 节点并将它们加入到群集中

补丁 etcd 的高集成, 这样我们可以在生产环境中运行超过 1 个  etcd 集群

测试从一个 etcd 备份中恢复

测试可以在不停机情况下重建整个集群

很高兴很早就做了这个测试。某个周五的早晨,在我们的生产集群中,一个 etcd 节点停止了对 ping 的响应。我们得到了警报,终止了节点,带来了一个新的节点,加入到集群中,同时 Kubernetes 继续运行。

策略 4:逐步将工作迁移到 Kubernetes

我们的目标之一是将工作迁移到 Kubernetes 而不造成任何中断。成功进行生产迁移的秘诀不是避免犯错(这是不可能的),而是设计你的迁移以减少错误的影响。

我们很幸运有多种职位可以迁移到新集群,所以可以迁移一些低影响的工作岗位,接受一两次失败。

在开始迁移之前,构建了易于使用的工具,如果有必要,可以在不到五分钟的时间内在旧系统和新系统之间来回移动作业。这种简单的工具减少了错误的影响 – 如果迁移一个没有计划的依赖的工作,没有什么大不了的!可以将其移回原处,解决问题,然后再试。

以下是我们采用的整体迁移策略:

根据他们的重要程度大致排序

将一些重复的工作迁移到 Kubernetes。如果发现新的情况,快速回滚,修复问题,然后重试。

策略 5: 调查 Kubernetes bug 并修复它们

我们在项目开始时制定了一个规则: 如果 Kubernetes 做了一些意外的事情,必须调查,找出原因,并提出补救措施。

调查每个问题都很耗时,但很重要。如果只是简单地将 Kubernetes 的”古怪行为”看作是复杂的分布式系统的功能,我们担心,因为它们会被调用导致产生 bug 集群。

在使用了这种方法之后,我们发现并且修复了 Kubernetes 的几个 bug。

以下是测试中发现的一些问题:

名称超过 52 个字符的 Cronjob 无法安排作业。

Pods 有时会永远停留在挂起状态。

调度程序会每 3 个小时崩溃一次。

Flannel 的 hostgw 后端没有替换过时的路由表项

修复这些 bug 让我们对 Kubernetes 项目的使用感觉好得多——不仅它运行得比较好,而且也接受补丁并有一个良好的 PR 审查过程。

Kubernetes 有 bug,像所有的软件一样。特别是,我们非常频繁地使用调度器(cron 作业总是在创建新的 pods),而调度器使用缓存有时会导致 bug、回退和崩溃。缓存是困难的! 但是代码库是可接近的,我们已经能够处理遇到的 bug。

值得一提的是,Kubernetes 的 pod 驱逐逻辑。Kubernetes 有一个称为节点控制器的组件,它负责将 pod 驱逐出去,如果节点没有响应,则将它们移到另一个节点。allnodes 会暂时无响应(例如,由于网络或配置问题),在这种情况下,Kubernetes 可以终止集群中的所有 pod。

如果运行的是大型 Kubernetes 集群,请仔细阅读节点控制器文档,仔细地考虑设置,并进行广泛测试。每次通过创建网络分区测试对这些设置的配置更改(例如,pod- 驱逐超时),就会发生令人惊讶的事情。最好在测试中发现这些意外,而不是在生产中发现。

策略 6:有意引起 Kubernetes 集群问题

之前讨论过在 Stripe 中进行游戏日练习。这个想法是要想出你最终会在生产中发生的情况,然后在生产中故意造成这些情况,从而确保能够处理它们。

在集群上进行了几次练习之后,经常发现诸如监视或配置错误等问题。很高兴在早期发现这些问题,而不是六个月后突然发现。

以下是运行的一些比赛日练习:

终止 Kubernetes API 服务器

终止所有 Kubernetes API 服务器并将其恢复(这非常有效)

终止 etcd 节点

从 API 服务器中关闭 Kubernetes 集群中的工作节点(以便它们无法通信)。这导致节点上的所有 pods 被迁移到其他节点。

很高兴看到 Kubernetes 如何应对我们投入的大量干扰。Kubernetes 的设计是为了适应错误 – 它有存储所有状态的 etcd 集群,一个只是该数据库的 REST 接口的 API 服务器,以及一个协调所有集群管理的无状态控制器集合。

如果任何 Kubernetes 核心组件(API 服务器,控制器管理器或调度程序)被中断或重新启动,一旦它们出现,它们将从 etcd 读取相关状态并继续无缝运行。这是我们希望的事情之一,而且在实践中实际运作良好。

以下是测试中发现的一些问题:

“没有得到 paged,来修复监控。“

“当销毁 API 服务器实例并将其恢复后,需要人工干预。最好解决这个问题。“

“有时执行 etcd 故障转移时,API 服务器会启动超时请求,直至重新启动。”

 

在运行这些测试后,针对发现的问题开发了补救措施:改进了监控,发现了固定配置问题,并提交了 Kubernetes bug。

使 cron 作业易于使用

简单地探讨一下我们是如何使基于 kubernetes 的系统易于使用的。

最初的目标是设计一个运行 cron 作业的系统,团队有信心运营和维护。一旦建立了对 Kubernetes 的信心,就需要工程师们轻松地配置和增加新的 cron 作业。我们开发了一个简单的 YAML 配置格式,这样用户就不需要了解 Kubernetes 的内部结构来使用这个系统。这是我们开发的格式:

name: job-name-here

kubernetes:

 schedule: 15 */2 * * *

command:

– ruby

– /path/to/script.rb

resources:

 requests:

 cpu: 0.1

 memory: 128M

 limits:

 memory: 1024M

没有做什么特别的事情——我们编写了一个简单的程序,将这种格式转换为 Kubernetes cron 作业配置,将其应用于 kubectl。

我们还编写了一个测试套件,以确保作业名称不会太长,并且所有名称都是惟一的。我们目前不使用 cgroups 来强化对大多数作业的内存限制,但计划将来推出。

我们的简单格式易于使用,而且由于自动生成了来自相同格式的 Chronos 和 Kubernetes cron 作业定义,所以在两个系统之间迁移作业非常简单。这是使我们的增量迁移工作良好的关键部分。将作业迁移到 Kubernetes 时,可以用一个简单的三行配置更改,在不到十分钟的时间内将其移回。

监控 Kubernetes

监测 Kubernetes 集群的内部状态非常令人愉悦。我们使用 kube-state-metrics 软件包进行监测,并使用一个名为 veneurl – Prometheus 的小型 Go 程序来获取 Prometheus 的度量标准,将它们作为 statsd 指标发布到我们的监控系统中。

例如,以下是过去一小时内集群中未决 Pod 的数量图表。Pending 意味着等待分配一个工作节点来运行。可以看到上午 11 点的数字峰值,很多 cron 作业在每小时的第 0 分钟运行。

还有一个监视器,用于检查有没有任何 Pod 在 Pending 状态中卡住 – 每个 Pod 在 5 分钟内开始在 worker 节点上运行,否则会收到警报。

Kubernetes 未来计划

设置 Kubernetes,到顺畅地运行生产代码并将所有 cron 作业迁移到新集群,花了五个月的时间,三位工程师全职工作。我们投资学习 Kubernetes 的一个重要原因是希望能够在 Stripe 中更广泛地使用 Kubernetes。

以下是适用于运行 Kubernetes(或任何其他复杂分布式系统)的原则:

为企业的 Kubernetes 项目,以及所有基础设施项目,定义清晰的商业原因。了解业务案例和用户的需求使项目变得更加容易。

积极削减范围。避免使用许多 Kubernetes 的基本特性来简化集群。这让我们可以更快速地发送消息,例如,由于 pod-to-pod 联网不是我们项目的必需条件,可以关闭节点之间的所有网络连接,并将 Kubernetes 的网络安全性推迟。

花大量时间学习如何正确地运营 Kubernetes 集群。仔细测试边界情况。分布式系统非常复杂,有很多潜在的问题。以前面的例子为例: 如果节点控制器由于配置与 API 服务器失去联系,那么它可以杀死集群中的所有 pods。学习 Kubernetes 在每次配置更改后的表现如何,需要时间和精心的关注。

通过专注于这些原则,我们已经有信心在生产中使用 Kubernetes。我们将继续开发 Kubernetes 的使用,例如,我们正在关注 AWS EKS 的发布。我们正在完成另一个系统的工作,训练机器学习模型,并且正在探索将一些 HTTP 服务迁移到 Kubernetes。随着我们继续在生产中运行 Kubernetes 时,我们计划对开源项目做出贡献。

关于如何在生产环境构建 K8S 就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-08-16发表,共计7445字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)