云不可知论架构的幻觉
每当我与客户讨论他们的IT战略时,供应商锁定似乎是一个非常紧迫且重要的话题。尤其是像银行和保险公司这样的受监管机构,他们总是不惜一切代价地避免供应商锁定。这篇短文探讨了这个问题,并提出了一些应对建议。
供应商锁定
首先,我们需要定义“锁定供应商”的含义。锁定供应商通常意味着我们的系统严重依赖于该供应商的能力。更换供应商会变得困难,或者成本高昂。锁定会导致供应商获得单方面的优势。定价条件和策略无法再自由协商,例如……此外,某些行业需要明确处理锁定问题,例如金融机构。他们需要制定计划,以防供应商关闭或弃用产品。某种形式的退出策略。
EBA 指南要求机构在外包关键或重要职能时,必须制定全面、记录在案且经过充分测试的退出策略(包括强制退出计划)。——
来源
让我们考虑一个例子:使用像 PostgreSQL 这样的特定数据库。
PostgreSQL是一个基于 SQL 的关系数据库,类似于MariaDB或Microsoft SQL Server。每个产品提供的功能各不相同。例如,PostgreSQL 为处理 CSV 数据提供了强大的支持,并对正则表达式提供了扩展支持。而 Microsoft SQL Server 则提供了自动更新的视图。
我们可以使用这些独有的功能,也可以不使用这些。我们要么依赖 PostgreSQL 对 CSV 数据的处理,要么不依赖。在第一种情况下,我们被锁定在这个功能上。在第二种情况下,我们需要自己构建这个 PostgreSQL 特有的功能。
许多开发人员应该熟悉这种情况。减少上述锁定的一个标准策略是使用外观(facade)。快速浏览一下 Java 技术栈,就会发现像用于消息传递的JMS或用于持久化的JPA这样的解决方案。每个解决方案都旨在抽象出实际的底层技术。原则上,这将允许开发人员在不更改代码的情况下在数据库之间切换。下图展示了这一理念。
一个服务使用 JPA 访问数据库。它通过配置A 使用 SpringBoot 和 PostgreSQL:
spring.datasource.platform=postgres
spring.datasource.url=jdbc:postgresql://localhost:5432/test
例如,为了测试而切换到 H2 时,无需更改代码。服务将应用配置 B。
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
spring.datasource.url=jdbc:h2:mem:testdb
我们不需要修改应用程序代码。只需指向不同的 SQL 风格spring.jpa.database-platform
和数据库实例位置spring.datasource.url
即可。
简而言之,我们通过在两者之间放置一个外观(例如 JPA)来将代码与特定供应商的功能隔离开来。再次强调这一点。如果我们使用外观并承诺只使用通用功能,就等于放弃了任何特定数据库的优势。如果我们只想通过配置进行切换,就不能依赖 PostgreSQL 独有的功能。
让我们将这个概念应用到云端!
云无关架构
如今,大多数 IT 公司都制定了某种形式的云战略。选择云提供商并非易事,尤其是在受监管的行业(银行、保险、医疗保健)。在选择供应商时,必须考虑SOX、GDPR、HIPAA等所有相关法规。
但工作远不止于此。企业需要处理供应商锁定的问题。亚马逊网络服务 (AWS)、谷歌云平台 (GCP) 和微软 Azure (Azure) 提供的服务和功能相当。但如果仔细观察,就会发现差异。例如,每个提供商都提供运行容器化工作负载的选项。但每个提供商的做法略有不同,底层运行时的配置方式略有不同,尤其是 SLA 也有所不同。比较一下Google Cloud Run 的 SLA和Azure 的容器实例。
我们可能会想:“如果谷歌提高其云产品的价格会发生什么?如果 Azure 弃用我们正在使用的数据库产品会发生什么?”
一个常见的建议似乎是:“让我们构建一个与云无关的平台!让我们使用 Kubernetes 作为隔离层。”这个想法似乎很简单。我们使用 Kubernetes 作为抽象层,并且不依赖任何特定于提供商的工具。
我们将所有服务构建为容器化工作负载,即OCI镜像(有时也称为 Docker 镜像)。我们将它们部署到云供应商提供的 Kubernetes 产品中。每当我们需要某些功能时,容器就是答案。这将我们的应用程序与供应商隔离开来。原则上,只要 Kubernetes 可用,我们就可以更换供应商。
容易吗?也许不容易。
Kubernetes 数据中心
我们将 OCI 图像用于一切,不依赖任何其他东西。
- 需要数据库吗?容器中的 PostgreSQL
- 需要对象存储吗?Minio 容器
- 需要监控吗?容器中的 ELK 堆栈
- 需要消息传递?容器中的 RabbitMQ
- 需要 XYZ 吗?XYZ 放在容器里
这导致了下图所示的结果。
我们需要自己托管许多基础设施组件。如果不能依赖云提供商的 IAM 解决方案,那么就必须自行部署Keycloak。
切换平台
从 AWS 迁移到 Azure 意味着从 AWS 的EKS迁移到 Azure 的AKS。其余部分可以按原样从 AWS 迁移到 Azure,不会造成太大影响。这能有多难?毕竟,我们只改了一个字母 ;)。
甚至可以说,只要我们能自己搭建 Kubernetes 集群,我们就可以更换供应商。几个虚拟机就足够了。这应该在每个平台上都能实现。
那么,一切都还好,对吧?我们接下来会看到,事情可能比这更复杂。
云不可知论的幻觉
这个想法太诱人了。如果它真的像描述的那样有效,那么这篇文章就不存在了。
重温云销售宣传
企业迁移到云端的原因之一是减少工程工作量。使用SaaS数据库、SaaS 消息代理或 SaaS Kubernetes 非常有效,原因如下:
- 我们可以减少运营工作量。供应商负责修补、更新等工作。
- 我们可以专注于产品,而不是构建内部工程。或者换句话说,维护负载均衡器对我们的业务有什么帮助?
- 我们可以更快、更高效地行动。提供商可以扩展或缩减规模,只需触发云供应商的 API 即可使用新产品。
简而言之,我们重新聚焦于那些能够带来竞争优势的事情。我们的产品,而不是我们自己编写的 HTTP 负载均衡器。
如果我们考察一下云无关的方法,其含义就显而易见了。我们构建了一个自定义数据中心,而不是利用云提供商。我们没有使用云供应商提供的 SaaS 功能,而是创建了自己的——通常更糟糕的——模仿产品。我们非但没有减少工程工作量,反而增加了它。
所有重点组件都必须由我们的工程师部署、修补和维护。他们致力于修补数据库,而不是开发下一个伟大的功能。
但是,假设我们能够接受所有这些额外的努力。假设我们在 GCP 上仅使用虚拟机和 Kubernetes 构建开发环境是可以接受的。这包括强化和保护 Kubernetes,这本身就是一项艰巨的任务。
即使投入了这么多精力,我们仍然无法做到云不可知。让我们来讨论一些例子,先从显而易见的开始,然后再讨论那些可能不那么显而易见的。
基本功能
从数据中心的分布来看,全球云似乎并没有那么全球化。根据我们的业务,这可能是个问题,也可能不是。例如,如果我们为一家德国银行构建系统,那么我们必须满足 GDPR 的要求。这意味着我们不能随意在全球范围内使用任何功能。
例如,如果我们想服务整个非洲的客户,选择合适的供应商并不容易。AWS和Azure在南非有一定的业务,GCP也提供了一些 CDN 功能,但仅此而已。
因此,围绕可用数据中心构建架构是一种有漏洞的抽象。故障转移、弹性和延迟都取决于数据中心的位置。如果一家供应商提供的数据中心位置比另一家供应商少,那么我们就会被锁定。我们需要意识到这一点,并在从一个云迁移到另一个云时考虑其影响。
如果我们需要特殊的硬件,例如专用服务器,我们很快就会发现,无限的规模也可能是一个问题。
联网
谈到网络,云供应商的不同功能常常被忽视。同样,从总体来看,这些供应商即使不完全相同,看起来也大同小异。
以虚拟私有云(简称 VPC)的概念为例。与 AWS 和 Azure 不同,GCP 的虚拟私有云资源不绑定到任何特定区域。它们被视为全球资源。但是,VPC 是GCP 项目的一部分。GCP 使用项目来组织相关资源,例如应用程序所需的一切。除非防火墙规则禁止,否则 VPC 内的所有子网都可以通信。如果我们想要集中控制通信,我们可以引入所谓的共享 VPC,其中多个项目利用同一个 VPC。这种架构不易转移到其他提供商。
数据引力井
谈论数据和云时,至少有两个方面需要考虑:成本和数据亲和性。我们先来讨论一下成本。
以 Azure 及其数据传输定价为例。将数据迁移到Azure 数据中心通常是免费的。我们可以上传数 TB 的数据,而无需支付一分钱。
另一方面,将数据从数据中心(出口)移出可能会很昂贵。假设我们在 Azure 数据中心存储了 1PB 的数据,并希望将其迁移到其他地方。使用数据传输定价页面,我们最终会得到一个五位数的数字(坦白说,这是一个简化的计算方法。如果我们要迁移这种规模的数据,云供应商会提供更好、更经济高效的方法。云端的定价计算非常复杂,需要数学博士学位才能理解)。
重点是:一旦数据进入特定的数据中心,将其导出的成本很快就会变得昂贵,因此应该做好规划。
我们要讨论的第二个方面是数据引力或数据亲和性。其理念是,应用程序倾向于靠近它们所需的数据。如果客户数据位于 GCP Spanner 实例中,那么应用程序很可能也会在 GCP 上运行。当然,我们可以将数据存储在 GCP 中,并将应用程序托管在 AWS 上。但这种架构有很多缺点。安全性、成本、延迟等等因素都可能使这种方法不可取。
安全
安全是任何重要架构的支柱,尤其是在云端。所有主流供应商都对此高度重视。AWS、Azure 和 GCP 都面临同样的困境。任何一家供应商的安全漏洞都会对其他所有供应商的信任产生负面影响。这种理解就是谷歌所说的“共同命运”。云提供商最重要的职责是:确保安全并帮助客户构建安全的系统。
然而,每个供应商的安全措施略有不同。当然,他们都有IAM方法。他们都支持加密。他们都允许某种形式的机密计算。
但如果仔细观察,就会发现其中的差异。安全云架构的设置方式使用相同的概念(访问控制、边界……),但实现方式却截然不同。让我们考虑两个示例:密钥管理和特权身份管理。
所有提供商都支持某种形式的自带密钥 (BCR)。我们可以使用自己的密钥进行解密和加密。这些密钥通常存储在提供商的数据中心。但是,如果我们想保留对密钥的控制权,而不是将其存储在外部数据中心,该怎么办?这时外部密钥管理就派上用场了。使用这种方法,我们可以控制密钥的位置和分发。在撰写本文时,GCP 的产品比 AWS 和 Azure 更胜一筹,提供了诸如密钥访问理由 (KEY Access Justifications)之类的功能。
特权身份管理(Privileged Identity Management,简称 PIM)允许用户在无需始终拥有“root”或“admin”权限的情况下执行特权操作。简而言之,我们会在一段时间内提升用户的权限。例如,“好的,您可以在接下来的 15 分钟内深入数据库以调试此问题”。同样,在撰写本文时,只有Azure在其云中提供此功能。AWS 和 GCP 则需要额外的工具。
这些功能可能会发生变化。供应商往往会填补其产品组合中的空白。然而,我们需要意识到,每个云供应商的功能各不相同,尤其是在涉及安全等跨领域问题时。
说到底,具体细节其实并不重要。安全功能会渗透到我们系统环境的所有其他方面。
基础设施即代码
使用 Terraform 或 CDK 等工具来自动化基础设施环境被认为是一种良好实践。这有助于减少配置漂移,并提高基础设施的整体质量。然而,底层云提供商的功能往往会被嵌入到基础设施代码中。
将基础设施代码从 GCP 迁移到 Azure 实际上意味着重写一切。当然,概念或高层架构可能相似。但对于代码而言,这类似于将应用程序从 Java 迁移到 Go-Lang。在 Terraform 中,从 GCP 提供商切换到 Azure 提供商意味着放弃一切。
幻觉
真正的云无关方法充其量只是一种幻想。当然,我们可以将符合 OCI 标准的镜像(请阅读“Docker 镜像”)从一个 Kubernetes 环境迁移到另一个。但这只是系统架构的一小部分。需要强调的是,Google 的 Kubernetes Engine 和 Azure 的 Kubernetes 服务的功能并不相同。
还记得JEE吗?同样的承诺。宣传语是:我们可以构建企业 Java 应用程序,将其打包为企业应用程序存储库 (EAR),然后在 JBoss、WebSphere 和 Weblogic 上运行。然而,这最终只是一句空话,充满了技术挑战。一次构建,随处运行?更确切地说,一次构建,随处调试。
那么我们能做什么呢?
应对锁定的策略
了解问题的范围
首要且最重要的事情是记录我们正在使用的物品。如果我们想做出明智的决策并权衡利弊,就需要了解正在使用哪些产品以及使用的原因。这项工作必须从一开始就自动化并强制执行。事后清理非常困难,而且可能无法形成完整的清单。
标签、标记和综合自动化是关键。
顺便说一句,无论锁定讨论如何,维护库存都很重要。在公有云中,我们很容易忘记自己正在使用什么。
更喜欢松散耦合的架构
一些架构指导方针可以减轻供应商锁定的痛苦。
我们可以通过遵循基本原则来缓解锁定。松耦合架构之所以流行是有原因的。遵循这一原则,我们可以构建允许替换单个组件的系统。例如,如果我们将对 GCP 的Pub/Sub的依赖项迁移到特定组件,那么迁移到 AWS 则需要用新版本的AWS SNS替换该组件。
Messaging Facade是我们与供应商无关的服务的唯一直接依赖项。从 GCP 迁移到 AWS 意味着构建和使用不同的适配器。服务本身无需更改。
每当需要对特定产品产生硬依赖时,我们都会构建外观。这可以将在供应商之间迁移时的影响降至最低。十二因素方法论中概述的理念在这种情况下非常有用。但是,这是一个重要的问题,我们需要了解底层的 SLA,这将影响我们的设计。99.9% 和 99.95% 的正常运行时间之间存在很大差异。同样,代码中不可见的潜在锁定也存在。
如果我们考虑数据架构,我们也可以运用同样的想法。供应商针对 SQL 数据库、文档存储或键值对等基础用例,提供的解决方案大体相当。如果我们使用不带边缘技术的标准数据库,风险就会降低。我们可以相当肯定,在各大主流云平台上都能找到类似 MongoDB、PostgreSQL 和 Kafka 的数据库。
这甚至可能适用于网络。我们可以设计网络架构,使其能够在提供商之间迁移。我们需要注意差异,例如 VPC 的工作方式。但其他构建模块,例如网关或子网,则非常相似。如上所述,特定功能可能会泄露,但如果我们遵循这些建议,其影响将会降低。
再次强调,我们需要阅读 SLA。我们需要了解产品的限制和优势。并非所有 SQL 数据库都支持 100 TB 的数据。并非所有负载均衡器都一样。
战略和战术锁定
如果我们想利用云提供商的功能,那么就无法避免锁定。
我们希望减少工程量。
我们希望提高质量和安全性。
我们希望创新。
因此,我们从战略上来处理这个问题。
我们确定了必须将锁定降至最低的领域。我们使用上面概述的“外观”方法。我们只使用在其他平台上有对应产品的产品。
如果我们需要 SQL 数据库,我们会选择 GCP Cloud SQL,而不是 GCP 的 Cloud Spanner。Cloud SQL 是托管的 PostgreSQL 或 MySQL,类似于 Azure Database for PostgreSQL。
运行时也是如此。如果我们使用容器,我们可以使用 Google 的 GKE,因为 AWS 上已经有类似的产品,例如 Amazon EKS。我们甚至可以使用无服务器的 Google Cloud Run,因为它基于KNative,我们也可以将其移植到 Azure 或 AWS。
另一方面,我们或许可以通过使用并依赖其他平台上不可用的产品来满足需求。以谷歌的 BigTable 为例。它与亚马逊的 DynamoDB 相当,可比但不完全相同。在这种情况下,我们应该避免使用 BigTable 吗?也许不应该。我们可以问问自己,重建使用 BigTable 的组件以使其与 DynamoDB 兼容有多难。我们应该尝试给出一个具体的数字。“我们需要一个 Sprint 才能从 BigTable 迁移到 DynamoDB”。这个客观的数字使我们能够做出明智的判断,判断锁定 BigTable 是否具有经济意义。
再次强调,拥有完善的库存至关重要。如果我们不完全了解谁在使用什么,就无法做出这些判断。
提前制定退出策略
这一点虽然看似微不足道,但却至关重要。我们需要先制定退出策略。以上提到的大多数问题都必须从一开始就着手解决。否则,这些建议可能会非常昂贵,甚至无法实施。
背水一战地制定退出策略并非明智之举。我们需要仔细考虑各种选择。我们必须首先思考“如果谷歌在未来6个月内关闭其云业务,会发生什么?”,并明确必要的行动。对锁定风险有一个大致的估计,总比毫无头绪地仓促行事要好。
我们一定不要忘记定期回顾和更新我们的退出策略。也许我们正在使用新产品,或者供应商推出了新功能。这些也必须纳入我们的策略中。否则,退出策略就会被束之高阁,从制定的那一刻起就过时了。
概括
正如我们所见,构建一个完全云无关的系统即使并非不可能,也是困难的。即使如此,其经济效益也值得怀疑。战略性地处理锁定问题更为明智。我们需要意识到锁定及其相关成本。一个良好且自动化的库存系统是先决条件。没有什么比意外发现应用程序由于意外的依赖关系而无法从 AWS 迁移到 Azure 更糟糕的了。
有多种方法可以构建支持在提供商之间移动的系统。
建立全面的库存
首先,我们需要确保了解我们在说什么。拥有自动化库存至关重要。我们必须先搞定这一点,然后才能做其他事情。
关注共同能力
如果我们不需要 Cloud Spanner 的某些特殊功能,那就不要用它。如果 PostgreSQL 的功能能够满足我们的需求,那么也许我们应该选择 PostgeSQL。
更喜欢松散耦合的架构
我们提到了外观和适配器。没什么值得大书特书的。但成熟且优秀的模式才能成就优秀的架构。
运行实验
我们可能不知道移动数据意味着什么。我们可能不知道从 Pub/Sub 切换到 SNS 意味着什么。进行实验和尝试是厘清这些问题的唯一方法。想法固然好,但运行代码才是关键。
要有策略
在实施锁定之前,务必仔细考虑。在陷入困境之前,务必了解各种选择。根据数据选择锁定方案。锁定的成本是多少?不锁定并构建定制解决方案的机会成本又是多少?
这些建议都不是灵丹妙药,也无法避免被锁定。我们希望使用云提供商的产品,但同时也希望保持灵活性。我们希望成为意见一致的合作伙伴。
现实地对待锁定及其影响比陷入简单的与云无关的解决方案的陷阱更有用。
这不仅仅是“使用 Kubernetes 就大功告成了”。
鏂囩珷鏉ユ簮锛�https://dev.to/koenighotze/cloud-agnostic-architecture-2ojo