将 Tomcat 应用程序迁移到 Azure 应用程序服务上的 Tomcat

本指南介绍在需要迁移现有 Tomcat 应用程序以使之在使用 Tomcat 9.0 的 Azure 应用程序服务上运行时应注意的事项。

预迁移

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

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

切换到受支持的平台

应用程序服务在特定版本的 Java 上提供特定版本的 Tomcat。 若要确保兼容性,请在继续执行其余步骤之前,将应用程序迁移到当前环境中支持的 Tomcat 和 Java 版本之一。 务必全面测试生成的配置。 请在此类测试中使用最新且稳定的 Linux 发布版。

注意

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

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

java -version

在 Azure 应用程序服务中,Java 8 的二进制文件由 Eclipse Temurin 提供。 对于 Java 11、17 和未来所有 LTS 版本的 Java,应用程序服务提供了 Microsoft Build of OpenJDK。 这些二进制文件可在以下网站免费下载:

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

${CATALINA_HOME}/bin/version.sh

若要获取 Azure 应用程序服务使用的当前版本,请下载 Tomcat 9,具体取决于你计划在 Azure 应用程序服务中使用的版本。

清点外部资源

外部资源(如数据源、JMS 消息代理等)通过 Java 命名和目录接口 (JNDI) 注入。 某些此类资源可能需要迁移或重新配置。

在应用程序中

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

在应用程序服务器上

检查 $CATALINA_BASE/conf/context.xml$CATALINA_BASE/conf/server.xml 文件,以及在 $CATALINA_BASE/conf/[engine-name]/[host-name] 目录中发现的 .xml 文件。

context.xml 文件中,JNDI 资源将由顶级 <Context> 元素中的 <Resource> 元素描述。

server.xml 文件中,JNDI 资源将由 <GlobalNamingResources> 元素中的 <Resource> 元素描述。

Datasources

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

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

有关详细信息,请参阅 Tomcat 文档中的 JNDI Datasource HOW-TO(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 Blob 存储,并添加 Azure CDN,方便用户在全球范围内快速下载。 有关详细信息,请参阅 Azure 存储中的静态网站托管快速入门:将 Azure 存储帐户与 Azure CDN 集成

动态发布的静态内容

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

动态或内部内容

对于经常由应用程序写入和读取的文件(如临时数据文件),或者仅对应用程序可见的静态文件,可以将 Azure 存储装载到应用程序服务文件系统中。 有关详细信息,请参阅将 Azure 存储装载为应用程序服务中的本地共享

识别会话持久性机制

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

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

如果需要会话持久性,则需要使用会将内容写入外部数据存储的备用 PersistentManager 实现,例如使用 Redis 缓存的 VMware Tanzu 会话管理器。 有关详细信息,请参阅将 Redis 作为会话缓存与 Tomcat 配合使用

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

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

特殊情况

某些生产方案可能需要进行其他更改或施加额外的限制。 虽然这种情况可能不怎么出现,但务必确保它们不适用于应用程序,或者在适用于应用程序的情况下已得到正确解决。

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

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

清点应用程序服务器内外部所有计划的作业。

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

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

确定是否使用了 Tomcat 聚类分析

Azure 应用程序服务不支持 Tomcat 聚类分析。 可以改为通过 Azure 应用程序服务来配置和管理缩放和负载均衡,无需使用特定于 Tomcat 的功能。 可以将会话状态持久保存到备用位置,使之可以跨副本使用。 有关详细信息,请参阅识别会话持久性机制

若要确定应用程序是否使用聚类分析,请在 server.xml 文件中查找 <Host><Engine> 元素内的 <Cluster> 元素。

确定是否使用了非 HTTP 连接器

应用程序服务仅支持单个 HTTP 连接器。 如果应用程序需要其他连接器(如 AJP 连接器),请不要使用应用程序服务。

若要确定应用程序使用的 HTTP 连接器,请在 Tomcat 配置中查找 server.xml 文件中的 <Connector> 元素。

确定是否使用了 MemoryRealm

MemoryRealm 需要一个持久的 XML 文件。 在 Azure 应用程序服务上,需要将此文件上传到 /home 目录或其子目录之一,或上传到装载的存储。 然后需要相应地修改 pathName 参数。

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

确定是否使用了 SSL 会话跟踪

应用程序服务在 Tomcat 运行时外部执行会话卸载,因此无法使用 SSL 会话跟踪。 请改用另一会话跟踪模式(COOKIEURL)。 如果需要 SSL 会话跟踪,请不要使用应用程序服务。

确定是否使用了 AccessLogValve

如果使用 AccessLogValve,则应将 directory 参数设置为 /home/LogFiles 或其子目录之一。

迁移

将配置参数化

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

例如,假设 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="t00secure2gue$$"
/>

在这种情况下,可以对其进行更改,如以下示例所示:

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

要确保参数替换适用于已部署的 .war 文件中 META-INF 文件夹内的任何 context.xml 文件,请务必设置 CATALINA_OPTS 环境变量,如下例所示:

export CATALINA_OPTS="-Dorg.apache.tomcat.util.digester.PROPERTY_SOURCE=org.apache.tomcat.util.digester.EnvironmentPropertySource"

预配应用程序服务计划

应用程序服务定价的可用服务计划列表中,选择其规格满足或超过当前生产硬件规格的计划。

注意

如果计划运行过渡/Canary 部署或使用部署槽位,应用程序服务计划必须包含该附加容量。 建议对 Java 应用程序使用高级或更高等级的计划。 有关详细信息,请参阅设置 Azure 应用程序服务中的过渡环境

然后,创建应用程序服务计划。 有关详细信息,请参阅在 Azure 中管理应用程序服务计划

创建和部署 Web 应用

需要在应用程序服务计划(选择一个版本的 Tomcat 作为运行时堆栈)中针对部署到 Tomcat 服务器的每个 WAR 文件创建一个 Web 应用。

注意

虽然可以将多个 WAR 文件部署到单个 Web 应用,但这根本没有必要。 如果将多个 WAR 文件部署到单个 Web 应用,则会妨碍每个应用程序根据其自身的使用需求进行缩放。 另外,这样还会增加后续部署管道的复杂性。 如果单个 URL 上需要有多个可用的应用程序,请考虑使用路由解决方案,如 Azure 应用程序网关

Maven 应用程序

如果应用程序是从 Maven POM 文件生成的,则请使用 Maven 的 Webapp 插件来创建 Web 应用并部署应用程序。

非 Maven 应用程序

如果无法使用 Maven 插件,则需通过如下所示的其他机制来预配 Web 应用:

创建 Web 应用后,请使用提供的部署机制之一来部署应用程序。

迁移 JVM 运行时选项

如果应用程序需要特定的运行时选项,请使用最适合的机制来指定它们

填充机密

使用“应用程序设置”存储特定于应用程序的任何机密。 若要在多个应用程序中使用相同的机密,或者需要精细的访问策略和审核功能,请改为使用 Azure Key Vault

配置自定义域和 SSL

如果应用程序将在自定义域上可见,则需将 Web 应用程序映射到它。 有关详细信息,请参阅教程:将现有的自定义 DNS 名称映射到 Azure 应用程序服务

然后,需将该域的 SSL 证书绑定到应用程序服务 Web 应用。 有关详细信息,请参阅在 Azure 应用程序服务中使用 SSL 绑定保护自定义 DNS 名称

导入后端证书

需将所有用于与后端系统(如数据库)通信的证书提供给应用程序服务。 有关详细信息,请参阅在应用程序服务中添加 SSL 证书

迁移数据源、库和 JNDI 资源

有关数据源配置步骤,请参阅为 Azure 应用程序服务配置 Linux Java 应用中的数据源部分。

如需更多的数据源说明,请参阅 Tomcat 文档中 JNDI Datasource How-To(JNDI 数据源操作方法)的以下部分:

按照数据源 JAR 文件的步骤迁移任何其他服务器级 classpath 依赖关系。

迁移任何其他共享服务器级 JDNI 资源

注意

如果遵循一个 webapp 一个 WAR 这样一种建议的体系结构,请考虑将服务器级 classpath 库和 JNDI 资源迁移到应用程序中。 这会大大简化组件管理和变更管理。

迁移剩余配置

完成上述部分后,应在 /home/tomcat/conf 中安装可自定义的服务器配置。

复制任何其他配置(如领域JASPIC),完成迁移。

迁移计划的作业

若要在 Azure 上执行计划的作业,请考虑使用 Azure Functions 的计时器触发器。 无需将作业代码本身迁移到函数中。 函数可以直接在应用程序中调用 URL 来触发作业。 如果必须动态调用和/或集中跟踪此类作业执行情况,请考虑使用 Spring Batch

也可使用定期触发器来创建逻辑应用,以便调用 URL,而无需在应用程序外编写任何代码。 有关详细信息,请参阅概述 - 什么是 Azure 逻辑应用?通过 Azure 逻辑应用中的定期触发器来创建、计划和运行重复执行的任务和工作流

注意

若要防止恶意使用,可能需确保作业调用终结点要求使用凭据。 在这种情况下,触发器函数需要提供凭据。

重启和冒烟测试

最后,需重启 Web 应用以应用所有配置更改。 重启完成后,请验证应用程序是否正常运行。

迁移后

将应用程序迁移到 Azure 应用程序服务后,即应验证其运行是否符合预期。 完成此操作后,可以参考我们提供的一些建议,使应用程序的云原生性更好。

建议