【注】本文译自:How to build a Spring Boot 12-Factor app (theserverside.com)
在这里,我们看看 Spring Boot 框架如何支持十二因素应用的方法,以及 GitHub、Docker 和 Kubernetes 等工具填补了哪些空白。
没有国际标准组织指定 Spring Boot 应用作为微服务必须满足的标准。Heroku 联合创始人 Adam Wiggins 向部署到 Heroku 平台的开发人员提供的 12 条建议是开发人员最接近的一套云原生开发指南。
这 12 条戒律被称为“十二因素应用方法论”,已成为创建现代的以 Docker 和 Kubernetes 为部署目标的现代云原生微服务的事实标准。
开发基于 Java 的微服务最流行的平台是 Spring Boot。以下是 Spring Boot 如何支持十二因素应用方法论的原则。
1. Spring Boot 代码库
并非每个 12 因素的原则都直接映射到 Spring Boot。代码库原则就是责任落在 Spring 框架之外的一个例子。
根据十二因素应用,每个 Spring Boot 微服务都应该有自己独立的代码库。这可以通过创建单个 Git 存储库来实现,开发人员可以在其中贡献代码、合并分支和修复错误。如果您的 Spring Boot 应用托管在其自己的 Git 存储库中,那么您已经正确地实现了 12 因素代码库要求。
2. 外部化依赖管理
如果您使用 Spring Boot 初始化器创建一个项目,则必须在 Gradle 或 Maven 之间进行选择作为项目的构建工具。这两个工具都将管理依赖项外部化。
如果您将 JAR 文件放在项目的 lib 目录之外,并在 Maven POM 或 Gradle 构建文件中列出程序的所有外部依赖项,则您的 Spring Boot 应用程序将正确实现 12 因素 依赖项管理。
3. Spring Boot 和 Kubernetes 配置
根据十二因素应用方法论,Spring Boot 应用程序应该从环境中读取其配置数据。 例如,如果将云原生 Spring Boot 应用程序部署到 Docker 容器并在 Kubernetes 集群中进行管理,则应用程序应该从 Kubernetes ConfigMap 读取其配置数据——而不是从 JavaBean 字段甚至应用程序属性文件。Spring 的级联配置处理系统完全满足了这个 12-因素要求。
任何用 Spring @ConfigurationProperties 注解修饰的 JavaBean 都会在多个地方寻找配置数据。 @ConfigurationProperties 修饰的 bean 的规则是始终使用最高外部化级别的配置。在 JavaBean 中硬编码的属性将被 ApplicationProperties 文件中的数据覆盖,这些数据将被 JVM 参数覆盖,最终将被 Docker 或 Kubernetes ConfigMap 提供的参数覆盖。
使用 @ConfigurationProperties 注解,您的 12 因素 Spring Boot 应用将符合配置。
4. 支持服务和 Spring Boot
将支持服务视为附加资源的能力自 Java 语言一开始就已经融入到 Java 语言中,因此即使开发人员齐心协力,也很难违反这个 12 因素 约束。
例如,所有通过 Java 数据库连接 (JDBC) 访问的数据库都需要一个 URL 和驱动程序,这隐式地使数据库成为附加资源。 如果不将数据库视为支持服务,就不可能在 Java 中执行 JDBC 或 JPA。 NoSQL 数据库、Kafka 队列和 RESTful Web 服务也是如此。如果您在 Jakarta EE 或 Spring Boot 中编写代码,则几乎必须按照 12-因素指南将所有外部资源视为支持服务。
5. 构建、发布和运行
开发人员遵循严格的构建、发布和运行策略的建议似乎有些不言而喻。 具有讽刺意味的是,这也可能是最常违反的 12 因素规则之一。
这里的想法是您应该始终从您的代码库构建您的代码。发布是与版本化配置文件相关联的标记构建。它是您在服务器上部署和运行的标记构建和版本化配置数据的组合。
不应更新在服务器上运行的代码来修复错误。不应在运行时调整配置设置来克服 Java 性能问题。进入部署的所有代码都来自构建,它基于在裸 Git 存储库中进行版本控制的代码。
一旦与构建配对以创建发布,配置数据就不得更改。如果需要更改,团队必须再次经历完整的构建、发布和运行周期。 不应该有违反 12 因素构建、发布和运行原则的捷径。
6. 无状态 Spring Boot 进程
Java 和 Jakarta EE API 有许多类和接口,它们隐式地向应用程序添加状态,其中最重要的是 Servlet 和 JSP API 的 HttpSession 对象。
为了实现 12 因素合规性,Spring Boot 为 HttpSession 提供了一个替代品,称为 Spring Session。这有助于外部化数据,否则这些数据将被有状态地保存在 Tomcat 或 Jetty 等应用程序服务器上。这是 Spring Boot 如何提供额外 API 并重新实现常用类以确保应用程序和微服务保持 12 因素合规性的一个主要示例。
此外,Spring Boot 允许开发人员轻松地将 NoSQL 数据库(如 Cassandra 和 MongoDB)中的状态外部化,这也有助于简化无状态微服务的开发。
必须指出的是,确保微服务作为无状态进程运行的责任也很大程度上落在了软件开发人员的肩上。如果开发人员决定将用户状态保存在一个实例变量中,而不是在共享资源中将该数据外部化,那么 Spring、Docker 或 Kubernetes 无法让该应用程序作为无状态进程进行扩展。
7. 端口绑定
端口绑定是另一个 12 因素 原则,它超出了 Spring Boot 框架的范围。相反,Docker 容器会将 Tomcat 或 Undertow 服务器使用的内部端口映射到公共端口。在集群环境中,kubectl 实用程序会将 Kubernetes Pod 的端口绑定为公共服务。无论哪种方式,Spring Framework 都不负责端口绑定要求。
Spring 确实提供了更改打包的 Spring Boot 应用程序内部使用的端口的能力,但 Kubernetes 或 Docker 将负责外部端口绑定,使云原生应用程序可公开访问。
8. 并发性
根据十二因素应用方法论,云原生应用应该能够横向扩展,以支持来自客户端的大容量并发请求-响应周期。只要 Spring Boot 应用是无状态的,Kubernetes 副本集就会负责使用 Docker 容器创建新的 Pod,这些容器可以同时处理不断增加的工作负载。
9. 快速启动和关闭
十二因素应用方法论的第 9 条原则是可处置性,它坚持微服务应该快速启动并优雅地关闭。
为了便于处理,Spring Boot 实现了延迟加载设计模式。它还执行智能初始化以减少在云原生微服务启动时创建的对象数量。此外,当开发人员使用 Spring 框架提供的资源类时,控制能力的反转确保资源在 Kubernetes 节点耗尽或 Docker 容器下线时优雅地终止。
10. 环境之间的奇偶校验
开发、用户验收测试、预生产和生产环境之间总会存在差异。但十二因素方法坚持这些环境尽可能相似。
为了促进环境对等,Spring Boot 构建将创建一个可运行的 JAR 文件,其中嵌入了一个应用程序服务器,例如 Tomcat。 打包在 Docker 容器中的相同嵌入式 Tomcat JAR 文件将用于每个不同的部署环境。 由于每个环境都部署了相同的编译代码和应用服务器,最终实现了环境间的对等。
此外,Spring Profiles 提供了一种简单的方法来定义和配置需要从一个环境更改到另一个环境的属性,从而允许开发人员解决不可避免地发生的环境之间的差异。
11. 日志作为事件流
十二因素应用坚持将日志视为事件流。
Spring Boot 使用的所有标准 Java 日志框架都将它们的数据写入事件流,该事件流被保存到运行 Docker 容器的 Kubernetes 节点上的公共目录中。然后这些日志文件很容易被 Kubernetes DaemonSets 使用,比如 FluentD 或 Logstash。这些 DaemonSet 然后将日志流式传输到 Elasticsearch 和 Logstash 等工具以供使用。
只要您使用框架标准的 Java 日志框架,您就可以放心,在日志消耗方面,您拥有一个符合 12 因素标准的 Spring Boot 应用程序。
12. 管理进程管理
应用通常需要运行管理进程,这些进程与处理客户端-服务器交互的请求-响应循环没有直接联系的。根据十二因素应用,不应将实现这些过程的代码放在单独的代码库中。管理进程应打包为标准的、受版本控制的构建的一部分,并且进程本身应在应用使用的相同运行时环境中执行。
在云原生 Spring Boot 应用程序中添加对管理进程的支持非常容易。Spring Batch 项目可以轻松添加对运行一次并退出的作业的支持。 此外,任何 Git 存储库都可以配置为包含文件夹,这些文件夹允许添加可以在需要时在 REPL shell 中运行的脚本。
云原生微服务的开发没有明确的标准,但十二要素应用方法很接近。如果您是一名 Java 开发人员并且想要创建 12 因素应用,Spring Boot 将帮助您的团队保持云原生合规性。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。