前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一个集群被删的故事

一个集群被删的故事

作者头像
我的小碗汤
发布于 2023-03-19 09:15:31
发布于 2023-03-19 09:15:31
6080
举报
文章被收录于专栏:我的小碗汤我的小碗汤

原文: https://thenewstack.io/deleting-production-in-a-few-easy-steps-and-how-to-fix-it/

想象一下,您从梦中醒来,收到一条简单的消息,“我们丢失了一个集群”,但这根本不是梦。

InfluxDB Cloud 运行在云应用编排平台 Kubernetes 上,我们使用自动化的持续交付(CD) 系统将代码和配置更改部署到生产环境。在一个平常的工作日,工程团队交付 5~15 种不同的生产变更。

为了将这些代码和配置更改部署到 Kubernetes 集群,该团队使用了一个名为 ArgoCD 的工具。ArgoCD 读取 YAML 配置文件并使用 Kubernetes API 使集群与 YAML 配置中指定的代码保持一致。

ArgoCD 使用 Kubernetes 中的自定义资源(称为 Applications 和 AppProjects)将源基础设施作为代码存储库进行管理。ArgoCD 还管理这些存储库的文件路径以及特定 Kubernetes 集群和命名空间的部署目标。

因为我们维护多个集群,所以我们还使用 ArgoCD 进行自我监管并管理所有不同 ArgoCD 应用程序和 AppProjects 的定义。这是一种常见的开发方法,通常被称为app of apps模式。

应用模式

我们使用一种称为 jsonnet 的语言来创建 YAML 配置的模板。CD 系统检测 jsonnet 中的更改,将 jsonnet 转换为 YAML,然后 Argo 应用更改。在我们事件发生时,单个应用程序的所有资源都保存在一个 YAML 文件中。

对象名称和目录结构遵循某些命名约定(app name)–(cluster name)用于对象名称, env/(cluster name)/(app name)/yml 用于保留其定义的存储库。例如,cluster01 中的 app01 定义为 app01-cluster01,其定义保存在路径 env/cluster01/app01/yml 下。

我们对基础设施即代码进行代码审查,其中包括检查生成的 YAML 并确保它在应用更新之前按预期运行。

发生了什么

考验始于配置文件中的一行代码。团队中的某个人创建了一个 PR,将几个新对象添加到配置文件和渲染的 YAML 文件中。

在这种情况下,添加的对象之一是新的 ArgoCD 应用程序和 AppProject。由于自动化错误,对象的名称错误。它们本应命名为app02-cluster01,但改为命名为app01-cluster01。代码审查忽略了 app01 和 app02 之间的差异,因此,在渲染时,这两个资源最终都在一个 YAML 配置文件中。

ArgoCD 应用程序/项目名称冲突

当我们将 PR 与错误命名的对象合并时,ArgoCD 会读取整个生成的 YAML 文件并按照它们在文件中列出的顺序应用所有对象。结果,列出的最后一个对象“获胜”并被应用,这就是发生的事情。ArgoCD 用新实例替换了以前的实例 app1。问题在于,ArgoCD 删除的 app1 实例是 InfluxDB Cloud 的核心工作负载。

此外,新对象创建了我们不想在该集群上启用的额外工作负载。简而言之,当 ArgoCD 替换 app01 的实例时,该过程触发了整个生产环境的立即删除。

显然,这对我们的用户不利。当生产出现故障时,所有 API 端点(包括所有写入和读取)都返回 404 错误。在中断期间,没有人能够收集数据,任务无法运行,外部查询也不起作用。

灾难恢复~计划和初步尝试

我们立即着手解决问题,首先查看合并 PR 中的代码。这个问题很难被发现,因为它涉及项目和应用程序名称之间的 ArgoCD 冲突。

我们的第一个直觉是恢复更改以使事情恢复正常。不幸的是,这并不是有状态应用程序的工作方式。我们开始了恢复过程,但几乎立即停止了,因为恢复更改会导致 ArgoCD 创建我们应用程序的全新实例。这个新实例将没有原始实例所具有的关于用户、仪表板和任务的元数据。至关重要的是,新实例不会拥有最重要的东西~客户的数据。

在这一点上,值得一提的是,我们将 InfluxDB 云集群中的所有数据存储在使用 reclaimPolicy:Retain 的卷中。这意味着即使我们管理的 Kubernetes 资源,例如 StatefulSet、PersistentVolumeClaim (PVC) 被删除,底层的 PersistentVolume 和云中的卷也不会被删除。

我们在制定恢复计划时考虑到了这一关键细节。我们必须手动重新创建所有底层 Kubernetes 对象,例如 PVC。一旦新对象启动并运行,我们需要从备份系统中恢复任何丢失的数据,然后让 ArgoCD 重新创建我们应用程序的无状态部分。

灾难恢复~恢复状态和数据

InfluxDB Cloud 在其他微服务与之交互的系统的一些组件中保持状态,包括:

  • Etcd:用于元数据,它存在于独立于 Kubernetes 控制平面的专用集群上。
  • Kafka 和 Zookeeper:用于预写日志 (WAL)。
  • 存储引擎:这包括用于持久性的 PVC 和对象存储

团队首先恢复 etcd 和元数据。这可能是恢复过程中最直接的任务,因为 etcd 存储的数据集相对较小,因此我们能够让 etcd 集群快速启动并运行。这对我们来说是一场轻松的胜利,让我们能够将所有注意力集中在更复杂的恢复任务上,比如 Kafka 和存储。

我们识别并重新创建了任何丢失的 Kubernetes 对象,这使卷(特别是持久卷对象)重新联机并将它们置于可用状态。一旦卷的问题得到解决,我们重新创建了 StatefulSet,以确保所有 pod 运行和集群同步。

下一步是恢复 Kafka,为此我们还必须让 Zookeeper 保持健康状态,它为 Kafka 集群保留元数据。Zookeeper 卷也在事件中被删除。好在我们使用 Velero 每小时备份一次 Zookeeper,Zookeeper 的数据不会经常变化。我们从最近的备份中成功恢复了 Zookeeper 卷,这足以让它启动并运行。

要恢复 Kafka,我们必须创建与 Kafka 的卷和状态相关的任何缺失对象,然后一次重新创建集群的 StatefulSet 一个 pod。我们决定禁用所有健康和就绪检查,以使 Kafka 集群处于健康状态。这是因为我们必须一次在 StatefulSet 中创建一个 Pod,而 Kafka 直到集群领导者启动后才准备好。暂时禁用检查允许我们创建所有必要的 pod,包括集群领导者,以便 Kafka 集群报告为健康。

因为 Kafka 和 etcd 是相互独立的,所以我们可以同时恢复两者。但是,我们希望确保有正确的程序,所以我们选择一次恢复一个。

一旦 Kafka 和 etcd 重新上线,我们可以重新启用部分 InfluxDB Cloud 以开始接受写入。因为我们使用 Kafka 作为我们的预写日志 (WAL),即使存储功能不正常,我们也可以接受对系统的写入并将它们添加到 WAL。一旦其他部分重新上线,InfluxDB Cloud 就会处理这些写入。

随着写入变得可用,我们开始担心我们的实例会被来自 Telegraf 和其他客户端的请求所淹没,这些请求写入在集群关闭时缓冲的数据。为了防止这种情况,我们调整了处理写入请求的组件的大小,增加了副本的数量并增加了内存请求和限制。这有助于我们处理临时的写入高峰并将所有数据摄取到 Kafka 中。

为了修复存储组件,我们重新创建了所有存储 pod。InfluxDB 还将所有时间序列数据备份到对象存储(例如,AWS S3、Azure Blob Store 和 Google Cloud Storage)。当 pod 出现时,他们从对象存储中下载数据副本,然后索引所有数据以实现高效读取。该过程完成后,每个存储 pod 都会联系 Kafka 并读取 WAL 中任何未处理的数据。

灾难恢复——最后阶段

一旦创建存储 pod 和索引现有数据的过程开始,灾难恢复团队就能够专注于修复系统的其他部分。

我们更改了存储集群的一些设置,减少了某些服务的副本数量,以使重新上线的部分能够更快地启动。此时,我们重新启用了 ArgoCD,以便它可以创建仍然缺失的任何 Kubernetes 对象。

在初始部署和存储引擎功能齐全后,我们可以重新启用关键流程的功能,例如查询数据和查看仪表板。在此过程继续进行的同时,我们开始为所有资源重新创建适当数量的副本,并重新启用任何剩余的功能。

最后,所有组件都部署了预期数量的副本,并且一切都处于健康和就绪状态,团队启用了计划任务并进行了最终的 QA 检查,以确保一切正常运行。

总的来说,从 PR 合并到我们恢复全部功能的时间不到六个小时。

学到了什么

事件发生后,我们进行了适当的事后分析,以分析哪些方面进展顺利,以及我们可以为未来的事件改进哪些方面。

从好的方面来说,我们能够在不丢失任何数据的情况下恢复系统。在整个中断期间,任何重试向 InfluxDB 写入数据的工具都会继续这样做,最终,该数据被写入 InfluxDB 云产品。例如,我们的开源收集代理 Telegraf 默认执行重试。

最重要的问题是我们的监控和警报系统没有立即检测到这个问题。这就是为什么我们最初的反应是尝试回滚更改,而不是计划和执行经过深思熟虑的恢复过程。我们还缺少丢失部分或整个 InfluxDB Cloud 实例的运行手册。

作为此事件的结果,InfluxData 工程创建了专注于恢复状态的运行手册。如果发生类似情况,即如果 Kubernetes 对象(例如 Persistent Volume Claims)被删除,但底层磁盘和卷上的数据被保留,我们现在有详细说明如何继续。我们还确保所有环境中的所有卷都设置为保留数据,即使 PVC 对象被删除。

我们还改进了处理面向公众的事件的流程。我们的目标是尽可能少地发生事件,这将有助于我们解决未来可能面向公众的平台出现的任何问题。

在技术方面,我们意识到我们的系统应该阻止 PR 被合并,我们采取了多个步骤来解决这个问题。我们改变了 InfluxDB 存储生成的 YAML 文件的方式,转向每个文件一个对象的方法。例如 v1.Service-(namespace).etcd.yaml 用于 etcd 服务。将来,类似的 PR 将清楚地显示为对现有对象的覆盖,并且不会被误认为是添加新对象。

我们还改进了在生成 YAML 文件时检测重复项的工具。现在,系统会在提交更改以供审核之前警告每个人重复。此外,由于 Kubernetes 的工作方式,检测逻辑不仅仅关注文件名。例如,apiVersion 包括 group 名和 version,具有 apiVersion 的对象 networking.k8s.io/v1beta1 和 networking.k8s.io/v1 和相同的命名空间和名称应被视为相同的对象,尽管 apiVersion 字符串不同。

这一事件是我们配置 CD 的宝贵经验。ArgoCD 允许添加特定的注释来防止删除某些资源。向我们所有的有状态资源添加 Prune=false 注释可确保 ArgoCD 在出现配置错误问题时保持这些资源完好无损。我们还将注解添加到 ArgoCD 管理的 Namespace 对象中,否则,ArgoCD 仍可能删除它所在的 Namespace,导致所有对象的级联删除。

我们还为 ArgoCD 应用程序对象添加了 FailOnSharedResource=true 选项。这使得 ArgoCD 在尝试将任何更改应用到由另一个 ArgoCD 应用程序管理或以前由另一个 ArgoCD 应用程序管理的对象之前失败。这确保了类似的错误,或将 ArgoCD 指向错误的集群或命名空间,将阻止它对现有对象造成任何更改。

最后一点

虽然这些都是我们已经想要做出的改变,但这一事件促使我们实施它们以改进我们所有的自动化和流程。希望对我们经验的深入了解将帮助您制定有效的灾难恢复计划。

- END -

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-06-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 进击云原生 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
K8S部署Kafka集群 - 部署笔记
Kafka和zookeeper是两种典型的有状态的应用集群服务。首先kafka和zookeeper都需要存储盘来保存有状态信息;其次kafka和zookeeper每一个实例都需要有对应的实例Id (Kafka需broker.id, zookeeper需要my.id) 来作为集群内部每个成员的标识,集群内节点之间进行内部通信时需要用到这些标识。
洗尽了浮华
2021/03/03
5.8K0
k8s基础概念及术语
上一篇简单介绍了一下k8s是什么以及如何使用kubeadm快捷安装,今儿来聊一下k8s的几个基础概念及术语。k8s中的资源都可以使用yaml文件进行描述。(文章内容来源于《kubernetes权威指南 第四版》)
Liusy
2020/09/16
1.1K0
k8s基础概念及术语
k8s实践(13)--有状态服务StatefulSet详解
https://blog.csdn.net/hguisu/category_9999400.html
黄规速
2023/03/06
5.2K0
k8s实践(13)--有状态服务StatefulSet详解
全方位分析zookeeper分布式系统协调器在Kubernetes上的实践
下面的清单包含Headless Service,Service,PodDisruptionBudget和StatefulSet。
公众号: 云原生生态圈
2021/06/09
9870
【K8S专栏】Kubernetes有状态应用管理
我们在《Kubernetes工作负载管理》中主要介绍了无状态应用的管理,当时也有提到有状态应用,但是由于那时候还没有解释数据如何持久化就没有做深度的介绍,而在这章,我们会着重介绍如何进行有状态应用的管理。
没有故事的陈师傅
2022/12/06
4920
ArgoCD 简明教程
Argo CD 是一个为 Kubernetes 而生的,遵循声明式 GitOps 理念的持续部署(CD)工具,它的配置和使用非常简单,并且自带一个简单易用的 Dashboard 页面,并且支持多种配置管理/模板工具(例如 Kustomize、Helm、Ksonnet、Jsonnet、plain-YAML)。Argo CD 被实现为一个 Kubernetes 控制器,它持续监控正在运行的应用程序并将当前的实时状态与所需的目标状态(例如 Git 仓库中的配置)进行比较,在 Git 仓库更改时自动同步和部署应用程序。
Se7en258
2021/12/27
3.1K0
ArgoCD 简明教程
k8s实践(12)--K8s service服务详解
Kubernetes Pod 是有生命周期的,它们可以被创建,也可以被销毁,然而一旦被销毁生命就永远结束。 通过 ReplicationController 能够动态地创建和销毁 Pod(例如,需要进行扩缩容,或者执行)。 每个 滚动升级 Pod 都会获取它自己的 IP 地址,即使这些 IP 地址不总是稳定可依赖的。 这会导致一个问题:在 Kubernetes 集群中,如果一组 Pod(称为 backend)为其它 Pod (称为 frontend)提供服务,那么那些 frontend 该如何发现,并连接到这组 Pod 中的哪些 backend 呢?
黄规速
2022/04/14
9.1K0
k8s实践(12)--K8s service服务详解
kubernetes 中 kafka 和 zookeeper 有状态集群服务部署实践 (二)
引言 Kafka和zookeeper是在两种典型的有状态的集群服务。首先kafka和zookeeper都需要存储盘来保存有状态信息,其次kafka和zookeeper每一个实例都需要有对应的实例Id
腾讯云容器服务团队
2017/07/17
5.4K0
kubernetes 中 kafka 和 zookeeper 有状态集群服务部署实践 (二)
Kubernetes(k8s)-StatefulSet介绍
我们上一章介绍了Docker基本情况,目前在规模较大的容器集群基本都是Kubernetes,但是Kubernetes涉及的东西和概念确实是太多了,而且随着版本迭代功能在还增加,笔者有些功能也确实没用过,所以只能按照我自己的理解来讲解。
运维小路
2024/12/30
1010
Kubernetes(k8s)-StatefulSet介绍
Argo CD 实践教程 05
这一部分介绍了核心概念,并讨论了如何将Argo CD作为SRE进行操作。 本书的这一部分包括以下章节:
拿我格子衫来
2023/08/24
6180
Argo CD 实践教程 05
Kubernetes全栈架构师(资源调度上)--学习笔记
Replication Controller(复制控制器,RC)和ReplicaSet(复制集,RS)是两种简单部署Pod的方式。在生产环境中,主要使用更高级的Deployment等方式进行Pod的管理和部署。
郑子铭
2021/08/01
6810
Kubernetes全栈架构师(资源调度上)--学习笔记
k8s——针对有状态服务实现数据持久化
对服务器程序来说,究竟是有状态服务,还是无状态服务,其判断依旧是指两个来自相同发起者的请求在服务器端是否具备上下文关系。如果是状态化请求,那么服务器端一般都要保存请求的相关信息,每个请求可以默认地使用以前的请求信息。而对于无状态请求,服务器端所能够处理的过程必须全部来自于请求所携带的信息,以及其他服务器端自身所保存的、并且可以被所有请求所使用的公共信息。 无状态的服务器程序,最著名的就是WEB服务器。每次HTTP请求和以前都没有什么关系,只是获取目标URI。得到目标内容之后,这次连接就被杀死,没有任何痕迹。在后来的发展进程中,逐渐在无状态化的过程中,加入状态化的信息,比如COOKIE。服务端在响应客户端的请求的时候,会向客户端推送一个COOKIE,这个COOKIE记录服务端上面的一些信息。客户端在后续的请求中,可以携带这个COOKIE,服务端可以根据这个COOKIE判断这个请求的上下文关系。COOKIE的存在,是无状态化向状态化的一个过渡手段,他通过外部扩展手段,COOKIE来维护上下文关系。 状态化的服务器有更广阔的应用范围,比如MSN、网络游戏等服务器。他在服务端维护每个连接的状态信息,服务端在接收到每个连接的发送的请求时,可以从本地存储的信息来重现上下文关系。这样,客户端可以很容易使用缺省的信息,服务端也可以很容易地进行状态管理。比如说,当一个用户登录后,服务端可以根据用户名获取他的生日等先前的注册信息;而且在后续的处理中,服务端也很容易找到这个用户的历史信息。 状态化服务器在功能实现方面具有更加强大的优势,但由于他需要维护大量的信息和状态,在性能方面要稍逊于无状态服务器。无状态服务器在处理简单服务方面有优势,但复杂功能方面有很多弊端,比如,用无状态服务器来实现即时通讯服务器,将会是场恶梦。
小手冰凉
2020/09/15
2.3K0
深入浅出 Kubernetes:StatefulSet 概念理解
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
耕耘实录
2019/09/18
6900
Running Solr on Kubernetes
我们将为搜索工程师介绍在Kubernetes(k8s)上运行Solr的基础知识。 具体来说,我们涵盖以下主题:
黎明你好
2020/02/05
6.3K0
Running Solr on Kubernetes
vcluster -- 基于虚拟集群的多租户方案
虚拟集群(virtual cluster, 简称 vcluster)是在常规的 Kubernetes 集群之上运行的一个功能齐全,轻量级,隔离性良好的 Kubernetes 集群。虚拟集群的核心思想是提供运行在“真实”Kubernetes 集群之上隔离的 Kubernetes 控制平面(例如 API Server)。与完全独立的“真实“集群相比,虚拟集群没有自己的工作节点或者网络,工作负载实际上还是在底层宿主集群上调度。
Se7en258
2022/12/06
1.5K0
vcluster -- 基于虚拟集群的多租户方案
云原生基础设施之Kubernetes
傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波
山河已无恙
2023/03/02
1.4K0
云原生基础设施之Kubernetes
深入理解StatefulSet,用Kubernetes编排有状态应用
作为一个后端工程师,因为负责的大部分项目都是Web服务这类的“无状态应用”,在平时工作中接触到的最常用的Kubernetes控制器是Deployment,但是Deployment只适合于编排“无状态应用”,它会假设一个应用的所有 Pod是完全一样的,互相之间也没有顺序依赖,也无所谓运行在哪台宿主机上。正因为每个Pod都一样,在需要的时候可以水平扩/缩,增加和删除Pod。
KevinYan
2020/12/15
1.2K0
深入理解StatefulSet,用Kubernetes编排有状态应用
kubernetes(十一) 存储& statefulset控制器
kubernetes支持持久卷的存储插件: https://kubernetes.io/docs/concepts/storage/persistent-volumes/
alexhuiwang
2020/09/23
8030
kubernetes(十一) 存储& statefulset控制器
【重识云原生】第六章容器基础6.4.10.5节——Statefulset原理剖析
首先,StatefulSet 的控制器直接管理的是 Pod。这是因为,StatefulSet 里的不同 Pod 实例,不再像 ReplicaSet 中那样都是完全一样的,而是有了细微区别的。比如,每个 Pod 的 hostname、名字等都是不同的、携带了编号的。而 StatefulSet 区分这些实例的方式,就是通过在 Pod 的名字里加上事先约定好的编号。
江中散人_Jun
2022/11/11
6920
【重识云原生】第六章容器基础6.4.10.5节——Statefulset原理剖析
【重识云原生】第六章容器基础6.4.10.2节——StatefulSet常规操作实操
StatefulSet 旨在与有状态的应用及分布式系统一起使用。本节将通过使用 StatefulSet 部署一个简单的 Web 应用,来演示StatefulSet的常规操作,包括:
江中散人_Jun
2022/11/12
9070
【重识云原生】第六章容器基础6.4.10.2节——StatefulSet常规操作实操
相关推荐
K8S部署Kafka集群 - 部署笔记
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档