likes
comments
collection
share

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

作者站长头像
站长
· 阅读数 19

本章内容涵盖:

  1. 云和云计算模型是什么?
  2. 云原生的定义是什么?
  3. 云原生应用程序的特征是什么?
  4. 支持云原生的文化和实践是什么?
  5. 何时以及为什么要考虑云原生方法?
  6. 云原生应用程序的拓扑和架构。

云原生应用程序是高度分布式的系统,部署在云中并具有很强的适应性。这些系统由多个通过网络通信的服务组成,在动态环境中部署,其中一切都在不断变化。

在深入研究技术之前,定义什么是云原生至关重要。与我们领域的其他时髦词汇(例如敏捷、DevOps或微服务)一样,云原生有时被误解,可能会导致混淆,因为它对不同的人意味着不同的事情。

在本章中,我将为您提供本书其余部分所需的概念工具。我将首先定义云原生的含义,以及应用程序被认定为云原生应用的条件。我将解释云原生应用程序的特性,研究云计算模型的特点,并讨论何时以及为什么要考虑迁移到云上。我还将介绍云原生拓扑和架构的一些基本概念。图1.1显示了本章中将要涵盖的不同内容,以定义和评估云原生系统。在本章结束时,您将准备好开始使用Spring构建云原生应用程序,并将它们部署到Kubernetes上。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

什么是云原生?

在2010年5月25日,云计算行业的资深人士保罗·弗里曼特尔(Paul Fremantle)在他的博客上发表了一篇名为《云原生》的文章。他是最早使用“云原生”这个术语的人之一。在当时,微服务、Docker、DevOps、Kubernetes和Spring Boot等概念和技术尚未出现,弗里曼特尔与WSO2团队一起讨论了“应用程序和中间件在云环境中良好运行”的要素,即成为云原生。

弗里曼特尔解释的关键概念是,云原生应用程序应该专门为云设计,并具有利用云环境和云计算模型的特性。您可以将传统应用程序(设计为在本地运行)迁移到云上,这通常称为“搬迁和转移”,但这并不使应用程序成为云原生。接下来我们看看什么才能算得上是云原生。

云原生的三个P:

应用程序专门为云而设计是什么意思?云原生计算基金会(CNCF)在其云原生定义中回答了这个问题:

云原生技术使组织能够在现代动态环境(如公共云、私有云和混合云)中构建和运行可扩展的应用程序。容器、服务网格、微服务、不可变基础架构和声明式API是这种方法的典型代表。

这些技术实现了松耦合的系统,这些系统具有弹性、易管理和可观察的特点。结合强大的自动化,它们允许工程师频繁且可预测地进行高影响的变更,并减少不必要的操作负担。

根据这个定义,我确定了三个要点,我喜欢称之为“云原生的三个P”:

  • 平台(Platforms):云原生应用程序在基于动态分布式环境的平台上运行,例如公共云、私有云或混合云。

  • 特性(Properties):云原生应用程序的设计目标是可扩展、松耦合、具有弹性、易管理和可观察。

  • 实践(Practices):围绕云原生应用程序的实践包括自动化、持续交付和DevOps,其中强大的自动化结合频繁且可预测的变更。

在接下来的章节中,我将进一步探讨这些概念。但首先,我想让您注意到云原生的定义与任何特定的实现细节或技术无关。CNCF在其定义中提到了一些例子,比如容器和微服务,但它们只是示例。在开始迁移到云上时常见的一个误解是,您必须采用微服务架构,构建容器,并将它们部署到Kubernetes。这是不正确的。弗里曼特尔在2010年的文章证明了这一点。他当时没有提到这些技术,因为它们当时还不存在。然而,他描述的应用程序不仅仍被认为是云原生的,而且八年后也符合CNCF给出的定义。

云和云计算模型

在专注于主要角色——云原生应用程序——之前,我想通过描述云原生应用程序运行的背景来为您设定场景:即云环境(图1.2)。在本节中,我将定义云以及其主要特征。毕竟,如果云原生应用程序被设计为在云环境中良好运行,我们应该了解这是一种怎样的环境。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

云是支持按照云计算模型向消费者提供计算资源的IT基础设施。美国国家标准与技术研究所(NIST)对云计算进行了如下定义:

云计算是一种模型,它可以实现无处不在、便利、按需的网络访问,访问共享的可配置计算资源池(如网络、服务器、存储、应用程序和服务),并且这些资源可以通过最小的管理工作或服务提供商的交互而快速配置和释放。

就像你从供应商那里获取电力而不是自己发电一样,通过云,您可以将计算资源(例如服务器、存储和网络)作为一种商品获得。

云提供商负责管理底层的云基础设施,因此消费者不需要担心像机器或网络这样的物理资源。将公司迁移到云上后,它们可以通过网络(通常是互联网)获取所有所需的计算资源,通过一组API,它们可以按需自助式地进行资源的配置和扩展。

弹性是该模型的主要特点之一:根据需求,计算资源可以动态地进行配置和释放。

弹性是系统根据工作负载变化能够自动配置和取消配置资源的能力,以便在任何时刻可用资源尽可能与当前需求相匹配。

传统的IT基础设施无法提供弹性。公司必须计算所需的最大计算能力,并设置一个支持该能力的基础设施,即使大部分资源只在某些时候使用。通过云计算模型,计算资源的使用情况被监控,消费者只需支付实际使用的资源。

对于云基础设施应该位于何处以及由谁来管理并没有严格的要求。有几种部署模型可供提供云服务。主要的模型包括私有云、公共云和混合云。

  • 私有云:为单个组织提供的云基础设施。它可以由组织自身或第三方进行管理,并可以在企业内部或外部进行托管。对于处理敏感数据或高度关键系统的组织,私有云通常是首选。它也是具有完全控制基础设施符合特定法律和要求(如通用数据保护条例(GDPR)或加州消费者隐私法(CCPA))的常见选择。例如,银行和医疗保健提供商可能会建立自己的云基础设施。

  • 公共云:提供给公众使用的云基础设施。通常由云提供商拥有和管理,并托管在提供商的设施中。公共云服务提供商的例子包括亚马逊网络服务(AWS)、微软Azure、谷歌云、阿里云和DigitalOcean等。

  • 混合云:由任何前述类型的两个或更多不同的云基础设施组成,它们被绑定在一起,作为一个单一的环境提供服务。

图1.3描述了五种主要的云计算服务模型,每个模型所提供的平台内容以及提供给消费者的抽象层次。例如,在基础设施即服务(IaaS)模型中,平台提供和管理计算、存储和网络资源,而消费者负责配置和管理虚拟机。选择哪种服务模型应由消费者对基础设施的控制程度以及他们需要管理哪种类型的计算资源决定。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

基础设施即服务(IaaS)

在基础设施即服务(IaaS)模型中,消费者可以直接控制和配置诸如服务器、存储和网络等资源。例如,他们可以配置虚拟机并安装操作系统和库等软件。尽管这种模型已经存在一段时间,但是2006年亚马逊通过Amazon Web Services (AWS)使其受到广泛关注并普及开来。一些IaaS提供商的例子包括AWS Elastic Compute Cloud (EC2)、Azure Virtual Machines、Google Compute Engine、阿里巴巴的虚拟机和DigitalOcean的Droplets。

容器即服务(CaaS)

使用容器即服务(CaaS)模型,消费者无法控制基本的虚拟化资源。相反,他们会进行容器的配置和管理。云提供商负责提供满足这些容器需求的底层资源,例如启动新的虚拟机并配置网络,使其可以通过互联网访问。Docker Swarm、Apache Mesos和Kubernetes是用于构建容器平台的工具的例子。所有主要的云提供商都提供托管的Kubernetes服务,它已成为CaaS提供的事实标准技术:Amazon Elastic Kubernetes Service (EKS)、Azure Kubernetes Service (AKS)、Google Kubernetes Engine (GKE)、阿里巴巴的Kubernetes容器服务 (ACK) 和DigitalOcean Kubernetes。

平台即服务(PaaS)

在平台即服务(PaaS)模型中,平台提供基础设施、工具和API,供开发人员用于构建和部署应用程序。例如,作为开发人员,您可以构建一个Java应用程序,将其打包为Java Archive(JAR)文件,然后部署到符合PaaS模型的平台上。平台提供Java运行时和其他所需的中间件,还可以提供额外的服务,如数据库或消息系统。PaaS提供的一些例子包括Cloud Foundry、Heroku、AWS Elastic Beanstalk、Azure App Service、Google App Engine、阿里巴巴的Web App Service和DigitalOcean App Platform。近年来,供应商们纷纷将重心转向使用Kubernetes来为开发人员和运维人员构建新的PaaS体验。这一代新服务的例子包括VMware Tanzu Application Platform和RedHat OpenShift。

函数即服务(FaaS)

函数即服务(FaaS)模型依赖于无服务器计算,使消费者能够专注于实现其应用程序的业务逻辑(通常以函数形式),而平台负责提供服务器和其他基础设施。无服务器应用程序是通过事件触发的,例如HTTP请求或消息。例如,您可以编写一个函数,每当从消息队列中可用时,该函数就会分析数据集并根据某些算法计算结果。商业FaaS提供的例子包括亚马逊的AWS Lambda、微软的Azure Functions、谷歌的Google Cloud Functions和阿里巴巴的Functions Compute。开源FaaS提供的例子包括Knative和Apache OpenWhisk。

软件即服务(SaaS)

在云计算服务模型中,具有最高抽象级别的服务是软件即服务(SaaS)。在这个模型中,消费者作为用户访问应用程序,而云提供商则负责管理整个软件和基础设施栈。许多公司构建他们的应用程序,使用CaaS或PaaS模型来运行它们,然后将它们的使用权作为SaaS销售给最终客户。SaaS应用程序的消费者通常使用像Web浏览器或移动设备这样的轻量级客户端来访问它们。一些作为SaaS提供的应用程序的例子包括Proton Mail、GitHub、Plausible Analytics和Microsoft Office 365。

云原生应用程序的特性

场景已经设定:你正在云环境中。那么,如何设计应用程序以充分利用云环境的特性呢?

CNCF确定了云原生应用程序应具备的五个主要特性:可扩展性、松耦合性、弹性、可观测性和可管理性。云原生是一种构建和运行具备这些特性的应用程序的方法论。Cornelia Davis总结说“云原生软件的定义关乎你如何进行计算,而不关乎在哪里进行计算。”换句话说,云关乎在哪里,而云原生关乎如何。

我已经介绍了在哪里的部分:即云。现在,让我们继续探索如何构建云原生应用程序。供快速参考,图1.4列出了这些特性以及简短的描述。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

可扩展性(Scalability)

云原生应用程序被设计为具备可扩展性,这意味着它们能够支持增加的工作负载,如果提供额外的资源。根据这些额外资源的性质,我们可以区分垂直可扩展性和水平可扩展性:

  • 垂直可扩展性 — 垂直扩展,也称为向上或向下扩展,意味着向计算节点(例如CPU或内存)添加或移除硬件资源。这种方法是有限的,因为不可能无限制地添加硬件资源。另一方面,应用程序不需要明确地设计为可垂直扩展或缩减。

  • 水平可扩展性 — 水平扩展,也称为向外或向内扩展,意味着向系统添加或移除更多的计算节点或容器。这种方法不像垂直可扩展性那样有限,但它要求应用程序能够具备可扩展性。

传统系统通常会在工作负载增加时采用垂直可扩展性。添加CPU和内存是一种常见的方法,以便应用程序能够在不重新设计其可扩展性的情况下支持更多的用户。在特定场景下,这仍然是一个不错的选择,但在云环境中,我们需要另一种方法。

在云环境中,一切都是动态的,不断变化的,因此更倾向于采用水平可扩展性。得益于云计算模型提供的抽象级别,我们可以轻松地启动新的应用程序实例,而不是增加已经运行的机器的计算能力。由于云具有弹性,我们可以快速动态地扩展和缩减应用程序实例。我在前文讨论了弹性作为云的主要特性之一:根据需求,计算资源可以主动配置和释放。可扩展性是实现弹性的前提条件。

图1.5显示了垂直可扩展性和水平可扩展性之间的区别。在第一种情况下,我们通过向现有虚拟机添加更多资源来进行扩展。在第二种情况下,我们添加另一个虚拟机,来帮助现有虚拟机处理额外的工作负载。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

当我们讨论Kubernetes时,你会发现平台(无论是CaaS、PaaS还是其他什么)会动态地负责应用程序的扩展和收缩。作为开发者,我们有责任设计可扩展的应用程序。实现可扩展性的主要障碍是应用程序的状态,它实质上是一个关于应用程序是否具有状态或无状态的问题。在整本书中,我将介绍构建无状态应用程序并使其能够无问题扩展的技术。其中包括向你展示如何将应用程序状态从Spring推送到像PostgreSQL和Redis这样的数据存储中。

松耦合性(Loose coupling)

松耦合性是一个系统中的各部分尽可能少地相互知晓的重要特性。其目标是使每个部分能够独立演化,这样当其中一个发生变化时,其他部分不需要相应地进行更改。

对于软件工程而言,耦合性及其对应的内聚性是几十年来的重要概念。将系统分解为模块(模块化)是一种良好的设计实践,每个模块尽量减少对其他部分的依赖(松耦合),并封装代码以便相关的变更在一起(高内聚性)。根据架构风格,一个模块可以是一个整体组件,也可以是一个独立的服务(例如,微服务)。不管哪种方式,我们应该努力实现适当的模块化,即松耦合和高内聚。

Parnas确定了模块化的三个好处:

  • 管理上的好处:由于每个模块都松散地耦合,负责该模块的团队不需要花费太多时间协调和与其他团队进行沟通。
  • 产品的灵活性:整体系统应该具有灵活性,因为每个模块都独立演化。
  • 可理解性:人们应该能够理解并处理一个模块,而不需要研究整个系统。

上述好处通常与微服务相关,但事实是,你不需要微服务来实现它们。在过去的几年里,许多组织决定从单块应用迁移到微服务。其中一些失败是因为缺乏适当的模块化。当单块应用由紧密耦合、非内聚的组件组成时,迁移到微服务时也会产生紧密耦合、非内聚的微服务系统,有时被称为分布式单块应用。我认为这个名称不好,因为它暗示单块应用在定义上就是由紧密耦合、非内聚的组件组成的。这并不是事实。架构风格并不重要:一个不良的设计就是一个不良的设计。实际上,我喜欢Simon Brown提出的"模块单块应用"这个术语,以增强人们对单块应用可以促进松耦合和高内聚的认识,并且无论是单块应用还是微服务,都可能最终成为"大泥球"。

在整本书中,我将讨论一些在应用程序中强制实现松耦合的技术。特别是,我们将采用基于服务的架构,专注于构建具有清晰接口以相互通信的服务,最小化对其他服务的依赖,同时实现高内聚性。

弹性(Resilience)

如果一个系统在发生故障或环境变化时仍能提供其服务,那么该系统就具备弹性。弹性是“硬件-软件网络在面对故障和对正常运行的挑战时,能够提供和维持可接受水平的服务能力。”7

在构建云原生系统时,我们的目标是确保我们的应用程序始终可用,无论基础设施还是我们的软件是否出现故障。云原生应用程序在一个不断变化的动态环境中运行,故障会时有发生。这是无法避免的。过去,我们通常将变化和故障视为例外情况,但对于像云原生这样高度分布式的系统而言,变化并不是例外情况:它们是规则。

在讨论弹性时,值得定义三个重要概念:故障、错误和失效:

  • 故障(Fault)—故障是在软件或基础设施中产生不正确的内部状态的缺陷。例如,一个方法调用返回了null值,即使其规范要求返回非null值。

  • 错误(Error)—错误是系统预期行为与实际行为之间的差异。例如,由于前面的故障,抛出了NullPointerException。

  • 失效(Failure)—当故障被触发并导致错误时,可能会发生失效,使系统无响应且无法按照其规范行为。例如,如果未捕获NullPointerException,该错误将导致失效:系统对任何请求都以500响应进行回应。

故障可能变成错误,进而引发失效,因此我们应该设计应用程序以具备容错能力。弹性的一个重要方面是确保失效不会级联到系统的其他组件,而是保持隔离,直到修复为止。我们还希望系统能够自我修复或自愈,而云模型可以实现这一点。

在整本书中,我将向你展示一些容忍故障的技术,并防止其影响传播到系统的其他部分,从而避免故障的扩散。例如,我们将使用断路器、重试、超时和速率限制等模式。

可观察性(Observability)

可观察性(Observability)是来自控制论世界的一个属性。如果你考虑一个系统,可观察性是衡量你能从系统的外部输出推断其内部状态的程度。在软件工程的上下文中,该系统可以是一个单一的应用程序或整个分布式系统。外部输出可以是指标、日志和追踪等数据。图1.6显示了可观察性的工作原理。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

Twitter的可观察性工程团队确定了四个可观察性的支柱:

  • 监控(Monitoring)—监控是测量应用程序特定方面以获取有关其整体健康状况和故障识别的信息。在本书中,你将学习有关Spring Boot Actuator的有用监控功能,并将Prometheus与Spring集成,以导出有关应用程序的相关指标。

  • 报警/可视化(Alerting/visualization)—收集有关系统状态的数据只有在用于采取某些操作时才有用。当监控应用程序时发现故障时,应该触发警报,并采取一些措施来处理它。使用特定的仪表板可视化收集的数据,并绘制相关的图形,以便更好地了解系统的行为。本书将展示如何使用Grafana来可视化从云原生应用程序收集的数据。

  • 分布式系统跟踪基础设施(Distributed systems tracing infrastructure)—在分布式系统中,仅跟踪每个子系统的行为是不够的。追踪数据在不同子系统之间的流动是至关重要的。在本书中,你将集成Spring与OpenTelemetry,并使用Grafana Tempo来收集和可视化追踪数据。

  • 日志聚合/分析(Log aggregation/analytics)—跟踪应用程序的主要事件对于推断软件的行为并在出现问题时进行调试至关重要。在云原生系统中,日志应该被聚合和收集,以便更好地了解系统的行为,并确保能够运行分析,从中获取信息。在整本书中,我会更多地讨论日志。你将使用Fluent Bit、Loki和Grafana来收集和可视化日志,并学习在云原生环境中的最佳日志记录实践。

可管理性(Manageability)

在控制论中,可观察性的对应物是可控性——外部输入在有限时间内改变系统的状态或输出的能力。这个概念引导我们来讨论云原生的最后一个主要特性:可管理性。

再次借鉴控制论的思想,我们可以说可管理性衡量的是外部输入如何以容易和高效的方式改变系统的状态或输出。用较少数学术语来说,可管理性是在不需要改变应用程序代码的情况下修改应用程序行为的能力。这与可维护性不同,可维护性衡量的是在内部通过改变代码来轻松高效地修改系统。图1.6展示了可管理性的工作原理。

可管理性的一个方面是在保持整个系统运行的同时部署和更新应用程序。另一个方面是配置,这将在整本书中详细讨论。我们希望使云原生应用程序可配置,以便我们可以在不改变其代码并构建新版本的情况下修改其行为。通常,我们会配置可配置的设置,如数据源URL、服务凭据和证书。例如,根据环境,您可以使用不同的数据源:一个用于开发,一个用于测试,一个用于生产。其他类型的配置可能是特性标志,用于确定是否在运行时启用特定功能。我将在整本书中向您展示配置应用程序的不同策略,包括使用Spring Cloud Config Server、Kubernetes ConfigMaps和Secrets以及Kustomize。

可管理性不仅关注于特定变更本身,还关注于如何轻松高效地应用这些变更。云原生系统是复杂的,因此设计应用程序能够适应功能、环境和安全性的不断变化的要求非常重要。由于这种复杂性,我们应该通过自动化来尽可能地管理,这也导致了云原生的最后一个主要特性:实践。

支持云原生的文化和实践

本节将着重讨论CNCF提供的云原生技术定义中的最后一句话:“结合强大的自动化,它们使工程师能够频繁、可预测地进行高影响的变更,同时尽量减少重复劳动。”我将讨论三个概念:自动化、持续交付和DevOps(图1.7)。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

自动化

自动化是云原生的核心原则。其思想是通过自动化重复的手动任务来加速云原生应用程序的交付和部署。许多任务可以自动化,从构建应用程序到部署它们,从供应基础设施到管理配置。自动化的最重要优势是使流程和任务可重复,从而使整个系统更加稳定和可靠。手动执行任务容易出错且费时。通过自动化,我们可以得到更可靠、更高效的结果。

在云计算模型中,计算资源以自动化、自助服务的方式进行供应,可以弹性地增加或减少。云的两个重要自动化类别是基础设施编码和配置管理。我们称之为基础设施即代码和配置即代码。

Martin Fowler将基础设施即代码定义为“通过源代码定义计算和网络基础设施的方法,然后可以像任何软件系统一样对待它”。云提供商提供便捷的API用于创建和供应服务器、网络和存储。通过使用像Terraform这样的工具自动化这些任务,将代码放入源代码控制,并应用用于应用程序开发的相同测试和交付实践,我们可以获得更可靠和可预测的基础设施,其可复现性更高、更高效,风险更小。一个简单的自动化任务示例可能是创建一个具有8个CPU、64 GB内存和Ubuntu 22.04作为操作系统的新虚拟机。

在供应了计算资源之后,我们可以管理它们并自动化它们的配置。引用之前的定义,配置即代码是通过源代码定义计算资源配置的方法,可以像任何软件系统一样对待它。

使用像Ansible这样的工具,我们可以指定如何配置服务器或网络。例如,在从前面的段落中供应了Ubuntu服务器之后,我们可以自动化安装Java Runtime Environment (JRE) 17并从防火墙打开端口8080和8443的任务。配置即代码同样适用于应用程序配置。

通过自动化所有基础设施供应和配置管理任务,我们可以避免不稳定、不可靠的特殊服务器。当每个服务器都是手动供应、管理和配置时,结果是一个雪花服务器:一个脆弱、独特的服务器,无法复现且更改风险较大。自动化有助于避免雪花服务器,而是采用凤凰服务器:所有作用于这些服务器的任务都是自动化的,每个更改都可以在源代码控制中跟踪,降低风险,每个设置都是可复现的。通过将这个概念发挥到极致,我们实现了所谓的不可变服务器,这也是CNCF在其云原生定义中提到的不可变基础设施。

注意:在比较传统的雪花基础设施(需要很多关注和细心照料,类似于宠物)和不可变基础设施或容器(特点是可替换和可丢弃,类似于牛群)时,您可能听过“宠物与牛”的表达方式。在本书中我不会使用这个表达方式,但在讨论这个主题时,有时会使用这个表达方式,所以您需要知道这一点。

在初始化供应和配置后,不可变服务器不再进行更改:它们是不可变的。如果需要进行任何更改,它们会定义为代码并进行交付。然后从新代码供应和配置新的服务器,同时销毁之前的服务器。

例如,如果您当前的基础设施由Ubuntu 20.04服务器组成,并且您想要升级到Ubuntu 22.04,您有两个选择。第一个选项是通过代码定义升级,然后运行自动化脚本在现有机器上执行操作(凤凰服务器)。第二个选项是自动化供应运行Ubuntu 22.04的新机器,并开始使用这些新机器(不可变服务器),而不是对现有机器进行升级。

接下来的章节中,我将讨论构建和部署应用程序的自动化。

持续交付

持续交付是“一种软件开发纪律,使得软件可以随时发布到生产环境。”持续交付中,团队以短周期实现功能,确保软件可以可靠地随时发布。这样的纪律是实现“在短时间内频繁和可预测地进行高影响的更改,同时尽量减少额外工作”的关键,正如CNCF对云原生的定义所述。

持续集成(CI)是持续交付中的基础实践。开发人员持续地(至少每天一次)将更改提交到主线(主分支)。每次提交时,软件会自动进行编译、测试,并打包成可执行的构件(如JAR文件或容器映像)。其目的是在每次新更改后快速了解软件的状态。如果检测到错误,应立即修复,以确保主线始终是进一步开发的稳定基础。

持续交付(CD)基于CI,并致力于始终保持主线处于健康和可发布状态。在与主线集成的过程中生成可执行构件后,软件会部署到类似生产环境的环境中。它经历额外的测试来评估其可发布性,如用户验收测试、性能测试、安全测试、合规性测试以及可能增加软件可发布信心的其他测试。如果主线始终处于可发布状态,发布新版本的软件将成为业务决策而不是技术决策。

持续交付鼓励通过部署管道(也称为持续交付管道)自动化整个流程,正如Jez Humble和David Farley的基础书籍《持续交付》(Addison-Wesley Professional,2010)中所描述的那样。部署管道从代码提交到可发布结果,并且它是到生产环境的唯一途径。在本书中,我们将构建一个部署管道,以始终将我们应用程序的主分支保持在可发布状态。最后,我们将使用它在生产中自动部署应用程序到Kubernetes集群。

有时持续交付被误认为是持续部署。前者确保每次更改后,软件处于可以部署到生产环境的状态。何时进行实际部署是一个业务决策。而持续部署是在部署管道中增加一个最后步骤,以在每次更改后自动在生产环境中部署新版本。

持续交付不是关于工具,而是涉及组织中的文化和结构性变化。建立一个自动化的流水线来测试和交付应用程序并不意味着您正在进行持续交付。同样,使用CI服务器自动化构建并不意味着您正在进行持续集成。这将引导我们进入下一个主题,这个主题也常常被误认为与工具有关。

DevOps

DevOps是当今非常流行的一个词汇,但往往被误解。在转向云原生时,理解DevOps是一个重要的概念。

DevOps的起源非常特别。一个有趣的方面是,创造者最初并没有提供明确的定义。结果,很多人都有自己的解释,因此我们对DevOps的理解也不尽相同。

注意:如果您想了解更多关于DevOps起源的信息,建议观看YouTube上Ken Mugrage的演讲:“DevOps and DevOpsDays—Where it started, where it is, where it’s going”(mng.bz/Ooln)。

在所有的DevOps定义中,我认为Ken Mugrage(ThoughtWorks首席技术专家)提出的定义尤为信息丰富和有趣。他强调了我认为是DevOps的真正含义。

一个文化,在这个文化中,人们不论职位或背景如何,一起合作来构想、开发、部署和运营系统。

所以DevOps是一种文化,它关乎共同的目标和合作。开发人员、测试人员、运维专家和其他人,不论职位或背景如何,共同合作将创意带入生产并创造价值。

这意味着终结了孤立——不再有特性团队、QA团队和运维团队之间的隔阂。DevOps通常被认为是敏捷的自然延续,敏捷通过小团队频繁地向客户交付价值,为DevOps提供了条件。一个简洁的描述DevOps的方法是亚马逊首席技术官Werner Vogels在2006年还没有DevOps概念时所说的著名一句话:“你构建它,你运行它”。

定义了DevOps后,我会简要提到它不是什么:

  • DevOps并不意味着NoOps。常见的错误是认为开发人员负责运维,运维人员的角色消失。相反,它是一种合作。一个团队将包含两种角色,为从最初的创意到生产的整个产品所需的技能做出贡献。
  • DevOps不是工具。像Docker、Ansible、Kubernetes和Prometheus这样的工具通常被称为DevOps工具,但这是错误的。DevOps是一种文化。您不会通过使用特定工具将组织转变为DevOps组织。换句话说,DevOps不是一个产品,但工具是重要的促进因素。
  • DevOps不是自动化。尽管自动化是DevOps的重要组成部分,但自动化并不是它的定义。DevOps涉及开发人员和运维人员从最初的创意到生产的全过程合作,可能会自动化其中一些流程,例如持续交付。
  • DevOps不是一个角色。如果我们将DevOps视为一种文化或一种心态,很难理解DevOps角色的意义。然而,现在越来越多地需要DevOps工程师。通常当招聘人员搜索DevOps工程师时,他们寻找的是熟练掌握自动化工具、脚本编写和IT系统等技能的人员。
  • DevOps不是一个团队。组织如果不完全理解前面的观点,可能会保留与以前相同的孤立现象,只是用DevOps团队取代运维团队,或者更糟的是,只是增加一个新的DevOps团队。

在转向云原生时,开发人员和运维人员之间的合作至关重要。正如您可能已经注意到的,设计和构建云原生应用程序需要时刻牢记将这些应用程序部署的地方:云。与运维人员一起合作可以让开发人员设计和构建更高质量的产品。

虽然称为DevOps,但请记住,该定义不仅适用于开发人员和运维人员。相反,它泛指不论职位或背景的人。这意味着合作还涉及其他角色,如测试人员和安全专家(虽然我们可能不需要像DevSecOps、DevTestOps、DevSecTestOps或DevBizSecTestOps这样的新术语)。他们共同负责整个产品生命周期,是实现持续交付目标的关键。

云计算是否是您的最佳选择?

我们行业中最大的错误之一就是因为某项技术或方法是新的,而且每个人都在谈论它,所以决定采用它。关于公司将巨石应用迁移到微服务并最终导致灾难性失败的故事数不胜数。我已经解释了云和云原生应用程序的特性。这些应该为您提供一些指导。如果您的系统不需要这些特性,因为它没有这些特性试图解决的问题,那么“走向云原生”可能不是您项目的最佳选择。

作为技术人员,我们很容易陷入最新、最时髦、最闪亮的技术中。关键是要弄清楚特定的技术或方法是否能解决您的问题。我们将想法转化为我们提供给客户的软件,并为他们提供一些价值。这是我们的最终目标。如果某项技术或方法能帮助您为客户提供更多价值,您应该考虑采用它。如果它没有价值,但您还是决定采用它,那么您可能会面临更高的成本和许多问题。

何时将系统迁移到云端是一个好主意?为什么公司采用云原生方法?主要原因如图1.8所示,包括速度、规模、弹性和成本。如果您的业务愿景包括这些目标,并且面临着云技术试图解决的相同问题,那么考虑将系统迁移到云端并采用云原生方法是很好的选择。否则,留在现有的环境可能更好。例如,如果您的公司通过一个维护阶段的巨石应用程序提供服务,该应用程序不会进一步扩展新功能,并且在过去的十年中表现良好,那么可能没有理由将其迁移到云端,更不用说将其转换为云原生应用程序了。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

速度

在当今企业中,能够更快地交付软件是一个重要目标。尽快将想法转化为产品,从而缩短上市时间,是一个至关重要的竞争优势。在正确的时间以正确的想法进入市场,可能是成功与失败之间的区别。

顾客希望有更多的功能实现或错误修复,并且他们希望立即得到。他们不愿意等待六个月才能获得你的软件的下一个版本。他们的期望不断增加,而你需要一种方法来跟上他们。最终,关键在于为顾客提供价值,并确保他们对结果满意。否则,你的企业将无法在激烈的竞争中生存。

更快地、更频繁地交付不仅仅涉及竞争和顾客期限。这也涉及缩短反馈周期。频繁且小规模的发布意味着你可以更早地从顾客那里获得反馈。较短的反馈循环进一步降低了与你发布的新功能相关的风险。与其花费几个月的时间来实现完美的功能,不如尽早将其发布出去,从顾客那里获得反馈,并根据他们的期望进行调整。此外,较小的发布包含的更少的变更,从而减少了可能出现故障的部分数量。

灵活性也是必需的,因为顾客希望你的软件持续演进。例如,它应该足够灵活,支持新类型的客户端。如今,我们日常生活中越来越多的对象都连接到互联网,例如各种移动和物联网系统。你希望对任何未来的扩展和客户端类型都持开放态度,以便以新的方式提供业务服务。

传统的软件开发方法不支持这一目标。往往以大规模发布、缺乏灵活性和长周期发布为特征。与自动化任务、持续交付工作流和DevOps实践相结合的云原生方法有助于企业加快速度,缩短上市时间。

弹性

一切都在不断变化,故障时有发生。我们不再试图预测故障并将其视为例外情况。如我之前提到的,变化不是例外,而是常态。

客户希望软件能够全天候提供服务,并在发布新功能时立即进行升级。停机或故障可能直接导致损失和客户不满。它们甚至可能影响到组织的声誉,损害其未来的市场机会。

无论是基础设施还是软件出现故障,您的目标是确保系统的可用性和可靠性,即使仅处于降级操作模式。为确保可用性,您需要在故障发生时采取措施来处理它们,并确保整个系统仍然能够向用户提供服务。任何处理故障或类似升级的操作都不应导致停机。客户期望如此。

我们希望云原生应用具有弹性,并且云技术提供了实现弹性基础设施的策略。如果始终可用、安全和具有弹性是您业务的要求,云原生方法是一个不错的选择。而软件系统的弹性反过来又促进了速度:系统越稳定,您就越能安全地频繁发布新功能。

规模

弹性是关于根据负载情况来扩展你的软件。你可以扩展一个具有弹性的系统,以确保为所有客户提供适当的服务水平。如果负载比平常高,你需要启动更多服务实例来支持额外的流量。或者可能发生了一些糟糕的事情,导致一些服务出现故障,你需要能够启动新的实例来替代它们。

预测未来发生的情况是困难的,甚至是不可能的。仅构建可扩展的应用是不够的,你需要使它们能够动态扩展。每当负载很高时,你的系统应该能够动态、快速且无痛地扩展。当高峰期结束后,它应该再次缩减。

如果你的业务需要快速、高效地适应新客户,或者需要灵活性来支持新类型的客户(增加服务器的工作负载),云的本质结合云原生应用可以为你提供所需的所有弹性。

成本

作为一名软件开发人员,你可能不直接处理金钱,但在设计解决方案时考虑成本是你的责任。云计算模型通过其弹性和按需付费政策帮助优化IT基础设施成本。不再需要一直运行基础设施:你在需要时提供资源,按实际使用量付费,然后在不再需要时销毁它们。

除此之外,采用云原生方法还可以进一步优化成本。云原生应用被设计为可扩展的,因此它们可以利用云的弹性。它们是有弹性的,因此与生产中的停机时间和严重故障相关的成本较低。它们松耦合,使团队能够更快地推进产品上市,拥有显著的竞争优势。此外,还有许多其他优点。

云原生拓扑结构

我的云原生解释没有涉及具体的技术或架构。CNCF在其定义中提到了一些,如容器和微服务,但这只是一些例子。你不必为了让你的应用程序成为云原生而使用Docker容器。考虑无服务器或PaaS解决方案。编写AWS Lambda平台的函数或将应用程序部署到Heroku并不要求你构建容器,但它们仍然被归类为云原生。

在本节中,我将介绍一些常见的云原生拓扑结构(见图1.9)。首先,我将介绍容器和编排的概念,这将在后面的章节中进一步探讨Docker和Kubernetes。然后,我会介绍无服务器技术和函数(FaaS)。在本书中,我不会过多关注FaaS模型,但我会介绍使用Spring Native和Spring Cloud Function构建无服务器应用程序的基础知识。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

容器

想象一下,你加入了一个团队并开始在一个应用程序上工作。首先,你会按照指南设置本地开发环境,使其与同事们使用的环境类似。然后你开发一个新功能,并在质量保证(QA)环境中进行测试。一旦功能经过验证,应用程序可以部署到暂存环境进行额外的测试,最终再部署到生产环境。应用程序是为在特定特性的环境中运行而构建的,因此使得所有不同环境尽可能相似是非常重要的。你会如何做到这一点呢?这就是容器的作用。

在使用容器之前,你可能会依赖虚拟机来确保环境的可重复性、隔离性和可配置性。虚拟化通过利用虚拟化监视器(hypervisor)组件来抽象硬件,使得在同一台机器上运行多个操作系统成为可能,并实现隔离。虚拟化监视器可以直接运行在机器硬件上(类型1),或者运行在主机操作系统上(类型2)。

另一方面,操作系统容器是一个轻量级的可执行包,包含运行应用程序所需的一切。容器与主机共享相同的内核:不需要引导完整的操作系统来添加新的隔离上下文。在Linux上,可以通过利用Linux内核提供的一些特性来实现这一点:

命名空间用于在进程之间划分资源,以便每个进程(或进程组)只能看到机器上可用资源的一个子集。 控制组用于控制和限制进程(或进程组)的资源使用情况。 注意:虚拟化只共享硬件,而容器还共享相同的操作系统内核。两者都提供了在隔离环境中运行软件的计算环境,尽管隔离程度不完全相同。

图1.10显示了虚拟化和容器技术之间的区别。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

为什么容器在云原生应用中如此受欢迎?传统上,为了让应用程序运行,你需要在虚拟机上安装和维护Java运行时环境(JRE)和中间件。相比之下,容器可以在几乎任何计算环境中可靠地运行,与应用程序、其依赖项或中间件无关。无论是什么类型的应用程序,用哪种编程语言编写,或使用了哪些库,容器都具有相似的外部形状,就像用于运输的集装箱一样。

因此,容器实现了敏捷性、在不同环境间的可移植性和部署的可重复性。它们轻量且资源要求较少,非常适合在云中运行,因为云中的应用程序是可丢弃的,可以动态快速地进行扩展。相比之下,构建和销毁虚拟机成本更高且耗时更长。

虚拟化和容器并不是互斥的。在云原生环境中,你可以同时使用它们,构建一个由虚拟机组成的基础设施,并在其中运行容器。基础设施即服务(IaaS)模型提供了一个虚拟化层,用于启动新的虚拟机。在其之上,你可以安装容器运行时并运行容器。

一个应用通常由不同的容器组成,这些容器可以在开发或早期测试时在同一台机器上运行。但是,当你开始为可扩展性复制容器并将它们分布在不同的机器上时,很快会变得过于复杂,管理众多容器会变得困难。这时,你将开始依赖容器即服务(CaaS)模型提供的更高层次的抽象,该模型提供了在机器集群中部署和管理容器的功能。请注意,背后仍然有一个虚拟化层。

即使在使用Heroku或Cloud Foundry等平台的平台即服务(PaaS)时,容器也扮演着重要角色。你只需提供JAR构件,这些平台会负责处理JRE、中间件、操作系统和所有所需的依赖项。在幕后,它们将所有这些组件构建成一个容器,并最终运行它。不同之处在于,构建容器的责任不再由你负责,而是由平台代替你完成。一方面,这很方便,减轻了开发人员的责任。另一方面,你会放弃对运行时和中间件的控制,并可能面临供应商锁定。

在本书中,你将学习如何使用云原生构建包(CNCF项目)将Spring应用程序容器化,并使用Docker在本地环境中运行它们。

编排(Orchestration)

那么您已经决定使用容器,太好了!您可以依靠它们的可移植性将它们部署到任何提供容器运行时的基础架构。您可以实现可复现性,因此在将容器从开发环境移动到暂存环境再到生产环境时不会有任何意外情况。您可以快速扩展它们,因为它们非常轻量级,并为您的应用程序提供高可用性。您已经准备好在下一个云原生系统中采用它们了。或者,您确定了吗?

在单个计算机上配置和管理容器是相当简单的。但是,当您开始处理在几台计算机上扩展和部署的数十甚至数百个容器时,您需要另一种方法。

当您从虚拟服务器(IaaS模型)转向容器集群(CaaS模型)时,您的视角也会发生转变。在IaaS中,您关注的是单个计算节点,即虚拟服务器。在CaaS中,底层基础设施被抽象化,您将关注的是节点集群。

通过CaaS解决方案提供的新视角,部署目标将不再是一台机器,而是一组机器的集群。基于Kubernetes等的CaaS平台提供了许多功能来解决我们在云原生环境中寻求的所有重要问题,对跨机器编排容器。两种不同的拓扑结构如图1.11所示。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

容器编排帮助您自动化许多不同的任务:

  1. 管理集群,根据需要启动和关闭计算机
  2. 在集群内调度和部署容器,选择满足CPU和内存等容器要求的计算机
  3. 通过动态缩放容器实现高可用性和韧性,利用健康监控
  4. 设置容器之间的网络通信,定义路由、服务发现和负载均衡
  5. 将服务暴露给互联网,建立端口和网络
  6. 根据特定标准为容器分配资源
  7. 配置容器内运行的应用程序
  8. 确保安全性和实施访问控制策略

编排工具通过声明式的方式进行指导,比如通过YAML文件。根据特定工具定义的格式和语言,您通常会描述希望实现的状态,例如,您希望在集群中部署三个Web应用程序容器的副本,并将其服务暴露给互联网。

容器编排器的例子包括Kubernetes(一个CNCF项目),Docker Swarm和Apache Mesos。在本书中,您将学习如何使用Kubernetes来编排您的Spring应用程序的容器。

Serverless

在从虚拟机转向容器之后,我们可以进一步抽象基础设施:这就是无服务器技术的位置。无服务器计算模型使开发人员能够专注于实现应用程序的业务逻辑。

“无服务器”这个名字可能会让人产生误解。当然,有服务器存在。区别在于您无需管理它,也不需要对应用程序在服务器上的部署进行编排。这些都成为平台的责任。当您使用类似Kubernetes的编排器时,仍然需要考虑基础设施的预配、容量规划和扩展。相比之下,无服务器平台负责设置应用程序所需的底层基础设施,包括虚拟机、容器和动态缩放。

无服务器架构通常与函数相关联,但它包含两个主要模型,通常同时使用:

  1. 后端即服务(BaaS)——在这种模型中,应用程序高度依赖于云提供商提供的第三方服务,例如数据库、认证服务和消息队列。重点是减少与后端服务相关的开发和运营成本。开发人员可以实现前端应用程序(例如单页应用程序或移动应用程序),同时将大部分或全部后端功能交给BaaS供应商处理。例如,他们可以使用Okta进行用户认证,使用Google Firebase进行数据持久化,使用Amazon API Gateway发布和管理REST API。
  2. 函数即服务(FaaS)——在这种模型中,应用程序是无状态的,由事件触发,并完全由平台管理。重点是减少与编排和扩展应用程序相关的部署和运营成本。开发人员可以实现应用程序的业务逻辑,而平台会处理其余部分。无服务器应用程序不必通过函数来实现,以被归类为无服务器应用程序。有两个主要的FaaS提供方式。一种方式是选择特定供应商的FaaS平台,例如AWS Lambda、Azure Functions或Google Cloud Functions。另一种方式是选择基于开源项目的无服务器平台,可以在公共云或本地运行,解决供应商锁定和缺乏控制等问题。此类项目的例子包括Knative和Apache OpenWhisk。Knative在Kubernetes之上提供了无服务器运行时环境,如第16章中所介绍的。它被用作企业无服务器平台,如VMware Tanzu Application Platform、RedHat OpenShift Serverless和Google Cloud Run的基础。

无服务器应用程序通常是事件驱动的,只有在有事件需要处理时才运行,比如HTTP请求或消息。事件可以是外部事件,也可以由另一个函数产生。例如,每当有消息添加到队列时,会触发一个函数来处理它,然后退出执行。

当没有需要处理的内容时,无服务器平台会关闭所有与函数相关的资源,因此您只需为实际使用情况付费。而在其他云原生拓扑结构中,如CaaS或PaaS,始终会有一个运行着的服务器,24/7。与传统系统相比,它们提供了动态扩展性的优势,减少了在任何给定时间内预配的资源数量。但仍然有一些东西在运行,这也带来了一定的成本。在无服务器模型中,只有在需要时才会预配资源。如果没有需要处理的内容,一切都会关闭。这就是我们所说的“缩减到零”,这也是无服务器平台提供的主要功能之一。

除了成本优化外,无服务器技术还将一些额外的责任从应用程序转移到了平台上。这可能是一个优势,因为它允许开发人员专注于业务逻辑。但同时也要考虑到您希望拥有多少控制权,以及如何处理供应商锁定的问题。每个FaaS,以及通常的无服务器平台,都有其自己的功能和API。一旦您开始为特定平台编写函数,就不能轻松地将它们移动到另一个平台,就像您使用容器时那样。在FaaS中,您可能会妥协得更多——以授权和范围为代价,来换取控制权和可移植性。这就是为什么Knative迅速变得流行:它构建在Kubernetes之上,这意味着您可以轻松地在不同平台和供应商之间移动您的无服务器工作负载。最终,这是一种权衡的问题。

云原生应用程序的架构

我们已经到达了定义云原生的最后一步,我已经介绍了我们将在整本书中依赖的主要特征。在前面的部分,您对主要的云原生拓扑有所了解,特别是我们的计算单元——容器。现在让我们来看看容器内部并探索一些涉及构建和设计云原生应用程序的高级原则。图1.12显示了本节涵盖的主要概念。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

从多层架构到微服务架构以及更多其他架构

IT基础设施一直影响着软件应用的架构和设计方式。起初,单体应用部署在巨大的主机上作为单一组件。随着互联网和个人计算机的普及,我们开始根据客户端/服务器范式设计应用程序。多层架构,依赖于该范式,广泛用于桌面和Web应用程序,将代码分解为表示层、业务层和数据层。

随着应用程序复杂性的增加和敏捷性的需求,人们开始探索更进一步分解代码的新方式,并引入了一种新的架构风格:微服务。在过去几年中,这种架构风格变得越来越受欢迎,许多公司决定根据这种新风格对其应用程序进行重构。微服务通常与单片应用进行比较,如图1.13所示。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

主要区别在于应用程序的分解方式。单片应用与三个大层关联。相反,基于微服务的应用与许多组件关联,每个组件只实现一个功能。为了将单片应用分解为微服务并处理由于有多个组件而产生的复杂性,提出了许多模式。

注意:本书不涉及微服务的内容,因此我不会详细介绍它们。如果您对此主题感兴趣,可以查阅Sam Newman所著的《构建微服务》第二版(O’Reilly,2021)和Chris Richardson所著的《微服务模式》(Manning,2018)。对于更多与Spring相关的分析,您可以在Manning目录中找到John Carnell和Illary Huaylupo Sanchez所著的《Spring微服务实战》第二版(Manning,2021)。如果您对微服务不熟悉,不用担心。这些知识不是阅读本书的前提条件。

经过多年的赞誉和失败的迁移后,开发者社区对这种流行的架构风格的未来展开了激烈讨论。一些工程师开始讨论“宏服务”,以减少组件的数量,从而减轻管理它们的复杂性。“宏服务”这个术语是Cindy Sridharan讽刺地提出的,但它已经在行业中得到采用,并被Dropbox和Airbnb等公司用来描述它们的新架构。另一些人提出了堡垒式架构风格,由一个中央单片应用围绕着微服务组成。还有一些人主张回归到单片应用,以模块化的单片应用形式。

最重要的是选择一个可以为客户和企业提供价值的架构。这是我们开发应用程序的原因。每种架构风格都有其使用案例。并不存在银弹或一刀切的解决方案。与微服务相关的大多数负面经验实际上是由于其他问题引起的,比如糟糕的代码模块化或不合适的组织结构。单片应用和微服务之间不应该有战争。

在本书中,我想向您展示如何使用Spring构建云原生应用并将它们部署为Kubernetes容器。云原生应用与微服务一样,是分布式系统。通常在微服务的背景下讨论的一些主题实际上属于任何分布式系统,例如路由和服务发现。云原生应用本质上是松耦合的,这也是微服务的一个特点。

尽管它们有一些相似之处,但重要的是要理解云原生应用和微服务并不相同。您可以完全将微服务风格用于云原生应用。许多开发人员这样做,但这不是必需的。在本书中,我将使用一种我们可能称之为基于服务的架构风格。也许这不是一个引人注目或花哨的名称,但对于我们的目的已经足够。我们将处理服务。它们可以是任何大小,并且可以根据不同的原则封装逻辑。这并不重要。我们要做的是设计服务以适应我们的开发、组织和业务需求。

云原生应用的基于服务的架构

在本书中,我们将根据基于服务的架构设计和构建云原生应用。

我们的中心工作单元将是一个服务,它可以以不同的方式与其他服务进行交互。根据Cornelia Davis在她的著作《Cloud Native Patterns》(Manning,2019)中提出的区分,我们可以确定架构的两个要素:服务和交互。

  • 服务 - 为其他组件提供任何类型的服务的组件
  • 交互 - 服务之间的通信,以实现系统的需求

服务是相当通用的组件 - 它们可以是任何东西。我们可以根据它们是否存储任何类型的状态将其分类,区分为应用程序服务(无状态)和数据服务(有状态)。

图1.14显示了云原生架构的要素。用于管理图书馆库存的应用程序将是一个应用程序服务。用于存储图书信息的PostgreSQL数据库将是一个数据服务。

《基于云原生的Spring实战:使用Spring Boot和Kubernetes》第一章:云原生入门

应用程序服务(Application Services)

应用程序服务是无状态的,负责实现各种逻辑。它们不必遵循像微服务那样的特定规则,只要它们暴露出您在本章早些时候学到的所有云原生特性。

在设计每个服务时,重要的是要考虑松散耦合和高内聚性。服务应该尽可能独立。分布式系统非常复杂,因此在设计阶段要特别小心。增加服务的数量会导致更多的问题。

您可能会自己开发和维护系统中的大多数应用程序服务,但您也可以使用云提供商提供的一些服务,例如身份验证或支付服务。

数据服务

数据服务是有状态的,负责存储任何类型的状态。状态是在关闭服务或启动新实例时需要保留的所有信息。

数据服务可以是像PostgreSQL这样的关系数据库,也可以是像Redis这样的键值存储,或者是像RabbitMQ这样的消息代理。你可以自行管理这些服务。相较于管理云原生应用程序而言,管理数据服务更具挑战性,因为需要保存状态的存储,但你可以获得更多对自己数据的控制。另一种选择是使用云提供商提供的数据服务,这样提供商将负责管理与存储、弹性、可扩展性和性能相关的所有问题。在这种情况下,你可以利用专为云端打造的众多数据服务,例如Amazon DynamoDB,Azure Cosmos DB和Google BigQuery。

云原生数据服务是一个非常有趣的话题,但在本书中主要关注应用程序。与数据相关的问题,如集群、复制、一致性和分布式事务,将不会详细介绍。我很想介绍它们,但它们值得有一本专门的书来全面覆盖。

交互

云原生服务彼此通信以满足系统的需求。这种通信方式将影响系统的整体性能。例如,选择请求/响应模式(同步的HTTP调用)而不是事件驱动的方式(通过RabbitMQ传递消息)将导致应用程序的韧性不同。在本书中,我们将使用不同类型的交互方式,了解它们之间的差异,并学习何时使用每种方法。

总结

  • 云原生应用是专门为云端设计并部署的高度分布式系统。
  • 云端是以计算、存储和网络资源为基础提供的IT基础设施。
  • 在云端,用户只支付实际使用的资源。
  • 云平台以不同的抽象层次提供其服务:基础设施(IaaS)、容器(CaaS)、平台(PaaS)、函数(FaaS)或软件(SaaS)。
  • 云原生应用具有水平可扩展性、松散耦合、高内聚性、容错性、可管理性和可观测性。
  • 云原生开发受到自动化、持续交付和DevOps的支持。
  • 持续交付是一种全面的工程实践,用于快速、可靠、安全地交付高质量的软件。
  • DevOps是一种文化,促进不同角色之间的合作,共同交付业务价值。
  • 现代企业采用云原生来开发软件,以便能够快速交付、根据需求进行动态扩展,并且始终可用和具备容错性,同时优化成本。
  • 在设计云原生系统时,可以使用容器(如Docker容器)作为计算单位。它们比虚拟机更轻量级,并提供了可移植性、不变性和灵活性。
  • 专用平台(如Kubernetes)提供服务来管理容器,无需直接处理底层层次。它们提供容器编排、集群管理、网络服务和调度功能。
  • 无服务器计算是一种模型,其中平台(如Knative)管理服务器和基础设施,而开发人员仅关注业务逻辑。后端功能以按需付费的方式启用,以实现成本优化。
  • 可以使用微服务架构来构建云原生应用,但这不是必须的。
  • 为了设计云原生应用,我们将使用服务为基础的风格,其特点是服务及其交互方式。
  • 云原生服务可以分为应用服务(无状态)和数据服务(有状态)。