将 Spring Boot 应用程序迁移到 Azure 容器应用

本指南介绍在需要迁移现有 Spring Boot 应用程序以使之在 Azure 容器应用上运行时应注意的事项。

预迁移

若要确保迁移成功,请在开始之前完成以下各节中所述的评估和清点步骤。

如果无法满足任何预迁移要求,请参阅以下伴随迁移指南:

  • 将可执行的 JAR 应用程序迁移到 Azure Kubernetes 服务上的容器(按指南进行计划)
  • 将可执行的 JAR 应用程序迁移到 Azure 虚拟机(按指南进行计划)

检查应用程序组件

标识本地状态

在 PaaS 环境上,无法保证应用程序在任意给定时间都刚好运行一次。 即使将应用程序配置为在单个实例中运行,在以下情况下也可以创建重复的实例:

  • 由于故障或系统更新,必须将应用程序重新定位到物理主机。
  • 正在更新应用程序。

在上述任何一种情况下,原始实例都会一直运行,直到新实例启动完毕。 此模式可能会对应用程序产生以下重大影响:

  • 无法保证单一实例真正是单一的。
  • 与单个物理服务器或 VM 相比,任何未持久化到外部存储的数据都可能会更快丢失。

在迁移到 Azure 容器应用之前,请确保代码不包含不可丢失或复制的本地状态。 如果存在本地状态,请更改代码,使其在应用程序外部存储该状态。 云就绪应用程序通常将应用程序状态存储在以下选项的位置:

确定是否使用以及如何使用文件系统

查找向本地文件系统写入和/或从中读取服务的任何实例。 确定写入和读取短期/临时文件的位置,以及写入和读取长期文件的位置。

Azure 容器应用提供多种类型的存储。 临时存储可以读写临时数据,并可供运行中的容器或副本使用。 Azure 文件提供永久存储,并且可跨多个容器共享。 有关详细信息,请参阅在 Azure 容器应用中使用存储装载

只读静态内容

如果应用程序目前提供的是静态内容,则需要为其提供一个备用位置。 不妨考虑将静态内容移至 Azure Blob 存储,并添加 Azure CDN,以便在全球范围内实现超快速下载。 有关详细信息,请参阅 Azure 存储中的静态网站托管快速入门:将 Azure 存储帐户与 Azure CDN 集成

动态发布的静态内容

如果应用程序支持静态内容,无论是上传的内容还是由应用程序本身生成的内容,且在创建后保持不变,则可以集成 Azure Blob 存储和 Azure CDN。 还可以使用 Azure Function 来管理上传,并在必要时触发 CDN 刷新。 我们提供了一个示例实现,用于通过 Azure Functions 进行静态内容的上传和 CDN 预加载操作

确定是否有服务包含特定于 OS 的代码

如果应用程序包含的代码有主机 OS 的依赖项,则需重构该代码,删除那些依赖项。 例如,如果应用程序在 Windows 上运行,则可能需要将文件系统路径中的 /\ 替换为 File.SeparatorPaths.get

切换到受支持的平台

如果手动创建 Dockerfile 并将容器化应用程序部署到 Azure 容器应用,则可以完全控制部署,包括 JRE/JDK 版本。

对于从项目进行部署,Azure 容器应用还提供特定版本的 Java(8、11、17 和 21)以及特定版本的 Spring Boot 和 Spring Cloud 组件。 若要确保兼容性,请在继续执行其余迁移步骤之前,首先将应用程序迁移到当前环境中支持的 Java 版本之一。 务必全面测试生成的配置。 请在此类测试中使用最新且稳定的 Linux 发布版。

注意

如果当前服务器在不受支持的 JDK(如 Oracle JDK 或 IBM OpenJ9)上运行,则此验证尤其重要。

若要获取当前的 Java 版本,请登录到生产服务器并运行以下命令:

java -version

有关支持的 Java、Spring Boot 和 Spring Cloud 版本以及更新说明,请参阅 Azure 容器应用上的 Java 概述

确定应用程序是否依赖于计划的作业

临时应用程序(如 Unix cron 作业或基于 Spring Batch 框架的短时应用程序)应作为作业在 Azure 容器应用上运行。 有关详细信息,请参阅 Azure 容器应用中的作业。 如果你的应用程序需要长时间运行,并使用 Quartz 或 Spring Batch 等计划框架来定期执行任务,则 Azure 容器应用可以托管该应用程序。 但是,应用程序必须适当处理缩放,以避免在横向扩展或滚动升级期间,同一应用程序实例在每个预定时间段内被执行超过一次的争用条件。

清点生产服务器上运行的任何计划任务,包括应用程序代码内部或外部的任务。

确定 Spring Boot 版本

检查要迁移的每个应用程序的依赖项,以确定其 Spring Boot 版本。

Maven

在 Maven 项目中,通常可以在 POM 文件的 <parent> 元素中找到 Spring Boot 版本:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
Gradle

在 Gradle 项目中,通常可以在 plugins 部分找到 Spring Boot 版本(作为 org.springframework.boot 插件的版本):

plugins {
  id 'org.springframework.boot' version '3.3.3'
  id 'io.spring.dependency-management' version '1.1.6'
  id 'java'
}

对于使用 Spring Boot 3.x 之前版本的任何应用程序,请遵循 Spring Boot 2.0 迁移指南Spring Boot 3.0 迁移指南,将其更新到受支持的 Spring Boot 版本。 有关支持的版本,请参阅 Spring Boot 和 Spring Cloud 版本

确定日志聚合解决方案

确定你正在迁移的应用程序正在使用的任何日志聚合解决方案。 需要在迁移中配置诊断设置,以使记录的事件可供使用。 有关详细信息,请参阅确保控制台日志记录并配置诊断设置部分。

确定应用程序性能管理 (APM) 代理

确定应用程序使用的任何应用程序性能管理代理。 Azure 容器应用不提供对 APM 集成的内置支持。 需要准备好容器镜像或将 APM 工具直接集成到代码中。 如果要衡量应用程序的性能,但尚未集成任何 APM,则可以考虑使用 Azure Application Insights。 有关详细信息,请参阅迁移部分。

清点外部资源

标识外部资源,如数据源、JMS 消息代理和其他服务的 URL。 在 Spring Boot 应用程序中,通常可以在 src/main/resources 文件夹中找到此类资源的配置,文件名通常为 application.propertiesapplication.yml

数据库

对于 Spring Boot 应用程序来说,当它依赖于外部数据库时,连接字符串通常会出现在配置文件中。 下面是 application.properties 文件中的示例:

spring.datasource.url=jdbc:mysql://localhost:3306/mysql_db
spring.datasource.username=dbuser
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

下面是 application.yaml 文件中的示例:

spring:
  data:
    mongodb:
      uri: mongodb://mongouser:deepsecret@mongoserver.contoso.com:27017

有关可能性更大的配置场景,请参阅 Spring 数据文档:

JMS 消息代理

通过在生成清单(通常是 pom.xml 或 build.gradle 文件)中查找相关依赖项,确定所使用的一个或多个代理

例如,使用 ActiveMQ 的 Spring Boot 应用程序通常会在其 pom.xml 文件中包含此依赖项

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-activemq</artifactId>
</dependency>

使用商业代理的 Spring Boot 应用程序通常直接包含对代理的 JMS 驱动程序库的依赖项。 下面是 build.gradle 文件中的示例:

    dependencies {
      ...
      compile("com.ibm.mq:com.ibm.mq.allclient:9.4.0.5")
      ...
    }

确定正在使用的一个或多个代理后,请找到相应的设置。 在 Spring Boot 应用程序中,通常可以在应用程序目录的 application.properties 和 application.yml 文件中找到它们

注意

Microsoft 建议使用最安全的可用身份验证流。 此过程中所述的身份验证流(例如数据库、缓存、消息传送或 AI 服务)需要高度信任应用程序,并且存在其他流中不存在的风险。 仅当更安全的选项(例如无密码连接或无密钥连接的托管标识)不可行时,才使用此流。 对于本地计算机操作,首选无密码连接或无密钥连接的用户标识。

下面是 application.properties 文件中的 ActiveMQ 示例

spring.activemq.brokerurl=broker:(tcp://localhost:61616,network:static:tcp://remotehost:61616)?persistent=false&useJmx=true
spring.activemq.user=admin
spring.activemq.password=<password>

有关 ActiveMQ 配置的详细信息,请参阅 Spring Boot 消息文档

下面是 application.yaml 文件中的 IBM MQ 示例

ibm:
  mq:
    queueManager: qm1
    channel: dev.ORDERS
    connName: localhost(14)
    user: admin
    password: <password>

有关 IBM MQ 配置的详细信息,请参阅 IBM MQ Spring 组件文档

确定外部缓存

确定正在使用的任何外部缓存。 通常,Redis 是通过 Spring Data Redis 使用的。 有关配置信息,请参阅 Spring Data Redis 文档。

通过搜索相应的配置(在 JavaXML)中,确定是否正在通过 Spring 会话缓存会话数据。

标识提供者

标识应用程序使用的任何标识提供者。 有关可如何配置标识提供者的信息,请参阅以下内容:

识别依赖于非标准端口的所有客户端

Azure 容器应用允许根据 Azure 容器应用的资源配置来公开端口。 例如,Spring Boot 应用程序默认侦听 8080 端口,但可以根据需要使用 server.port 或环境变量 SERVER_PORT 进行设置。

所有其他的外部资源

本指南不可能记录每个可能的外部依赖项。 迁移后,你将负责验证你能否满足应用程序的所有外部依赖项的要求。

清单配置源和机密

清单密码和安全字符串

检查生产部署上的所有属性和配置文件以及所有环境变量中是否有机密字符串和密码。 在 Spring Boot 应用程序中,通常可以在 application.properties 或 application.yml 文件中找到此类字符串

清点证书

记录用于公共 SSL 终结点或与后端数据库以及其他系统通信的所有证书。 可以通过运行以下命令来查看生产服务器上的所有证书:

keytool -list -v -keystore <path to keystore>

检查部署体系结构

记录每个服务的硬件要求

记录 Spring Boot 应用程序的以下信息:

  • 正在运行的实例数。
  • 为每个实例分配的 CPU 数量。
  • 为每个实例分配的 RAM 量。

记录异地复制/分发

确定 Spring Boot 应用程序实例当前是否分布在多个区域或数据中心。 记录要迁移的应用程序的运行时间要求/SLA。

迁移

创建 Azure 容器应用环境并部署应用

在 Azure 订阅中预配 Azure 容器应用实例。 其安全的托管环境也随之创建。 更多信息,请参阅快速入门:使用 Azure 门户部署你的第一个应用程序

确保控制台日志记录并配置诊断设置

配置日志记录,确保所有输出都路由控制台而不是文件。

将应用程序部署到 Azure 容器应用之后,可以在容器应用环境中配置日志选项,以定义一个或多个日志目标。 这些目标可以包括 Azure Monitor Log Analytics、Azure 事件中心,甚至其他第三方监控解决方案。 还可以选择禁用日志数据,并且只在运行时查看日志。 有关详细配置说明,请参阅 Azure 容器应用中的日志存储和监控选项

配置持久性存储

如果应用程序的任何部分要读写本地文件系统,则需要配置持久性存储来替代本地文件系统。 可以通过应用程序设置指定装载到容器中的路径,并将其与应用正在使用的路径保持一致。 有关详细信息,请参阅在 Azure 容器应用中使用存储装载

将所有证书迁移到 KeyVault

Azure 容器应用支持应用之间的安全通信。 应用程序无需管理建立安全通信的过程。 可以将私人证书上传到 Azure 容器应用,或使用 Azure 容器应用提供的免费托管证书。 建议使用 Azure Key Vault 来管理证书。 有关详细信息,请参阅 Azure 容器应用中的证书

配置应用程序性能管理 (APM) 集成

无论是通过容器映像还是代码来部署应用,Azure 容器应用都不会干扰映像或代码。 因此,将应用程序与 APM 工具集成取决于自己的偏好和实现情况。

如果应用程序没有使用支持的 APM,Azure Application Insights 也是一种选择。 有关详细信息,请参阅将 Azure Monitor Application Insights 与 Spring Boot 配合使用

部署应用

按照使用 az containerapp up 命令部署 Azure 容器应用中的描述,部署迁移的每个微服务(不包括 Spring Cloud Config Server 和 Spring Cloud Service Registry)。

配置基于服务的机密和外部化设置

可以将配置设置作为环境变量注入每个应用程序。 可以将这些变量设置为手动条目或对机密的引用。 有关配置的详细信息,请参阅管理 Azure 容器应用中的环境变量

迁移和启用标识提供者

如果任何 Spring Cloud 应用程序需要身份验证或授权,请确保将其配置为访问标识提供者:

  • 如果标识提供者是 Microsoft Entra ID,则不需要进行任何更改。
  • 如果标识提供者是本地 Active Directory 林,请考虑使用 Microsoft Entra ID 实现混合标识解决方案。 有关详细信息,请参阅混合标识文档
  • 如果标识提供者是另一个本地解决方案(如 PingFederate),请参阅 Microsoft Entra Connect 的自定义安装主题,以配置与 Microsoft Entra ID 的联合身份验证。 或者,考虑使用 Spring 安全性通过 OAuth2/OpenID ConnectSAML 来使用标识提供者。

公开应用程序

默认情况下,部署到 Azure 容器应用的应用程序可通过应用程序 URL 访问。 如果你的应用部署在使用自己虚拟网络的托管环境中,则需要确定应用的可访问性级别,以允许公共流入或仅从虚拟网络流入。 有关详细信息,请参阅 Azure 容器应用环境中的网络

迁移后

现在你已完成迁移,请验证应用程序是否按预期运行。 然后可借助以下建议,提高应用程序的云原生性。

  • 请考虑将应用程序与 Spring Cloud 注册表配合使用。 此组件可让其他已部署的 Spring 应用程序和客户端动态发现你的应用程序。 有关详细信息,请参阅 在 Azure 容器应用中为 Eureka Server for Spring 组件配置设置。 然后,修改任何应用程序客户端以使用 Spring 客户端负载均衡器。 Spring Client 负载均衡器使客户端能够获取应用程序所有运行实例的地址,并在另一个实例损坏或无响应时找到可以运行的实例。 有关详细信息,请参阅 Spring 博客中的 Spring 提示:Spring 云负载均衡器

  • 请考虑添加 Spring Cloud 网关实例,而不是公开你的应用程序。 Spring Cloud Gateway 可为部署在 Azure 容器应用环境中的所有应用程序提供单一终结点。 如果已经部署了 Spring Cloud Gateway,请确保配置了路由规则,以便将流量路由到新部署的应用程序。

  • 考虑添加 Spring Cloud Config Server,以便集中管理所有 Spring Cloud 应用程序的配置并对其进行版本控制。 首先,创建一个 Git 存储库来存放配置,并配置应用程序实例来使用它。 有关详细信息,请参阅在 Azure 容器应用中为 Config Server for Spring 组件配置设置。 然后使用以下步骤迁移配置:

    1. 在应用程序的 src/main/resources 目录内,创建一个包含以下内容的 bootstrap.yml 文件

        spring:
          application:
            name: <your-application-name>
      
    2. 在配置 Git 存储库中,创建 <your-application-name>.yml 文件,其中 your-application-name 与上一步相同。 将 src/main/resourcesapplication.yml 文件的设置移到创建的新文件中。 如果这些设置以前在 .properties 文件中,则先将其转换为 YAML。 可以查找联机工具或 IntelliJ 插件来执行此转换。

    3. 在上述目录中创建一个 application.yml 文件。 可以使用此文件定义 Azure 容器应用环境中所有应用程序之间共享的设置和资源。 此类设置通常包括数据源、日志记录设置、Spring Boot Actuator 配置等。

    4. 提交这些更改并将其推送到 Git 存储库。

    5. 从应用程序中删除 application.properties 或 application.yml 应用程序

  • 考虑添加 Admin for Spring 托管组件,为公开执行器终结点的 Spring Boot Web 应用程序启用管理界面。 有关详细信息,请参阅在 Azure 容器应用中配置 Spring Boot 控制台组件

  • 请考虑为自动、一致的部署添加部署管道。 为 Azure 管道GitHub 操作均提供了说明。

  • 请考虑使用容器应用修订、修订标签和入口流量权重来实现蓝绿部署,这样就能在生产中测试代码变更,然后再将其提供给部分或全部最终用户。 有关详细信息,请参阅 Azure 容器应用中的蓝绿部署

  • 请考虑添加服务绑定,以便将应用程序连接到受支持的 Azure 数据库。 如果使用这些服务绑定,则无需向 Spring Cloud 应用程序提供连接信息(包括凭据)。

  • 请考虑启用 Java 开发堆栈来收集应用程序的 JVM 核心指标。 有关详细信息,请参阅 Azure 容器应用中 Java 应用的 Java 指标

  • 请考虑添加 Azure Monitor 预警规则和操作组,以快速检测并解决异常情况。 有关详细信息,请参阅在 Azure 容器应用中设置警报

  • 请考虑通过启用 Azure 容器应用区域冗余,在区域内跨区域复制应用。 如果发生区域中断,流量会负载均衡并自动路由到副本。 有关冗余设置的详细信息,请参阅 Azure 容器应用中的可靠性

  • 请考虑通过在应用程序网关上使用 Web 应用程序防火墙来保护 Azure 容器应用免受常见漏洞的攻击。 有关详细信息,请参阅使用应用程序网关上的 Web 应用程序防火墙保护 Azure 容器应用