你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

将 Tomcat 应用程序迁移到 Azure 容器应用

本指南指导你完成将现有 Tomcat 应用程序迁移到 Azure 容器应用的过程。 它涵盖迁移前评估、迁移本身和迁移后优化。

先决条件

迁移前评估

在开始迁移之前,请完成以下部分中介绍的评估和清单步骤。

清点外部资源

使用 Java 命名和目录接口(JNDI)注入外部资源,例如数据源、JMS 消息代理和其他资源。 其中一些资源可能需要迁移或重新配置。

在应用程序中

检查 META-INF/context.xml 文件。 查找 <Resource> 元素内的 <Context> 元素。

在应用程序服务器上

检查 $CATALINA_BASE/conf/context.xml$CATALINA_BASE/conf/server.xml 文件。 此外,检查 目录中的 < 文件。

context.xml 文件中,通过在顶级<Resource>元素内使用<Context>元素来描述 JNDI 资源。

server.xml 文件中,通过在 <Resource> 元素中使用 <GlobalNamingResources> 元素来描述 JNDI 资源。

数据源

数据源是 JNDI 资源, type 其属性设置为 javax.sql.DataSource. 对于每个数据源,请记录以下信息:

  • 数据源名称是什么?
  • 什么是连接池配置?
  • JDBC 驱动程序 JAR 文件在哪里?

有关详细信息,请参阅 Tomcat 文档中的 JNDI 数据源操作 说明。

所有其他的外部资源

在本指南中记录每个可能的外部依赖项是不可行的。 你的团队负责验证迁移后是否可以满足应用程序的每个外部依赖项。

清点密钥和证书

密码和安全字符串

检查生产服务器上的所有属性和配置文件,查找任何机密字符串和密码。 请务必在 $CATALINA_BASE/conf 中检查 server.xmlcontext.xml。 还可以在应用程序中查找包含密码或凭据的配置文件,包括 META-INF/context.xml ,以及 Spring Boot 应用程序、 application.propertiesapplication.yml 文件。

证书

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

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

查看文件系统使用情况

标识服务从本地文件系统读取或写入到的任何实例。 请注意哪些文件是短期或临时文件,哪些文件是长期存在的。

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

如果应用程序提供 只读静态内容,请考虑将其移动到 Azure Blob 存储并添加用于全局分发的 Azure CDN。 有关详细信息,请参阅 Azure 存储 中的静态网站托管快速入门:将 Azure 存储帐户与 Azure CDN 集成

如果应用程序处理 动态发布的静态内容 (在创建后上传或生成的内容不会更改),则可以集成 Azure Blob 存储和 Azure CDN。 还可以使用 Azure 函数来管理上传和触发 CDN 刷新。 有关示例实现,请参阅 使用 Azure Functions 上传和 CDN 预加载静态内容

如果应用程序当前提供 Tomcat Webapps/ 目录中的静态内容,请计划将该内容移动到外部存储解决方案作为迁移的一部分。

检查特定于操作系统的代码

如果应用程序包含具有主机 OS 依赖项的代码,请重构它以删除这些依赖项。 例如,将文件系统路径中/\的任何用法替换为File.SeparatorPaths.get

验证平台兼容性

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

在创建容器映像之前,请将应用程序迁移到要用于容器应用的 JDK 和 Tomcat 版本。 彻底测试应用程序,以确保兼容性和性能。

注释

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

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

java -version

标识会话持久性机制

若要标识正在使用的会话持久性管理器,请检查应用程序和 Tomcat 配置中的 context.xml 文件。 查找 <Manager> 元素,然后记下特性的值 className

Tomcat 的内置 PersistentManager 实现(如 StandardManagerFileStore)不设计用于分布式缩放平台,例如 Azure 容器应用。 容器应用可能会在多个实例之间进行负载均衡,并随时以透明方式重启任何实例,因此不建议将可变状态保存到文件系统。

如果需要会话持久性,请使用写入外部数据存储的备用 PersistentManager 实现,例如具有 Redis 缓存的 VMware Tanzu 会话管理器。

标识计划任务

你无法在容器化 Tomcat 部署中使用计划作业,如 Quartz Scheduler 任务或 cron 作业。 如果应用程序扩缩容,每个计划周期可能运行多个计划作业,导致意外后果。

清点应用程序服务器内外的任何计划作业。 短期任务或批处理式任务非常适合用于容器应用作业。 有关详细信息,请参阅 Azure 容器应用 中的作业

确定是否使用 MemoryRealm

MemoryRealm 需要持久化 XML 文件。 在 Azure 容器应用中,需要将此文件添加到容器映像,或将其上传到可供容器使用的共享存储。 有关详细信息,请参阅 “标识会话持久性机制 ”部分。 必须相应地修改 pathName 参数。

要确定 MemoryRealm 当前是否在使用,请检查 server.xmlcontext.xml 文件。 搜索 <Realm> 元素,其中 className 属性设置为 org.apache.catalina.realm.MemoryRealm

参数化配置

在预迁移期间,你可能在 server.xmlcontext.xml 文件中标识了机密和外部依赖项,例如数据源。 对于每个项,请将任何用户名、密码、连接字符串或 URL 替换为环境变量。

注释

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

例如,假设 context.xml 文件包含以下元素:

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="jdbc:postgresql://postgresdb.contoso.com/wickedsecret?ssl=true"
    driverClassName="org.postgresql.Driver"
    username="postgres"
    password="{password}"
/>

可以更改它,如以下示例所示:

<Resource
    name="jdbc/dbconnection"
    type="javax.sql.DataSource"
    url="${postgresdb.connectionString}"
    driverClassName="org.postgresql.Driver"
    username="${postgresdb.username}"
    password="${postgresdb.password}"
/>

评估日志记录和 应用性能管理 (APM)

确定要迁移的应用程序使用的任何日志聚合解决方案。 需要在迁移期间配置诊断设置,以便记录的事件可供使用。 有关详细信息,请参阅 “配置日志记录和诊断 ”部分。

确定应用程序使用的任何应用程序性能管理(APM)代理。 Azure 容器应用不提供内置的 APM 支持。 准备容器映像或将 APM 工具直接集成到代码中。 若要衡量应用程序的性能,但尚未集成任何 APM,请考虑将 Azure 应用程序 Insights 与自动检测 Java 代理配合使用。 有关详细信息,请参阅 为 Java 应用程序启用 Azure Monitor OpenTelemetry

文档部署体系结构

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

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

此外,确定是否在多个区域或数据中心之间分配应用程序实例。 记录要迁移的应用程序的运行时间要求和 SLA。

Migration

创建容器应用环境

在 Azure 订阅中创建容器应用环境。 有关详细信息,请参阅 Quickstart:使用 Azure 门户部署第一个容器应用

配置日志记录和诊断

配置日志记录以将所有输出路由到控制台而不是文件。

将应用程序部署到 Azure 容器应用后,可以在容器应用环境中配置日志记录选项以定义一个或多个日志目标。 这些目标可能包括 Azure Monitor Log Analytics、Azure 事件中心或非Microsoft监视解决方案。 您还可以禁用日志数据存储,并仅在运行时查看日志。 有关配置说明,请参阅 Azure 容器应用中的日志存储和监视选项

配置持久性存储

如果应用程序的任何部分读取或写入本地文件系统,请配置永久性存储以替换它。 例如,如果 Tomcat 应用程序将日志或上传到 /opt/tomcat/data,请创建 Azure 文件共享并将其装载到同一路径:

az containerapp update \
    --resource-group <RESOURCE_GROUP> \
    --name <APP_NAME> \
    --set-env-vars "UPLOAD_DIR=/opt/tomcat/data"

指定通过应用设置在容器中装载的路径,并将其与应用程序使用的路径保持一致。 有关详细信息,请参阅 在 Azure 容器应用中使用存储挂载

将证书迁移到 Azure 密钥保管库

Azure 容器应用支持应用之间的安全通信。 应用程序无需管理建立安全通信的过程。 可以将专用证书上传到 Azure 容器应用或使用免费的托管证书。 建议使用 Azure 密钥保管库 管理证书。

若要在 密钥保管库 中存储证书,并从容器应用引用它:

  1. 将证书导入 Azure 密钥保管库。 有关详细信息,请参阅 在 Azure 密钥保管库 中导入证书
  2. 在容器应用上启用托管标识,并在保管库上向其授予 密钥保管库 机密用户 角色。
  3. 将容器应用配置为将 密钥保管库 证书用于自定义域。

有关详细信息,请参阅 Azure 容器应用中的证书

准备部署项目

克隆 Tomcat on Containers Quickstart GitHub 存储库。 此存储库包含一个 Dockerfile 和 Tomcat 配置文件,其中包含许多建议的优化。 以下步骤概述了在生成容器映像并部署到容器应用之前可能需要对这些文件所做的修改。

注释

某些 Tomcat 部署在单个 Tomcat 服务器上运行多个应用程序。 如果此设置与部署匹配,请在单独的容器应用中运行每个应用程序。 通过使用此方法,可以优化每个应用程序的资源利用率,同时最大程度地降低复杂性和耦合性。

添加 JNDI 资源

编辑 server.xml 以添加在迁移前步骤(如数据源)中准备的资源,如以下示例所示:

注释

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

<!-- Global JNDI resources
      Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
    <!-- Editable user database that can also be used by
         UserDatabaseRealm to authenticate users
    -->
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml"
               />

    <!-- Migrated datasources here: -->
    <Resource
        name="jdbc/dbconnection"
        type="javax.sql.DataSource"
        url="${postgresdb.connectionString}"
        driverClassName="org.postgresql.Driver"
        username="${postgresdb.username}"
        password="${postgresdb.password}"
    />
    <!-- End of migrated datasources -->
</GlobalNamingResources>

有关更多数据源说明,请参阅 Tomcat 文档中 JNDI 数据源操作 说明的以下部分:

生成并推送映像

生成映像并将其上传到 Azure 容器注册表(ACR)以供容器应用使用的最简单方法是使用 az acr build 此命令。 此命令不需要在计算机上安装 Docker。 例如,如果当前目录中有 tomcat-container-quickstart 存储库中的 Dockerfile 和应用程序包 petclinic.war ,则可以使用以下命令在 ACR 中生成容器映像:

az acr build \
    --registry $acrName \
    --image "${acrName}.azurecr.io/petclinic:{{.Run.ID}}" \
    --build-arg APP_FILE=petclinic.war \
    --build-arg SERVER_XML=prod.server.xml .

如果 WAR 文件名为 --build-arg APP_FILE...,则可以省略该参数。 如果服务器 XML 文件命名--build-arg SERVER_XML...,则可以省略该参数。 这两个文件必须与 Dockerfile 位于同一目录中。

或者,可以使用 Docker CLI 通过以下命令在本地生成映像。 在初始部署到 ACR 之前,此方法可以简化映像测试和优化。 但是,它要求安装 Docker CLI,并运行 Docker 守护程序。

# Build the image locally.
docker build . --build-arg APP_FILE=petclinic.war -t "${acrName}.azurecr.io/petclinic:1"

# Run the image locally.
docker run -d -p 8080:8080 "${acrName}.azurecr.io/petclinic:1"

# You can now access your application with a browser at http://localhost:8080.

# Sign in to ACR.
az acr login --name $acrName

# Push the image to ACR.
docker push "${acrName}.azurecr.io/petclinic:1"

注释

在 Linux 上,如果用户不在docker组中,可能需要为命令sudo添加前缀docker

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

部署到 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

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

配置机密和环境变量

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

设置标识和身份验证

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

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

如果应用程序使用 Tomcat 领域进行身份验证(例如, MemoryRealmJDBCRealm),计划迁移到外部标识提供者或在容器映像中配置领域。

公开应用程序

默认情况下,部署到 Azure 容器应用的应用程序无法从环境外部访问。 若要启用外部访问,请配置入口:

az containerapp ingress enable \
    --resource-group <RESOURCE_GROUP> \
    --name <APP_NAME> \
    --type external \
    --target-port 8080 \
    --transport auto

如果你在带自有虚拟网络的托管环境中部署应用,确定应用的可访问级别,允许公共入口或仅来自虚拟网络的入口。 有关详细信息,请参阅 Azure 容器应用 环境中的 Networking

迁移后

完成迁移后,请验证应用程序是否按预期工作。 以下部分介绍了有关使应用程序更具云原生性和可操作性的建议。

改进操作准备情况

以下建议可帮助你增强迁移应用程序的可靠性、可观测性和部署做法。

  • CI/CD 管道:添加一个用于自动且一致部署的管道。 可以查看有关 Azure PipelinesGitHub Actions 的说明。
  • 蓝绿部署:使用容器应用修订、修订标签和入口流量权重测试生产中的代码更改,然后再将其提供给最终用户。 有关详细信息,请参阅 Azure 容器应用 中的蓝绿部署
  • 服务绑定:添加服务绑定以将应用程序连接到受支持的 Azure 数据库。 服务绑定无需向 Spring Boot 应用程序提供连接信息(包括凭据)。
  • JVM 指标:启用 Java 开发堆栈以收集 JVM 核心指标。 有关详细信息,请参见 Azure 容器应用 中的 Java 应用程序的 Java 指标
  • 警报:添加 Azure Monitor 警报规则和操作组,以快速检测和解决异常情况。 有关详细信息,请参阅 在 Azure 容器应用
  • 区域冗余:通过启用区域冗余跨可用性区域复制应用。 如果发生区域中断,流量会负载均衡并自动路由到副本。 有关详细信息,请参阅 Azure 容器应用中的可靠性
  • Web 应用程序防火墙:在应用程序网关上使用 Web 应用程序防火墙保护容器应用免受常见攻击和漏洞的影响。 有关详细信息,请参阅通过应用程序网关上的网页应用防火墙保护Azure容器应用

Tomcat 的特定建议

  • 若要提高性能,请评估 logging.properties 文件中的项。 请考虑消除或减少某些日志记录输出。

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