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

本指南介绍迁移现有 Spring Boot 应用程序以在 ACA (ACA) 上运行的现有 Spring Boot 应用程序时应注意的内容。

预迁移

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

验证支持的 Java 版本是否正常运行

建议在 ACA 上运行 Spring Boot 应用程序时使用受支持的 Java 版本。 确认应用程序使用受支持的版本正常运行。

注意

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

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

java -version

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

如果 Spring Boot 应用程序要使用文件系统,则需要重新配置,在极少数情况下需要体系结构更改。 可以标识以下部分所述的部分或全部方案。

只读静态内容

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

动态发布的静态内容

如果应用程序允许那些通过应用程序上传/生成但在创建后不可变的静态内容,则可将上述 Azure Blob 存储和 Azure CDN 与 Azure 函数配合使用,以便处理上传和 CDN 刷新操作。 我们提供了一个示例实现,用于通过 Azure Functions 进行静态内容的上传和 CDN 预加载操作

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

不应将计划作业(如Tzron 计划程序任务或 Unix cron 作业)用于 Azure Kubernetes 服务 (AKS) 。 Azure Kubernetes 服务不会阻止你部署内含计划任务的应用程序。 但是,如果应用程序横向扩展,则同一个计划的作业可能会按照计划期间运行多次。 这种情况可能会导致意外的后果。

若要在 AKS 群集上执行计划的作业,请按需定义 Kubernetes CronJob。 有关详细信息,请参阅使用 CronJob 运行自动化任务

确定是否需要连接到本地

如果应用程序需要访问任何本地服务,则需预配 Azure 的某个连接服务。 有关详细信息,请参阅选择用于将本地网络连接到 Azure 的解决方案。 或者,你需要重构应用程序,以便使用本地资源公开的公开可用的 API。

确定应用程序是否包含特定于 OS 的代码

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

确定在生产服务器上运行的所有外部进程和守护程序

如果在应用程序服务器外运行任何进程(如监视守护程序),则需消除它们或将它们迁移到其他位置。

确定 Spring Boot 版本

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

Maven

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

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

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

plugins {
  id 'org.springframework.boot' version '2.2.6.RELEASE'
  id 'io.spring.dependency-management' version '1.0.9.RELEASE'
  id 'java'
}

对于使用 Spring Boot 1.x 的任何应用程序,请按照 Spring Boot 2.0 迁移指南将其更新为受支持的 Spring Boot 版本。

查看数据库属性

如果应用程序使用数据库,请查看 application.properties 文件中的数据库属性,以确保 Spring Boot 应用程序在迁移到 ACA 后仍可访问该数据库。 如果数据库在本地,则需要将其迁移到云,或建立与本地数据库的连接。

确定日志聚合解决方案

确定要迁移的应用程序正在使用的任何日志聚合解决方案。

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

确定与应用程序一起使用的任何应用程序性能监视代理(例如 Dynatrace 和 Datadog)。 需要重新配置这些 APM 代理以包含在 Dockerfile 或 Jib 配置中,或使用 Application Insights 进程内 Java 代理。

确定 Zipkin 依赖项

确定应用程序是否在 Zipkin 上具有显式依赖项。 在 Maven 或 Gradle 依赖项中查找 io.zipkin.java 组的依赖项。

清点外部资源

标识外部资源,如数据源、JMS 消息代理和其他服务的 URL。 在 Spring Boot 应用程序中,通常可在通常名为 application.properties 或 application.yml 的文件的 src/main/directory 文件夹中找到此类资源的配置 。 此外,请查看生产部署的环境变量,了解任何相关的配置设置。

数据库

确定任何 SQL 数据库的连接字符串。

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.0.4.0")
      ...
    }

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

下面是 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=tryandguess

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

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

ibm:
  mq:
    queueManager: qm1
    channel: dev.ORDERS
    connName: localhost(14)
    user: admin
    password: big$ecr3t

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

确定外部缓存

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

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

清单配置源和机密

清单密码和安全字符串

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

清点证书

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

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

检查部署体系结构

记录每个服务的硬件要求

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

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

记录异地复制/分发

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

标识提供者

确定需要身份验证和/或授权的所有标识提供者和所有 Spring Boot 应用程序。 有关如何配置标识提供者的信息,请参阅以下资源:

通过 VMware Tanzu 应用程序服务(TAS,之前称为 Pivotal Cloud Foundry)配置的资源

对于使用 TAS 托管的应用程序,通常通过 TAS 服务绑定配置外部资源(包括前面所述的资源)。 若要检查此类资源的配置,请使用 TAS (Cloud Foundry) CLI 查看 VCAP_SERVICES 应用程序的变量,如以下示例所示:

# Sign in to TAS, if needed (enter credentials when prompted)
cf login -a <API endpoint>

# Set the organization and space containing the application, if not already selected during login.
cf target org <Organization Name>
cf target space <Space Name>

# Display variables for the application
cf env <Application Name>

检查绑定到应用程序的外部服务配置设置的 VCAP_SERVICES 变量。 有关详细信息,请参阅 TAS (Cloud Foundry) 文档

就地测试

在创建容器映像之前,请将应用程序迁移到要用于 Azure Kubernetes 服务 (AKS) 的 JDK 和 Spring Boot 版本。 全面测试应用程序,确保兼容性和性能。

迁移

创建 Spring Boot 的 Docker 映像

若要创建 Dockerfile,需要符合以下先决条件:

  • 受支持的 JDK。
  • JVM 运行时选项。
  • 可以通过某种方法传入环境变量(如果适用)。

然后,可以执行以下部分所述的步骤(如果适用)。 对于 Dockerfile 和 Spring Boot 应用程序,可以从使用 Spring Boot 容器快速入门存储库着手。

构建 Docker 映像并将其推送到 Azure 容器注册表

创建 Dockerfile 后,需要生成 Docker 映像并将其发布到 Azure 容器注册表。

如果你使用了我们的 Spring Boot 容器快速入门 GitHub 存储库,则构建映像并将其推送到 Azure 容器注册表的过程相当于调用以下三个命令。

在这些示例中,MY_ACR 环境变量保存 Azure 容器注册表的名称,MY_APP_NAME 变量保存要在 Azure 容器注册表中使用的 Web 应用程序的名称。

使用以下命令生成部署文件:

mvn package

使用以下命令登录到 Azure 容器注册表:

az acr login --name ${MY_ACR}

使用以下命令生成和推送映像。

az acr build --image ${MY_ACR}.azurecr.io/${MY_APP_NAME} .

也可使用 Docker CLI 在本地生成并测试映像,如以下命令所示。 此方法可以简化在一开始部署到 ACR 之前对映像进行的测试和优化。 但是,它要求安装 Docker CLI 并确保 Docker 后台程序正在运行。

使用以下命令生成映像:

docker build -t ${MY_ACR}.azurecr.io/${MY_APP_NAME}

使用以下命令在本地运行映像:

docker run -it -p 8080:8080 ${MY_ACR}.azurecr.io/${MY_APP_NAME}

现在可以在 http://localhost:8080 上访问应用程序。

使用以下命令登录到 Azure 容器注册表:

az acr login --name ${MY_ACR}

使用以下命令将映像推送到 Azure 容器注册表:

docker push ${MY_ACR}.azurecr.io/${MY_APP_NAME}

有关在 Azure 中生成和存储容器映像的详细信息,请参阅使用 Azure 容器注册表 生成和存储容器映像

如果使用了 Spring Boot 容器快速入门 GitHub 存储库,还可以添加自定义密钥存储,该密钥存储将在启动时添加到 JVM。 如果将密钥存储文件放在 /opt/spring-boot/mycert.crt,则会发生这种添加操作。 可以通过将文件直接添加到 Dockerfile 来执行此操作。

如果使用了 Spring Boot 容器快速入门 GitHub 存储库,还可以通过在 Kubernetes 部署文件中设置 APPLICATIONINSIGHTS_CONNECTION_STRING 环境变量来启用 Application Insights。 环境变量的值应类似于 InstrumentationKey=00000000-0000-0000-0000-00000000000000。 有关详细信息,请参阅 Java 无代码应用程序监视 Azure Monitor Application Insights

如果不需要对 Docker 映像进行任何自定义,也可以浏览 Maven Jib 插件的使用。

部署到 Azure 容器应用

以下命令展示的是一个示例部署:

az containerapp create \
    --resource-group <RESOURCE_GROUP> \
    --name <APP_NAME> \
    --environment <ENVIRONMENT_NAME> \
    --image <IMAGE_NAME> \
    --target-port 8080 \
    --ingress 'external' \
    --registry-server <REGISTRY_SERVER> \
    --min-replicas 1

有关更深入的快速入门,请参阅 快速入门:部署第一个容器应用

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

配置日志记录,使所有应用程序都记录到控制台而不是文件。

LogStash/ELK 堆栈

如果使用 LogStash/ELK Stack 进行日志聚合,请将诊断设置配置为将控制台输出流式传输到Azure 事件中心。 然后,使用 LogStash EventHub 插件将记录的事件引入到 LogStash 中。

Splunk

如果使用 Splunk 进行日志聚合,请将诊断设置配置为将控制台输出流式传输到 Azure Blob 存储。 然后,使用 Microsoft 云服务的 Splunk 附加产品将记录的事件引入到 Splunk 中。

迁移和启用标识提供者

如果任何 Spring Boot 应用程序需要身份验证或授权,请确保它们已配置为使用以下指南访问标识提供者:

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

迁移后

将应用程序迁移到 ACA 后,应验证它是否按预期工作。 完成该操作后,可以参考我们提供的一些建议,使应用程序的云原生性更好。

建议

  • 设计和实施 DevOps 策略。 为了在提高开发速度的同时保持可靠性,请考虑使用 Azure Pipelines 或 GitHub Actions 自动部署和测试。

  • 考虑通过 Prometheus 公开特定于应用程序的指标。 Prometheus 是在 Kubernetes 社区中广泛采用的开源指标框架。 可以在 Azure Monitor 中配置 Prometheus 指标擦除,而不是托管自己的 Prometheus 服务器。 Prometheus 指标擦除允许从应用程序聚合指标,并自动响应或升级异常条件。 有关详细信息,请参阅 使用容器见解配置 Prometheus 指标的擦除

  • 考虑监视代码缓存大小并向 Dockerfile 中的 JAVA_OPTS 变量添加参数 -XX:InitialCodeCacheSize-XX:ReservedCodeCacheSize,进一步优化性能。 有关详细信息,请参阅 Oracle 文档中的 Codecache Tuning(Codecache 优化)。

  • 请考虑添加 Azure Monitor 预警规则和操作组,以快速检测并解决异常情况。

  • 请考虑复制另一个区域中的 Azure 容器应用部署,以提高延迟和更高的可靠性和容错能力。 使用 Azure 流量管理器在部署之间实现负载均衡,或使用 Azure Front Door 添加 SSL 卸载和具有 DDoS 防护的 Web 应用程序防火墙。

  • 如果不需要异地复制,请考虑添加 Azure 应用程序网关,以便添加 SSL 卸载和具有 DDoS 防护的 Web 应用程序防火墙。