在 Azure 应用服务中部署和配置 Tomcat 或 Java SE 应用

本文介绍应用服务中 Java 应用的最常见部署和运行时配置。 如果你从未用过 Azure 应用服务,首先应该通读 Java 快速入门应用服务常见问题解答中解答了有关使用应用服务且非特定于 Java 开发的一般问题。

Azure 应用服务以三种形式在完全托管的服务上运行 Java Web 应用程序:

  • Java SE - 可以运行作为 JAR 包(其中包含嵌入式服务器)部署的应用(例如 Spring Boot、Dropwizard、Quarkus,或包含嵌入式 Tomcat 或 Jetty 服务器的应用)。
  • Tomcat - 内置的 Tomcat 服务器可以运行作为 WAR 包部署的应用。

注意

对于 Spring 应用程序,我们建议使用 Azure Spring Apps。 但是,你仍然可以使用 Azure 应用服务作为目标。

显示 Java 版本

若要显示当前的 Java 版本,请在 bash 中运行以下命令:

az webapp config show --resource-group <resource-group-name> --name <app-name> --query linuxFxVersion

若要显示所有受支持的 Java 版本,请在 bash 中运行以下命令:

az webapp list-runtimes --os linux | grep "JAVA\|TOMCAT\|JBOSSEAP"

有关版本支持的详细信息,请参阅应用服务语言运行时支持策略

部署应用

生成工具

Maven

使用适用于 Azure Web 应用的 Maven 插件,可以在项目根中使用一个命令来轻松为 Azure Web 应用准备 Maven Java 项目:

mvn com.microsoft.azure:azure-webapp-maven-plugin:2.13.0:config

此命令会提示你选择现有的或创建新的 Azure Web 应用,通过这种方式来添加 azure-webapp-maven-plugin 插件和相关配置。 在配置期间,它会尝试检测应用程序是否应部署到 Java SE、Tomcat。 然后可以使用以下命令将 Java 应用部署到 Azure:

mvn package azure-webapp:deploy

下面是 pom.xml 中的示例配置:

<plugin> 
  <groupId>com.microsoft.azure</groupId>  
  <artifactId>azure-webapp-maven-plugin</artifactId>  
  <version>2.11.0</version>  
  <configuration>
    <subscriptionId>111111-11111-11111-1111111</subscriptionId>
    <resourceGroup>spring-boot-xxxxxxxxxx-rg</resourceGroup>
    <appName>spring-boot-xxxxxxxxxx</appName>
    <pricingTier>B2</pricingTier>
    <region>westus</region>
    <runtime>
      <os>Linux</os>      
      <webContainer>Java SE</webContainer>
      <javaVersion>Java 17</javaVersion>
    </runtime>
    <deployment>
      <resources>
        <resource>
          <type>jar</type>
          <directory>${project.basedir}/target</directory>
          <includes>
            <include>*.jar</include>
          </includes>
        </resource>
      </resources>
    </deployment>
  </configuration>
</plugin> 

Gradle

  1. 通过将适用于 Azure Web 应用的 Gradle 插件添加到 build.gradle 来设置该插件:

    plugins {
      id "com.microsoft.azure.azurewebapp" version "1.10.0"
    }
    
  2. 配置 Web 应用详细信息。 如果相应的 Azure 资源不存在,则会创建它们。 下面是示例配置。有关详细信息,请查看此文档

    azurewebapp {
        subscription = '<your subscription id>'
        resourceGroup = '<your resource group>'
        appName = '<your app name>'
        pricingTier = '<price tier like 'P1v2'>'
        region = '<region like 'westus'>'
        runtime {
          os = 'Linux'
          webContainer = 'Tomcat 10.0' // or 'Java SE' if you want to run an executable jar
          javaVersion = 'Java 17'
        }
        appSettings {
            <key> = <value>
        }
        auth {
            type = 'azure_cli' // support azure_cli, oauth2, device_code and service_principal
        }
    }
    
  3. 使用一个命令进行部署。

    gradle azureWebAppDeploy
    

IDE

Azure 在常用 Java IDE 中提供了无缝的 Java 应用服务开发体验,这些 IDE 包括:

Kudu API

若要将 .jar 文件部署到 Java SE,请使用 Kudu 站点的 /api/publish 终结点。 有关此 API 的详细信息,请参阅此文档

注意

必须将 .jar 应用程序命名为 app.jar,应用服务才能识别并运行该应用程序。 Maven 插件会在部署期间自动执行此操作。 如果不希望将 JAR 重命名为 app.jar,可使用命令上传 shell 脚本来运行 .jar 应用。 将此脚本的绝对路径粘贴到门户的“配置”部分的启动文件文本框中。 启动脚本不从放置它的目录运行。 因此,请始终使用绝对路径在启动脚本中引用文件(例如:java -jar /home/myapp/myapp.jar)。

若要将 .war 文件部署到 Tomcat,请使用 /api/wardeploy/ 终结点对存档文件执行 POST 操作。 有关此 API 的详细信息,请参阅此文档

不要使用 FTP 来部署 .war 或 .jar。 FTP 工具设计用来上传启动脚本、依赖项或其他运行时文件。 它不是用于部署 Web 应用的最佳选项。

重写或重定向 URL

若要重写或重定向 URL,请使用可用的 URL 重写程序之一,例如 UrlRewriteFilter

Tomcat 还提供重写阀

日志记录和调试应用

可以通过 Azure 门户对每个应用使用性能报告、流量可视化和运行状况检查。

流式传输诊断日志

可以访问在容器中生成的控制台日志。

首先,请运行以下命令,以便启用容器日志记录功能:

az webapp log config --name <app-name> --resource-group <resource-group-name> --docker-container-logging filesystem

<app-name><resource-group-name> 替换为适合 Web 应用的名称。

启用容器日志记录功能以后,请运行以下命令来查看日志流:

az webapp log tail --name <app-name> --resource-group <resource-group-name>

如果没有立即看到控制台日志,请在 30 秒后重新查看。

若要随时停止日志流式处理,可键入 CtrlC。

也可通过浏览器在 https://<app-name>.scm.chinacloudsites.cn/api/logs/docker 中检查日志文件。

Linux 中的 SSH 控制台访问

若要通过容器打开直接的 SSH 会话,应用应该处于正在运行状态。

将以下 URL 粘贴到浏览器中,将 <app-name> 替换为应用名称:

https://<app-name>.scm.chinacloudsites.cn/webssh/host

如果尚未进行身份验证,则需通过要连接的 Azure 订阅进行身份验证。 完成身份验证以后,可以看到一个浏览器内 shell,可以在其中的容器中运行命令。

SSH 连接

注意

/home 目录之外进行的任何更改均存储在容器本身中,在应用重启后不保留。

若要从本地计算机打开远程 SSH 会话,请参阅从远程 shell 打开 SSH 会话

Linux 故障排除工具

内置的 Java 映像建立在 Alpine Linux 操作系统上。 使用 apk 包管理器安装任何故障排除工具或命令。

Java 探查器

Azure 应用服务上的所有 Java 运行时都附带 JDK 运行情况记录器,用于分析 Java 工作负载。 你可以使用它来记录 JVM、系统和应用程序事件,并排查应用程序中的问题。

若要了解有关 Java 探查器的详细信息,请访问 Azure Application Insights 文档

网络流量记录器

应用服务上的所有 Java 运行时都附带 Java Flight Recorder。 可以使用它来记录 JVM、系统和应用程序事件,并对 Java 应用程序中的问题进行故障排除。

使用 SSH 进入应用服务,运行 jcmd 命令以查看所有正在运行的 Java 进程的列表。 除了 jcmd 本身,你还会看到正在运行的 Java 应用程序以及进程 ID 号 (PID)。

078990bbcd11:/home# jcmd
Picked up JAVA_TOOL_OPTIONS: -Djava.net.preferIPv4Stack=true
147 sun.tools.jcmd.JCmd
116 /home/site/wwwroot/app.jar

执行以下命令以启动 JVM 的 30 秒录制。 它会分析 JVM 并在主目录创建一个名为“jfr_example.jfr”的 JFR 文件。 (将 116 替换为 Java 应用的 PID。)

jcmd 116 JFR.start name=MyRecording settings=profile duration=30s filename="/home/jfr_example.jfr"

在 30 秒的间隔内,可以通过运行 jcmd 116 JFR.check 来验证记录是否正在进行。 该命令会显示给定 Java 进程的所有录制。

连续记录

你可以使用 Java Flight Recorder 在对运行时的性能影响最小的情况下连续分析 Java 应用程序。 为此,请运行以下 Azure CLI 命令,通过必要的配置创建名为 JAVA_OPTS 的应用设置。 应用启动后,JAVA_OPTS 应用设置的内容会被传递到 java 命令。

az webapp config appsettings set -g <your_resource_group> -n <your_app_name> --settings JAVA_OPTS=-XX:StartFlightRecording=disk=true,name=continuous_recording,dumponexit=true,maxsize=1024m,maxage=1d

开始记录后,你可以使用 JFR.dump 命令随时转储当前的记录数据。

jcmd <pid> JFR.dump name=continuous_recording filename="/home/recording1.jfr"

分析 .jfr 文件

使用 FTPS 将 JFR 文件下载到本地计算机。 如果要分析 JFR 文件,请下载并安装 Java Mission Control。 有关 Java Mission Control 的说明,请参阅 JMC 文档安装说明

应用日志记录

通过 Azure 门户或 Azure CLI 启用应用程序日志记录,以将应用服务配置为向本地文件系统或 Azure Blob 存储写入应用程序的标准控制台输出和标准控制台错误流。 如果需要保留日志更长时间,请将应用程序配置为向 Blob 存储容器写入输出。

Java 和 Tomcat 应用日志位于 /home/LogFiles/Application/ 目录中。

只能使用 Azure Monitor 配置适用于基于 Linux 的应用的 Azure Blob 存储日志记录。

如果应用程序使用 LogbackLog4j 进行跟踪,则你可以遵照在 Application Insights 中浏览 Java 跟踪日志中的日志记录框架配置说明,将这些用于审查的跟踪写入到 Azure Application Insights。

注意

由于已知漏洞 CVE-2021-44228,请务必使用 Log4j 版本 2.16 或更高版本。

自定义和优化

Azure 应用服务原生支持通过 Azure 门户和 CLI 进行优化和自定义。 请查看以下文章了解非特定于 Java 的 Web 应用配置:

在本地复制应用内容

将应用设置 JAVA_COPY_ALL 设为 true,以将应用内容从共享文件系统复制到本地辅助角色。 此设置有助于解决文件锁定问题。

设置 Java 运行时选项

若要设置分配的内存或其他 JVM 运行时选项,请使用这些选项创建名为 JAVA_OPTS应用设置。 应用服务在启动时,会将此设置作为环境变量传递给 Java 运行时。

在 Azure 门户中 Web 应用的“应用程序设置”下,创建名为 CATALINA_OPTS 且包含其他设置的新应用设置,例如 -Xms512m -Xmx1204m

若要通过 Maven 插件配置应用设置,请在 Azure 插件部分中添加设置/值标记。 以下示例设置特定的最小和最大 Java 堆大小:

<appSettings>
    <property>
        <name>JAVA_OPTS</name>
        <value>-Xms1024m -Xmx1024m</value>
    </property>
</appSettings>

注意

在 Windows 应用服务上使用 Tomcat 时,无需创建 web.config 文件。

在应用服务计划中运行包含一个部署槽位的单个应用程序的开发人员可以使用以下选项:

  • B1 和 S1 实例:-Xms1024m -Xmx1024m
  • B2 和 S2 实例:-Xms3072m -Xmx3072m
  • B3 和 S3 实例:-Xms6144m -Xmx6144m
  • P1v2 实例:-Xms3072m -Xmx3072m
  • P2v2 实例:-Xms6144m -Xmx6144m
  • P3v2 实例:-Xms12800m -Xmx12800m
  • P1v3 实例:-Xms6656m -Xmx6656m
  • P2v3 实例:-Xms14848m -Xmx14848m
  • I1 实例:-Xms3072m -Xmx3072m
  • I2 实例:-Xms6144m -Xmx6144m
  • I3 实例:-Xms12800m -Xmx12800m
  • I1v2 实例:-Xms6656m -Xmx6656m
  • I2v2 实例:-Xms14848m -Xmx14848m
  • I3v2 实例:-Xms30720m -Xmx30720m

优化应用程序堆设置时,请查看应用服务计划详细信息,并考虑多个应用程序和部署槽位方面的需求,以得出最佳内存分配。

启用 Web 套接字

在 Azure 门户中应用程序的“应用程序设置”中启用 Web 套接字支持。 需要重启应用程序才能使设置生效。

在 Azure CLI 中使用以下命令启用 Web 套接字支持:

az webapp config set --name <app-name> --resource-group <resource-group-name> --web-sockets-enabled true

然后重启应用程序:

az webapp stop --name <app-name> --resource-group <resource-group-name>
az webapp start --name <app-name> --resource-group <resource-group-name>

设置默认的字符编码

在 Azure 门户中 Web 应用的“应用程序设置”下,创建名为 JAVA_OPTS 且包含值 -Dfile.encoding=UTF-8 的新应用设置。

或者,可以使用应用服务 Maven 插件配置应用设置。 在插件配置中添加设置名称和值标记:

<appSettings>
    <property>
        <name>JAVA_OPTS</name>
        <value>-Dfile.encoding=UTF-8</value>
    </property>
</appSettings>

预编译 JSP 文件

要提高 Tomcat 应用程序的性能,可以先编译 JSP 文件,再部署到应用服务。 你可以使用由 Apache Sling 提供的 Maven 插件,也可以使用此 Ant 生成文件

日志中的 robots933456

你可能会在容器日志中看到以下消息:

2019-04-08T14:07:56.641002476Z "-" - - [08/Apr/2019:14:07:56 +0000] "GET /robots933456.txt HTTP/1.1" 404 415 "-" "-"

可以放心忽略此消息。 /robots933456.txt 是一个虚拟 URL 路径,应用服务使用它来检查容器能否为请求提供服务。 404 响应只是指示该路径不存在,但它让应用服务知道容器处于正常状态并已准备就绪,可以响应请求。

选择 Java 运行时版本

应用服务允许用户选择 JVM 的主版本(例如 Java 8 或 Java 11)和补丁版本(例如 1.8.0_232 或 11.0.5)。 还可以选择在新的次要版本可用时自动更新补丁版本。 在大多数情况下,生产应用应使用 JVM 的固定补丁版本。 这可防止在补丁版本自动更新期间发生意外中断。 所有 Java Web 应用都使用 64 位 JVM,这是不可配置的。

如果选择固定次要版本,则需要定期更新应用上 JVM 的次要版本。 为了确保应用程序在较新的次要版本上运行,请创建一个过渡槽并在暂存站点上递增次要版本。 确认应用程序在新的次要版本上正常运行后,可以交换过渡槽和生产槽。

Tomcat 基线配置

注意

本部分仅适用于 Linux。

如果 Java 开发人员了解 server.xml 文件和 Tomcat 的配置详细信息,他们就可以自信地自定义服务器设置、排查问题并将应用程序部署到 Tomcat。 可能的自定义包括:

  • 自定义 Tomcat 配置:通过了解 server.xml 文件和 Tomcat 的配置详细信息,可以微调服务器设置以满足其应用程序的需求。
  • 调试:在 Tomcat 服务器上部署应用程序时,开发人员需要了解服务器配置以调试可能出现的任何问题。 其中包括检查服务器日志、检查配置文件以及识别可能发生的任何错误。
  • 排查 Tomcat 问题:Java 开发人员不可避免地会遇到 Tomcat 服务器问题,例如性能问题或配置错误。 通过了解 server.xml 文件和 Tomcat 的配置详细信息,开发人员可以快速诊断和排查这些问题,从而节省时间和精力。
  • 将应用程序部署到 Tomcat:若要将 Java Web 应用程序部署到 Tomcat,开发人员需要了解如何配置 server.xml 文件和其他 Tomcat 设置。 了解这些详细信息对于成功部署应用程序并确保它们在服务器上顺利运行至关重要。

当你使用内置 Tomcat 创建应用来托管 Java 工作负载(WAR 文件或 JAR 文件)时,Tomcat 配置中有一些现成的设置。 有关详细信息,请参阅 Apache Tomcat 官方文档,其中包括 Tomcat Web 服务器的默认配置。

此外,在启动 Tomcat 发行版时,还会在 server.xml 之上进一步应用某些转换。 这些转换是连接器、主机和阀设置的转换。

Tomcat 的最新版本具有 server.xml(8.5.58 和 9.0.38 及更高版本)。 旧版本的 Tomcat 不使用转换,因此可能会有不同的行为。

连接器

<Connector port="${port.http}" address="127.0.0.1" maxHttpHeaderSize="16384" compression="on" URIEncoding="UTF-8" connectionTimeout="${site.connectionTimeout}" maxThreads="${catalina.maxThreads}" maxConnections="${catalina.maxConnections}" protocol="HTTP/1.1" redirectPort="8443"/>
  • maxHttpHeaderSize 设置为 16384
  • URIEncoding 设置为 UTF-8
  • conectionTimeout 设置为 WEBSITE_TOMCAT_CONNECTION_TIMEOUT,默认为 240000
  • maxThreads 设置为 WEBSITE_CATALINA_MAXTHREADS,默认为 200
  • maxConnections 设置为 WEBSITE_CATALINA_MAXCONNECTIONS,默认为 10000

注意

可以使用应用设置优化 connectionTimeout、maxThreads 和 maxConnections 设置

以下是一条示例 CLI 命令,可用于更改 conectionTimeout、maxThreads 或 maxConnections 的值:

az webapp config appsettings set --resource-group myResourceGroup --name myApp --settings WEBSITE_TOMCAT_CONNECTION_TIMEOUT=120000
az webapp config appsettings set --resource-group myResourceGroup --name myApp --settings WEBSITE_CATALINA_MAXTHREADS=100
az webapp config appsettings set --resource-group myResourceGroup --name myApp --settings WEBSITE_CATALINA_MAXCONNECTIONS=5000
  • 连接器使用容器的地址,而不是 127.0.0.1

主机

<Host appBase="${site.appbase}" xmlBase="${site.xmlbase}" unpackWARs="${site.unpackwars}" workDir="${site.tempdir}" errorReportValveClass="com.microsoft.azure.appservice.AppServiceErrorReportValve" name="localhost" autoDeploy="true">
  • appBase 设置为 AZURE_SITE_APP_BASE,默认为本地 WebappsLocalPath
  • xmlBase 设置为 AZURE_SITE_HOME,默认为 /site/wwwroot
  • unpackWARs 设置为 AZURE_UNPACK_WARS,默认为 true
  • workDir 设置为 JAVA_TMP_DIR,默认为 TMP
  • errorReportValveClass 使用我们的自定义错误报告阀

<Valve prefix="site_access_log.${catalina.instance.name}" pattern="%h %l %u %t &quot;%r&quot; %s %b %D %{x-arr-log-id}i" directory="${site.logdir}/http/RawLogs" maxDays="${site.logRetentionDays}" className="org.apache.catalina.valves.AccessLogValve" suffix=".txt"/>
  • directory 设置为 AZURE_LOGGING_DIR,默认为 home\logFiles
  • maxDaysWEBSITE_HTTPLOGGING_RETENTION_DAYS,默认为 0 [永久]

在 Linux 上,它具有所有相同的自定义项,以及:

  • 向阀添加一些错误和报告页:

    <xsl:attribute name="appServiceErrorPage">
        <xsl:value-of select="'${appService.valves.appServiceErrorPage}'"/>
    </xsl:attribute>
    
    <xsl:attribute name="showReport">
        <xsl:value-of select="'${catalina.valves.showReport}'"/>
    </xsl:attribute>
    
    <xsl:attribute name="showServerInfo">
        <xsl:value-of select="'${catalina.valves.showServerInfo}'"/>
    </xsl:attribute>
    

后续步骤

请访问面向 Java 开发人员的 Azure 中心查找 Azure 快速入门、教程和 Java 参考文档。