现在一切都变成了“Gitops”,所有的工作负载都变成了“无状态”,我还需要 Kubernetes 备份工具吗?我想向您展示,这是一个初学者经常会犯的严重误解......
译自 Kubernetes is not stateless, you need a backup tool,作者是 Michael Courcy 。
我们经常听到使用 Kubernetes 的客户和潜在客户提出这样一个奇怪的假设:
有了 Kubernetes,现在一切都变成 Gitops 和无状态了!
因此:
既然一切都变成了“Gitops”,所有的工作负载都变成了“无状态”,我还需要 Kubernetes 备份工具吗?
我想向您展示,这是一个初学者经常会犯的严重误解。他们希望现在灾难恢复管理只是重启一个工具链那么简单,他们不需要投资任何备份工具。
这里对无服务器和无状态之间存在混淆,从开发人员的角度来看,kubernetes 是无服务器的,但绝对不是无状态的......
但是在深入探讨这个问题之前,我们先明确这些不同的词:Gitops、无状态和工具链。
Gitops 是一种 Devops 实践,使用 GIT 和 CI/CD 工具来应用基础设施自动化。您通过在 GIT 中提交新的代码更改来声明您的基础设施,然后 CI/CD 工具会自动部署/应用您的更改。
无状态意味着应用程序没有持久值,如果您从零重新部署应用程序,它会像以前一样继续工作。无状态应用程序不会在任何存储介质上维护数据。
工具链是从 GIT 获取代码并对此代码执行不同操作以构建基础设施的一组工具。如果工具链产生的结果不依赖于先前执行的状态,则该工具链被称为幂等的。一个好的工具链应该是幂等的。
容器化强化了这种无状态的想法,因为容器“包含”运行应用程序所需的所有依赖项。镜像定义了此依赖项列表,容器是此镜像的短暂实例。如果您失去运行容器的机器,这并不是什么大事,只需要在另一台机器上从镜像重新部署一个新的容器实例即可。容器运行时将从镜像定义重建所有文件,这样您就可以长期运行了。
但是,如果容器使用卷,这就不是真的。例如,数据库容器将使用卷来写入其数据。在这种情况下,容器是有状态的。如果您失去卷,您的数据库将为空重新启动。
容器是无状态的,除非它们是有状态的。听起来很愚蠢?我同意......
您可能会惊讶地发现,2023年 Datadog 的最新报告(事实6)显示:
数据库和 Web 服务器是容器的主要工作负载类别。
是的,您没有看错,容器的主要工作负载类别是有状态的!
随着 Kubernetes,“无状态”的感觉达到了另一个阈值,现在您甚至不需要记住在哪台机器上部署了哪些容器,因为 Kubernetes 会为您处理这个问题,并动态处理您的期望状态。Kubernetes 让您强烈感觉到您可以完全抽象出基础设施,只有代码才重要。
您仍然必须在 Kubernetes 中定义“期望状态”,如负载均衡器来公开您的应用程序,副本数,内存和 CPU,机密,配置文件等。但所有这些都定义在您应用于 Kubernetes 的 YAML 文件中,并且您在 GIT 中维护它们。
但是等等!我们仍然必须构建和保护 Kubernetes 集群;这是一个复杂的任务,对吗?
不再如此!现在云可以在一分钟内构建 Kubernetes 集群。只需在 AWS 或 Azure 控制台中点击一下,执行一个简单的 “glcoud containers create...” 命令,或者只需要在 GIT 中定义一个新的集群定义,并连接到云 API 的 CI/CD 工具,就可以了。
当我们谈论在 Kubernetes 上进行备份时,我们遇到了真诚地感到困惑的潜在客户......
现在是时候再次接触现实,并谈论现实情况了。
如果把应用程序作为一个整体来看,您会很快意识到现实中不存在无状态应用程序。试想一个在线商店,它不维护订单,不维护客户的地址。想象一个银行应用程序,它不管理交易。这样说听起来可能很荒谬且明显,但重要的是要重新连接到现实。
如果一个应用程序真的无状态,那么很有可能它将是无用的。
那么我们为什么要谈论无状态呢?因为应用程序的一部分是无状态的。例如,一个无状态的 Node.js 前端正在向一个有状态的 PostgreSQL 数据库发出请求。从功能的角度来看,整个应用程序是相当有状态的。您将应用程序分成两部分,一部分无状态,另一部分有状态,这并不意味着您不再需要管理数据。
是的,但是我的数据库在 Kubernetes 集群之外,我的模式仍然有效,对吗?
如果您的数据库在 Kubernetes 集群之外,您将面临一些真正的挑战,这将严重影响您的 GitOps 方法。让我们详细看看它们。
您希望数据库像其他组件一样成为 Kubernetes 的公民。
如果数据库在 Kubernetes 集群之外,您将面临共定位挑战,这将打破您的“无状态”方法。的确,您不能把数据库放得离工作负载太远,否则您将面临严重的性能问题。
因此,出于很好的原因,您的数据库和 Kubernetes 集群在同一个网络上。现在,您遇到了灾难,破坏了您的基础设施。重建 Kubernetes 集群在其他地方很容易(记住它是完全无状态和 GitOps 的),但是您的数据库怎么办?您必须实例化新的数据库机器并重新应用您的转储。这并不很干净,也不很“GitOps”。
那么怎么样?您的 GitOps 实践在您的数据库启动时就停止了吗?DevOps 意味着开发和运维共享他们的忧虑,您难道不违反这条规则吗?
这并不是由于灾难,而是您想要迁移到另一个提供商以节省资金,Kubernetes 部分很简单,但数据库部分风险很大,因为您仍然以旧方式管理这部分。您要权衡您通过迁移节省的资金与您承担的数据库风险。这种体系结构真的减少了您的选择自由。
您的开发人员和 QA 团队需要使用实际数据测试应用程序,您需要将数据库的副本复制到另一台机器或一组机器上,并确保测试实例的配置不指向生产数据库。现在,您想增加开发和 QA 团队的数量,就需要增加机器和配置更改的数量。如果数据库在 Kubernetes 中与应用程序在同一命名空间中管理,您甚至不会考虑这个问题。备份工具将在一分钟内将您的应用程序恢复到其他位置。
您还必须映射您的镜像版本与您的数据库方案版本。这不是很容易管理的,在我的开发人员职业生涯中,我已经看到许多数据库方案与应用程序版本之间的不匹配。意外的模式更改和数据转换会损坏您的数据,并可能会产生极大的后果。
您的开发团队非常敏捷,希望发展为微服务架构。此架构需要构建几个数据库,通常用于不同目的(例如,Elasticsearch、Redis、MongoDB 和 PostgreSQL 提供不同的功能),但如果以旧方式管理数据库,则很难接受这种多样性。它将我们之前列出的所有挑战乘以数据库和数据库类型的数量。很有可能,随着应用程序的发展,您将拒绝此更改,并通过使数据库成为实际单体来加强应用程序的单体性质。
如果您不将数据库移至 Kubernetes,随着应用程序的发展,您将使应用程序更加单一化。
在 Kubernetes 上部署应用程序可以大大减少应用程序的成本。但这对数据库部分并不适用。Kubernetes 优化您的计算资源,为什么数据库会是一个例外?
出于所有这些原因,数据库将逐渐进入您的 Kubernetes 集群。这就是我们在现场观察到的情况。
第一步是为测试和开发而进行的,以允许在 Kubernetes 中部署数据库,这更便宜、更容易管理。
然后,团队注意到它的工作效果非常好,并且不再看到在 Kubernetes 之外维护数据库的意义。他们希望使用具有不同功能的其他数据库,等待 DBA 团队与他们同步通常太长,他们会直接在自己的应用程序命名空间中创建新数据库。
您很快就会发现自己维护一种“精神分裂”模式,数据库的一部分在 Kubernetes 之外,另一部分在内部。
您最终会将大多数数据库移到 Kubernetes 内部,这是不可避免的。
现在您需要一个强大的 Kubernetes 备份工具......
理论上,所有内容都是代码,在所有级别上,您都以“As Code”的精神进行自动化,换句话说,您试图 100% 声明式。
例如:
- 您使用 Terraform 代码来创建网络、云服务、Kubernetes 集群等
- 您使用 Argo CD 来部署主要的 Kubernetes 工具,如 cert-manager、Istio 等
- 您使用 Tekton 来构建、测试和推送应用程序镜像
- 您使用 Helm Chart 部署应用程序及其特定配置
所有这些都是伟大的,当然我们只能批准这些实践的执行。 但现实情况并不像看起来那么光明......
- 构建所有这些链式工具需要很大的努力;您不一定有全部人力资源
- 有时一小时内的热修复绝对是必需的,而链式工具无法处理这种情况
- 您的工具链旨在重新部署太多组件,而您不能允许重新部署,您只想重新部署特定组件,因此您会手动执行
- 现在,您被要求部署同一基础架构的多个实例,但某些参数化没有考虑到这一点,重新开发整个工具链与手动更改相比,这会使您选择后者
- 应用程序不再发展,只需要开发人员偶尔修复一些错误;您不会重新投资工具链。 开发人员将手动应用更改,这有时会持续多年。
- 许多工具链(由不同团队维护)针对单个应用程序,随着不同工具链的代码演变,重建应用程序在给定时间点的确切状态并不容易。
这个列表并不详尽,每次我认真研究任何项目时,在不同级别我都能看到并非所有内容都是“作为代码”。总有一块(有时是大块)异常会打破这一理论过程。
最后,真理的源头是 Kubernetes,您需要一个能够正确捕获它的工具。
所有这些工具链(Terraform、ArgoCD、Tekton ......)甚至云提供商提供的工具链(Azure DevOps、GitHub Action、CodeFresh、AWS ......)都只是在机器上执行的程序,它们也可能由于许多原因而中断。它们也可能仅由于人为错误或不再工作的依赖项而中断。
例如,我记得有一个工具链用于扫描 Docker 镜像中的漏洞,这个工具必须传递所有镜像才能允许部署过程继续。不幸的是,此工具暂时中断,并且由于另一个原因(您知道灾难总是聚集在一起...)集群中断,必须恢复应用程序。当时没有人知道如何在不进行安全扫描的情况下重建工具链。应用程序已经部署这一事实如果您要再次部署,您必须通过此步骤。
无法恢复应用程序,团队不得不等待有人找出如何在没有安全扫描的情况下重建工具链。最后没有满足 SLA 要求。
团队决定投资备份工具,该工具可以独立于工具链重新安装应用程序。
此外,黑客也非常了解 GIT 存储库和工具链的重要性,他们可能决定破坏或销毁它们。如果发生这种情况,您必须在能够重用之前修复它们。这可能会严重影响您的恢复时间目标。如果您完全丢失了 GIT 存储库,您将不得不在午夜叫醒您的一名开发人员,并询问他们是否碰巧仍在笔记本电脑上拥有主分支。如果您认为这种情况从未发生过,请三思......
GitOps 工具链用于开发和部署,它不是备份工具。
例如,Kasten 具有不可变备份,可保证即使是不法管理员也无法销毁您的备份。GIT 和工具链没有设计用于此目的。请记住,大多数攻击都是内部攻击。
Operator 是 Kubernetes 上专门用于数据库的 Controller。几乎所有主要数据库供应商现在都提供他们的 Operator 版本。Operator 封装了数据库专家的知识,并使 Kubernetes 上的数据库管理变得非常简单和受支持。
Operator 将帮助您扩展或扩展。您只需更改自定义资源中的一个字段(例如副本数),Operator 将执行所有复杂的操作以满足所需状态,而不会中断服务。
有了 Operator,就没有理由不将数据库移到 Kubernetes 中(如果您信任供应商)。但有一点需要注意,就是 Operator 在 Kubernetes 中创建了大量更改(Secrets、Certificates、PVC ...),现在比以往任何时候都更需要一个备份工具,该工具可以与 Operator API 协同工作。Kasten 基于 Kanister 的扩展机制可以非常容易地在 Operator API 和备份操作之间进行协调。
归结这个话题的目的不是否定 GitOps 实践带来的价值。在 Kasten,我们每两周部署一次,运行大量自动化部署和自动化测试。如果我们不采用 DevOps(包括 GitOps)实践,所有这些都不可能实现。
我还在这个 Tekton 演示中展示了如何在部署新版本之前包含 Kasten 备份操作来捕获应用程序的快照。还有一个 Azure DevOps 示例做了同样的事情,但是使用 Azure DevOps 任务。所以 Kasten 与 GitOps 实践配合得非常好。
但如果您认为现在您是 GitOps 所以在 Kubernetes 上不需要备份工具,那将是一个错误:
- 您仍然需要捕获最终的真实来源,即 Kubernetes,没有别的。
- 您的数据库最终会进入 Kubernetes,因为它使应用程序和数据管理变得更容易操作并降低成本。因此,您将与应用程序堆栈的其余部分一起对其进行备份。
- 如果一切同时崩溃,您需要一个计划B,以快速在其他地方重建,而不依赖于开发资源。