现在一切都变成了“Gitops”,所有的工作负载都变成了“无状态”,我还需要 Kubernetes 备份工具吗?我想向您展示,这是一个初学者经常会犯的严重误解......
译自Kubernetes is not stateless, you need a backup tool,作者是 Michael Courcy 。
一种奇怪的假设
我们经常听到使用 Kubernetes 的客户和潜在客户提出这样一个奇怪的假设:
有了 Kubernetes,现在一切都变成 Gitops 和无状态了!
因此:
既然一切都变成了“Gitops”,所有的工作负载都变成了“无状态”,我还需要 Kubernetes 备份工具吗?
我想向您展示,这是一个初学者经常会犯的严重误解。他们希望现在灾难恢复管理只是重启一个工具链那么简单,他们不需要投资任何备份工具。
这里对无服务器和无状态之间存在混淆,从开发人员的角度来看,kubernetes 是无服务器的,但绝对不是无状态的......
但是在深入探讨这个问题之前,我们先明确这些不同的词:Gitops、无状态和工具链。
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 备份工具......
一切都是 GitOps ...... 不真实(大多数时候)
理论上,所有内容都是代码,在所有级别上,您都以“As Code”的精神进行自动化,换句话说,您试图 100% 声明式。
例如:
- 您使用 Terraform 代码来创建网络、云服务、Kubernetes 集群等
- 您使用 Argo CD 来部署主要的 Kubernetes 工具,如 cert-manager、Istio 等
- 您使用 Tekton 来构建、测试和推送应用程序镜像
- 您使用 Helm Chart 部署应用程序及其特定配置
所有这些都是伟大的,当然我们只能批准这些实践的执行。但现实情况并不像看起来那么光明......
- 构建所有这些链式工具需要很大的努力;您不一定有全部人力资源
- 有时一小时内的热修复绝对是必需的,而链式工具无法处理这种情况
- 您的工具链旨在重新部署太多组件,而您不能允许重新部署,您只想重新部署特定组件,因此您会手动执行
- 现在,您被要求部署同一基础架构的多个实例,但某些参数化没有考虑到这一点,重新开发整个工具链与手动更改相比,这会使您选择后者
- 应用程序不再发展,只需要开发人员偶尔修复一些错误;您不会重新投资工具链。开发人员将手动应用更改,这有时会持续多年。
- 许多工具链(由不同团队维护)针对单个应用程序,随着不同工具链的代码演变,重建应用程序在给定时间点的确切状态并不容易。
这个列表并不详尽,每次我认真研究任何项目时,在不同级别我都能看到并非所有内容都是“作为代码”。总有一块(有时是大块)异常会打破这一理论过程。
最后,真理的源头是 Kubernetes,您需要一个能够正确捕获它的工具。
GitOps 可能会中断,这比您想象的要频繁
所有这些工具链(Terraform、ArgoCD、Tekton ......)甚至云提供商提供的工具链(Azure DevOps、GitHub Action、CodeFresh、AWS ......)都只是在机器上执行的程序,它们也可能由于许多原因而中断。它们也可能仅由于人为错误或不再工作的依赖项而中断。
例如,我记得有一个工具链用于扫描 Docker 镜像中的漏洞,这个工具必须传递所有镜像才能允许部署过程继续。不幸的是,此工具暂时中断,并且由于另一个原因(您知道灾难总是聚集在一起...)集群中断,必须恢复应用程序。当时没有人知道如何在不进行安全扫描的情况下重建工具链。应用程序已经部署这一事实如果您要再次部署,您必须通过此步骤。
无法恢复应用程序,团队不得不等待有人找出如何在没有安全扫描的情况下重建工具链。最后没有满足 SLA 要求。
团队决定投资备份工具,该工具可以独立于工具链重新安装应用程序。
此外,黑客也非常了解 GIT 存储库和工具链的重要性,他们可能决定破坏或销毁它们。如果发生这种情况,您必须在能够重用之前修复它们。这可能会严重影响您的恢复时间目标。如果您完全丢失了 GIT 存储库,您将不得不在午夜叫醒您的一名开发人员,并询问他们是否碰巧仍在笔记本电脑上拥有主分支。如果您认为这种情况从未发生过,请三思......
GitOps 工具链用于开发和部署,它不是备份工具。
例如,Kasten 具有不可变备份,可保证即使是不法管理员也无法销毁您的备份。GIT 和工具链没有设计用于此目的。请记住,大多数攻击都是内部攻击。
Operator 改变了游戏规则
Operator 是 Kubernetes 上专门用于数据库的 Controller。几乎所有主要数据库供应商现在都提供他们的 Operator 版本。Operator 封装了数据库专家的知识,并使 Kubernetes 上的数据库管理变得非常简单和受支持。
Operator 将帮助您扩展或扩展。您只需更改自定义资源中的一个字段(例如副本数),Operator 将执行所有复杂的操作以满足所需状态,而不会中断服务。
有了 Operator,就没有理由不将数据库移到 Kubernetes 中(如果您信任供应商)。但有一点需要注意,就是 Operator 在 Kubernetes 中创建了大量更改(Secrets、Certificates、PVC ...),现在比以往任何时候都更需要一个备份工具,该工具可以与 Operator API 协同工作。Kasten 基于 Kanister 的扩展机制可以非常容易地在 Operator API 和备份操作之间进行协调。
Kasten 不否定 GitOps 实践,相反!
归结这个话题的目的不是否定 GitOps 实践带来的价值。在 Kasten,我们每两周部署一次,运行大量自动化部署和自动化测试。如果我们不采用 DevOps(包括 GitOps)实践,所有这些都不可能实现。
我还在这个 Tekton 演示中展示了如何在部署新版本之前包含 Kasten 备份操作来捕获应用程序的快照。还有一个 Azure DevOps 示例做了同样的事情,但是使用 Azure DevOps 任务。所以 Kasten 与 GitOps 实践配合得非常好。
但如果您认为现在您是 GitOps 所以在 Kubernetes 上不需要备份工具,那将是一个错误:
主要结论
- 您仍然需要捕获最终的真实来源,即 Kubernetes,没有别的。
- 您的数据库最终会进入 Kubernetes,因为它使应用程序和数据管理变得更容易操作并降低成本。因此,您将与应用程序堆栈的其余部分一起对其进行备份。
- 如果一切同时崩溃,您需要一个计划B,以快速在其他地方重建,而不依赖于开发资源。