注意事项 佩雷夫 :我们提供了一些简短的事后样本,介绍了不同公司的工程师在操作基于Kubernetes的基础架构时面临的致命问题。 每个注释都讨论了问题本身,原因和后果,当然还涉及有助于避免将来发生类似情况的解决方案。
如您所知,从别人的经验中学习是比较便宜的,因此-让这些故事帮助您为可能的意外做好准备。 顺便说一句,大量的,定期更新的指向此类“失败故事”的链接的选择都会在此站点上发布(根据该Git存储库中的数据)。 1号 内核恐慌如何使网站崩溃
原稿: 月光 。在1月18日至22日之间,Moonlight网站和API出现间歇性故障。 所有这些都始于随机的API错误,最后是完全关闭。 问题已解决,应用程序恢复正常。
一般资讯
Moonlight使用称为Kubernetes的软件。 Kubernetes在服务器组上运行应用程序。 这些服务器称为节点。 在节点上运行的应用程序的副本称为Pod。 Kubernetes有一个调度程序,可以动态确定哪些节点上的哪些Pod应该工作。
时间表
星期五的第一个错误与连接到Redis数据库的问题有关。 Moonlight API使用Redis验证每个经过身份验证的请求的会话。 我们的监控工具Kubernetes已通知某些节点和Pod没有响应。 同时,Google Cloud报告了
网络服务出现
故障 ,我们认为这是造成问题的原因。
随着周末流量的减少,这些错误似乎已得到解决。 但是,在星期二早上,Moonlight的站点倒塌了,外部流量完全没有到达集群。 我们
在Twitter上发现了
另一个具有类似症状的
人,并认为Google托管网络出现故障。 我们联系了Google Cloud支持,该支持迅速将问题转给了技术支持团队。
Google技术支持团队揭示了Kubernetes集群中节点行为的某些模式。 单个节点的CPU利用率达到100%,此后,虚拟机中发生了内核崩溃并崩溃了。
原因
导致故障的周期如下:
- Kubernetes调度程序在同一节点上托管了多个CPU占用率很高的Pod。
- Pod占用了节点上的所有CPU资源。
- 接下来是内核恐慌,这导致了一段时间的停机时间,在此期间节点未响应调度程序。
- 调度程序将所有掉落的吊舱移动到新节点,并且重复该过程,加剧了总体情况。
最初,该错误发生在Redis吊舱中,但最终所有处理流量的吊舱均下降,从而导致完全关闭。 重新计划期间的指数延迟导致更长的停机时间。
解决方案
通过向所有主要部署中添加
反关联性规则 ,我们能够还原该站点。 它们自动将Pod分布在节点上,从而提高了容错能力和性能。
Kubernetes本身被设计为容错主机系统。 Moonlight在不同服务器上使用三个节点来保持稳定性,并且我们为服务流量的每个应用程序运行三个副本。 这个想法是在每个节点上有一个副本。 在这种情况下,即使两个节点发生故障也不会导致停机。 但是,Kubernetes有时会将所有三个Pod与站点放置在同一节点上,从而在系统中造成瓶颈。 同时,其他需要处理器功能(即服务器端渲染)的应用程序位于同一节点上,而不是在单独的节点上。
需要正确配置和正常运行的Kubernetes集群来应对长时间的高CPU负载并以最大程度利用可用资源的方式放置Pod。 我们将继续与Google Cloud支持合作,以识别并解决服务器上内核恐慌的根本原因。
结论
使用反关联性规则,您可以使处理外部流量的应用程序更加容错。 如果您在Kubernetes上有类似的服务,请考虑添加它们。
我们将继续与Google的人员合作,以发现并消除节点上OS内核故障的原因。
2号 Kubernetes和Ingress端点的“肮脏”秘密
原文: Ravelin的Phil Pearl 。优雅被高估
我们在Ravelin迁移到Kubernetes(位于GKE上)。 这个过程非常成功。 我们的广告连播中断预算一如既往地充满,有状态确实是有状态的
(很难翻译的双关语:“我们的有状态集非常有状态”-大约是Transl。) ,并且节点的滑动替换就像发条一样。
最后一个难题是将API层从旧虚拟机迁移到Kubernetes集群。 为此,我们需要配置Ingress,以便可以从外部访问API。
起初,这项任务看起来很简单。 我们只需定义Ingress控制器,调整Terraform即可获得一定数量的IP地址,Google会处理几乎所有其他事务。 所有这一切都将像魔术一样起作用。 上课!
但是,随着时间的流逝,他们开始注意到集成测试会定期收到错误502。由此,我们的旅程开始了。 但是,我会节省您的时间,直接得出结论。
正常关机
每个人都在谈论正常关闭(“正常”,逐步关闭)。 但是您真的不应该在Kubernetes上依靠他。 至少,这不应该是
您从母亲的乳汁中吸收的优雅停药。 在Kubernetes世界中,这种“优雅”程度是不必要的,并且会带来严重的问题。
完美世界
在多数视图中,这是从Kubernetes中的服务或负载平衡器中删除Pod的方式:
- 复制控制器决定删除容器。
- 端点容器已从服务或负载平衡器中删除。 到吊舱的新交通不再到达。
- 称为停止前的钩子,或者吊舱接收到SIGTERM信号。
- “优美地”显示的广告连播已断开连接。 它停止接受传入的连接。
- “优美的”断开连接完成,并且在停止或终止其所有现有连接之后,吊舱被破坏。
不幸的是,现实是完全不同的。
真实世界
大多数文档都暗示所有事情都有些不同,但是它们并没有在任何地方明确地写这件事。 主要问题是步骤3不跟随步骤2。它们同时发生。 在普通服务中,端点的删除是如此之快,以至于遇到问题的可能性极低。 但是,对于Ingress,一切都不同:它们的响应速度通常要慢得多,因此问题变得很明显。 在端点的更改进入Ingress之前,Pod可能早已获得SIGTERM。
结果,正常关机根本不是吊舱所需的。 他将获得新的连接,并且必须继续进行处理,否则客户端将开始出现第500个错误,并且有关简单的部署和扩展的整个精彩故事将开始崩溃。
实际上是这样的:
- 复制控制器决定删除容器。
- 端点容器已从服务或负载平衡器中删除。 对于Ingress,这可能需要一些时间,并且新流量将继续流入广告连播中。
- 称为停止前的钩子,或者吊舱接收到SIGTERM信号。
- 在很大程度上,吊舱必须忽略这一点,继续工作并维护新的连接。 如果可能的话,他应该向客户暗示切换到另一个地方会很好。 例如,对于HTTP,它可能会在响应头中发送
Connection: close
。 - 仅当“优雅”等待期到期并且被SIGKILL杀死时,Pod才会退出。
- 确保此时间段长于对负载均衡器进行重新编程所需的时间。
如果这是第三方代码,并且您无法更改其行为,那么您可以做的最好的事情就是添加一个停止前的钩子,该钩子将在“优雅”的时间内进入睡眠状态,以便Pod可以继续正常工作发生了
3号 简单的Webhook如何导致集群故障
原始: Jetstack 。Jetstack在Kubernetes上为其客户提供多租户平台。 有时会有一些特殊要求,我们无法使用标准的Kubernetes配置来满足。 为了实现它们,最近我们开始使用
开放策略代理 (在本次评测中,我们对项目进行了详细介绍-大约翻译)作为实现特殊策略的访问控制器。
本文介绍了由于未正确配置此集成而导致的故障。
突发事件
我们致力于更新开发集群的向导,其中各个团队在工作日内测试了他们的应用程序。 它是Google Kubernetes引擎(GKE)在europe-west1区域中的区域集群。
指挥官被警告说正在进行更新,预计不会造成停机。 那天早些时候,我们已经对另一个预生产环境进行了类似的更新。
我们使用GKE Terraform管道开始了升级。 直到Terraform超时(我们设置为20分钟)到期,向导更新才完成。 这是第一个出现问题的唤醒电话,尽管在GKE控制台中群集仍被列为“升级中”。
重新启动管道导致以下错误
google_container_cluster.cluster: Error waiting for updating GKE master version: All cluster resources were brought up, but the cluster API is reporting that: component "kube-apiserver" from endpoint "gke-..." is unhealthy
这次,与API服务器的连接开始定期中断,并且团队无法部署其应用程序。
当我们试图了解正在发生的事情时,所有节点开始被破坏并以无休止的循环重新创建。 这导致对我们所有客户的不加选择的拒绝服务。
我们确定失败的根本原因
借助Google的支持,我们能够确定导致失败的事件的顺序:
- GKE在一个向导实例上完成了升级,并在更新下一个向导时开始接受到该API服务器上的所有流量。
- 在升级向导的第二个实例期间,API服务器无法执行PostStartHook来注册CA。
- 在执行此挂钩期间,API服务器尝试在
kube-system
更新名为extension-apiserver-authentication
的kube-system
。 无法执行此操作,因为我们配置的Open Policy Agent(OPA)检查Webhook的后端未响应。 - 为了使向导通过运行状况检查,此操作必须成功完成。 由于这没有发生,因此第二个主机进入了紧急周期并停止了更新。
结果是周期性的API崩溃,由于kubelet无法报告节点的运行状况。 反过来,这导致了一个事实,即GKE节点的自动恢复机制
(节点自动修复)开始重新启动节点。
文档中详细描述了此功能:
状态不正常可能意味着:在给定的时间(大约10分钟)内,节点完全不发出任何状态。
解决方案
当我们发现
ValidatingAdmissionWebhook
资源导致对API服务器的间歇访问时,我们将其删除并恢复了群集的正常运行。
从那时起,OPA的
ValidatingAdmissionWebhook
已配置为仅监视那些适用策略且开发团队可以访问的名称空间。 我们还将网络挂钩限制为
Ingress
和
Service
,这是我们的政策适用的唯一方式。
自从我们第一次部署OPA以来,文档
已更新以反映此更改。
我们还添加了活动性测试,以确保OPA在不可用时重新启动(并对文档进行了
适当的修改 )。
我们还考虑过禁用GKE节点
的自动恢复
机制 ,但仍然决定放弃这一想法。
总结
如果启用了API服务器响应时间警报,则在部署用于OPA的Webhook之后,最初可以注意到所有
CREATE
和
UPDATE
请求的全局增加。
这强调了为所有工作负载设置测试的重要性。 回顾过去,我们可以说OPA的部署非常简单,以至于我们甚至都没有参与
Helm图表 (尽管应该这样做)。 该图表进行了超出手册中描述的基本设置的许多调整,包括带有入场控制器的容器的livenessProbe设置。
我们不是第一个遇到此问题的人:
上游问题仍然悬而未决。 此功能的功能可以明显改善(我们将对此进行跟进)。
译者的PS
另请参阅我们的博客: