本教程介绍如何在连接到 MySQL 数据库的 Azure 应用服务中生成、配置和部署安全 Tomcat 应用程序(使用 Azure Database for MySQL)。 Azure 应用服务是一种可缩放程度高、支持自修补的 Web 托管服务,可轻松地在 Windows 或 Linux 上部署应用。 完成本教程后,Linux 上的 Azure 应用服务中将会运行一个 Tomcat 应用。
本教程中,您将学习如何:
- 为 Azure 应用服务和 Azure Database for MySQL 创建默认安全的体系结构。
- 使用托管标识和 密钥保管库 引用来保护连接机密。
- 从 GitHub 存储库将 Tomcat 示例应用部署到应用服务。
- 在应用程序代码中访问应用服务应用设置。
- 进行更新并重新部署应用程序代码。
- 从应用服务流式传输诊断日志。
- 在 Azure 门户中管理应用。
- 使用 Azure Developer CLI 预配同一体系结构并进行部署。
- 使用 GitHub Codespaces 和 GitHub Copilot 优化开发工作流。
先决条件
- 拥有有效订阅的 Azure 帐户。 如果没有 Azure 帐户,可以免费创建一个。
- 一个 GitHub 帐户。 你也可以免费获得一个。
- 具备 Tomcat 开发的 Java 知识。
- (可选) 要尝试 GitHub Copilot,需要一个 GitHub Copilot 帐户。 提供 30 天试用期。
- 拥有有效订阅的 Azure 帐户。 如果没有 Azure 帐户, 可以创建一个。
- 已安装 Azure Developer CLI。
- 具备 Tomcat 开发的 Java 知识。
- (可选) 要尝试 GitHub Copilot,需要一个 GitHub Copilot 帐户。 提供 30 天试用期。
跳到末尾
可以快速部署本教程中的示例应用,并查看它是否在 Azure 中运行。 只需在 Azure Ci 中运行以下命令,然后按照提示操作:
mkdir msdocs-tomcat-mysql-sample-app
cd msdocs-tomcat-mysql-sample-app
azd init --template msdocs-tomcat-mysql-sample-app
azd up
1.运行示例
首先,将示例数据驱动的应用设置为起点。 为方便起见,示例存储库包含一个开发容器配置。 开发容器包含开发应用程序所需的所有内容,包括示例应用程序所需的数据库、缓存和所有环境变量。 开发容器可以在 GitHub codespace 中运行,这意味着可使用 Web 浏览器在任何计算机上运行示例。
步骤 1:在新浏览器窗口中:
- 登录到 GitHub 帐户。
- 转到 https://github.com/Azure-Samples/msdocs-tomcat-mysql-sample-app/fork。
- 取消选择“仅复制主分支”。 你想要所有的分支。
- 选择“创建分支”。
步骤 2:在 GitHub 分支中:
- 选择main>starter-no-infra作为起始分支。 此分支仅包含示例项目,不包含与 Azure 相关的文件或配置。
- 选择代码>在 starter-no-infra 上创建代码空间。 设置代码空间需要几分钟时间。
步骤 3:在 codespace 终端中:
- 运行
mvn jetty:run。 - 看到通知
Your application running on port 80 is available.时,选择“在浏览器中打开”。 应在新的浏览器选项卡中看到该示例应用程序。若要停止 Jetty 服务器,请键入Ctrl+C。
遇到问题? 检查 “故障排除”部分。
2.创建应用服务和 MySQL
首先,创建 Azure 资源。 本教程中使用的步骤创建一组默认安全的资源,其中包括应用服务和 Azure Database for MySQL。 对于创建过程,需要指定:
- Web 应用程序的名称。 它用作 DNS 名称的一部分。
- 用于在世界上实际运行应用的区域。 它还用作应用的 DNS 名称的一部分。
- 应用的运行时堆栈。 在此处选择要用于应用的 PHP 版本。
- 应用程序的托管计划。 定价层为您的应用提供了一组功能和可扩展的容量。
- 应用的资源组。 使用资源组可将应用程序所需的所有 Azure 资源分组到一个逻辑容器中。
登录到 Azure 门户并按照以下步骤创建 Azure 应用服务资源。
在 Azure 门户中:
- 在顶部的搜索栏中,输入 应用服务。
- 在 “服务 ”标题下,选择 “应用服务”。
- 选择“创建”“Web 应用”>。
还可以直接转到 创建向导。
在“创建 Web 应用”页面的“基本信息”选项卡上,按如下所示填写表单:
- 资源组:选择“新建”,并使用名称 msdocs-tomcat-mysql-tutorial。
- 名称:msdocs-tomcat-mysql-XYZ,其中 XYZ 是任意三个随机字符。
- 运行时堆栈:Java 25。
- Java Web 服务器堆栈:Apache Tomcat 11.0。
- 作系统: Linux。
- 区域:你附近的任何 Azure 区域。
- 定价计划: 基本。 准备就绪后,可以纵向扩展到生产定价层。
选择“ 数据库 ”选项卡并配置数据库:
- 选择“ 创建数据库”。
- 在 “引擎”中,选择 “MySQL 灵活服务器”。 Azure Database for MySQL - 灵活服务器是 Azure 上完全托管的 MySQL 数据库即服务,与最新社区版兼容。
- 不要选择“创建Azure Cache for Redis”。
选择“查看 + 创建”。 验证完成后,选择“创建”。
部署完成后,选择“ 转到资源 ”按钮。 你将直接进入 App Service 应用。
将创建以下资源:
- 资源组:所有已创建资源的容器。
- 应用服务计划:为应用服务定义计算资源。 创建了一个属于Basic层的 Linux 计划。
- 应用服务:表示应用并在应用服务计划中运行。
- 虚拟网络:与应用服务应用集成,并隔离后端网络流量。
- Azure Database for MySQL 灵活服务器:只能从虚拟网络访问。 你的数据库和用户创建于此服务器上。
- 专用 DNS 区域:在虚拟网络中启用数据库服务器的 DNS 解析。
遇到问题? 检查 “故障排除”部分。
4.确认 JNDI 数据源
如果应用设置包含适用于 Oracle、SQL Server、PostgreSQL 或 MySQL 的有效 JDBC 连接字符串,并且应用设置 WEBSITE_AUTOCONFIGURE_DATABASE 设为 true,App Service 会在 Tomcat 服务器的 context.xml 文件中为其添加一个 Java 命名和目录接口 (JNDI) 数据源。 在此步骤中,将添加此应用设置,然后使用 SSH 连接到应用容器来验证 JNDI 数据源。 在此过程中,你将了解如何访问 Tomcat 容器的 SSH shell。
步骤 1: 你仍在上一部分的 “环境变量 ”页上。 添加应用设置以启用数据源自动配置:
- 选择 并添加。
- 将 Name 设置为
WEBSITE_AUTOCONFIGURE_DATABASE并将 值 设置为true. - 选择 “应用”,然后再次 应用 以保存并重启应用。
步骤 2: 返回应用服务页:
- 从左侧菜单中选择“SSH”。
- 选择 “Go”。
步骤 3: 在 SSH 终端中,运行 cat /usr/local/tomcat/conf/context.xml。 你应会看到已添加名为 jdbc/AZURE_MYSQL_CONNECTIONSTRING_DS 的 JNDI 资源。 稍后你将使用该数据源。
Note
只有对 /home 中文件的更改才能在应用重启之后持久保存。 例如,如果编辑/usr/local/tomcat/conf/server.xml,则在应用重启之后不会保存更改。
遇到问题? 检查 “故障排除”部分。
6.打开应用程序
步骤 1:在“应用服务”页中:
- 从左侧菜单中选择“概述”。
- 选择应用的 URL。
步骤 2:将一些任务添加到列表。 恭喜,你已在 Azure 应用服务中运行了一个 Web 应用,并安全连接到了 Azure Database for MySQL。
遇到问题? 检查 “故障排除”部分。
7. 实时传输诊断日志
Azure 应用服务会捕获输出到控制台的所有消息,以帮助你诊断应用程序的问题。 示例应用程序包括标准 Log4j 日志记录语句,用于演示此功能,如以下代码片段所示:
@WebServlet(urlPatterns = "/")
public class ViewServlet extends HttpServlet {
private static Logger logger = LogManager.getLogger(ViewServlet.class.getName());
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
logger.info("GET /");
EntityManagerFactory emf = (EntityManagerFactory) req.getServletContext().getAttribute("EMFactory");
步骤 1:在“应用服务”页中:
- 从左菜单中选择“应用服务日志”。
- 在“应用程序日志记录”下,选择“文件系统”。
- 在顶部菜单中,选择“保存”。
步骤 2:在左侧菜单中,选择“日志流”。 将显示应用的日志,包括平台日志和容器内部的日志。
在为 .NET、Node.js、Python 和 Java 应用程序启用 Azure Monitor OpenTelemetry 系列教程中详细了解 Java 应用中的日志记录。
遇到问题? 检查 “故障排除”部分。
8.清理资源
完成后,可以通过删除资源组,从Azure订阅中删除所有资源。
步骤 1:在 Azure 门户顶部的搜索栏中:
- 输入资源组名称。
- 选择资源组。
步骤 2:在资源组页上,选择“删除资源组”。
步骤 3:
- 键入资源组名称以确认删除。
- 选择 删除。
- 再次使用“删除”进行确认。
2.创建 Azure 资源并部署示例应用
在此步骤中,将创建Azure资源,并将示例应用部署到Linux 上的应用服务。 本教程中使用的步骤创建一组默认安全的资源,其中包括应用服务和 Azure Database for MySQL。
开发容器已具有 Azure Developer CLI (AZD)。
从存储库根路径,运行
azd init。azd init --template tomcat-app-service-mysql-infra .出现提示时,请提供以下答案:
Question 回答 当前目录不为空。 是否要在此处初始化“<your-directory>”中的项目? Y 你希望对这些文件执行哪些操作? 使现有文件保持不变 输入新环境名称 键入唯一名称。 AZD 模板将此名称用作 Azure( <app-name>-<hash>.chinacloudsites.cn)中 Web 应用的 DNS 名称的一部分。 允许使用字母数字字符和下划线。通过运行
azd auth login命令并按照提示登录到 Azure:azd auth login使用
azd up命令创建必要的 Azure 资源并部署应用代码。 按照提示为 Azure 资源选择所需的订阅和位置。azd up该
azd up命令需要大约 10 分钟才能完成。 它还会编译和部署应用程序代码,但你稍后将修改代码以使用应用服务。 在运行时,该命令会提供有关预配和部署过程的消息,包括指向 Azure 中部署的链接。 完成后,命令还会显示指向部署应用程序的链接。此 AZD 模板包含使用以下 Azure 资源生成安全默认体系结构的文件(azure.yaml 和 infra 目录):
- 资源组:所有已创建资源的容器。
- 应用服务计划:为应用服务定义计算资源。 在 B1 层中创建了一个 Linux 计划。
- 应用服务:表示应用并在应用服务计划中运行。
- 虚拟网络:与应用服务应用集成,并隔离后端网络流量。
- Azure Database for MySQL 灵活服务器:只能通过 DNS 区域集成从虚拟网络访问。 将在服务器上为你创建数据库。
- Azure托管 Redis:只能通过虚拟网络内部访问。
- 专用终结点:访问虚拟网络中密钥保管库和托管 Redis 实例的终结点。
- 专用 DNS 区域:在虚拟网络中启用对密钥保管库、数据库服务器和托管 Redis 实例的 DNS 解析。
- Log Analytics 工作区:充当应用交付日志的目标容器,还可以在其中查询日志。
- 密钥保管库:使用 AZD 重新部署时,用于保留数据库密码。
一旦命令完成创建资源和首次部署应用程序代码的操作,已部署的示例应用就无法运行,因为你必须进行微小的更改才能使其连接到 Azure 中的数据库。
遇到问题? 检查 “故障排除”部分。
3.验证连接字符串
你使用的 AZD 模板已为你生成了连接变量作为应用设置,并将它们输出到终端,以方便你使用。 使用应用设置可以将连接机密保留在代码存储库之外。
在 AZD 输出中,找到应用设置
AZURE_MYSQL_CONNECTIONSTRING。 仅显示设置名称。 在 AZD 输出中,它们看起来是这样的:App Service app has the following connection strings: - AZURE_MYSQL_CONNECTIONSTRING - AZURE_REDIS_CONNECTIONSTRING - AZURE_KEYVAULT_RESOURCEENDPOINT - AZURE_KEYVAULT_SCOPEAZURE_MYSQL_CONNECTIONSTRING包含 Azure 中 MySQL 数据库的连接字符串。 稍后需要在代码中使用它。为方便起见,AZD 模板会显示应用的应用设置页的直接链接。 找到该链接并在新的浏览器选项卡中打开它。
如果添加包含有效 Oracle、SQL Server、PostgreSQL 或 MySQL 连接字符串的应用设置,则应用服务会在 Tomcat 服务器的 context.xml 文件中将其添加为 Java 命名和目录接口 (JNDI) 数据源。
遇到问题? 检查 “故障排除”部分。
4.确认 JNDI 数据源
在此步骤中,使用与应用容器的 SSH 连接来验证 Tomcat 服务器中的 JNDI 数据源。 在此过程中,你将了解如何访问 Tomcat 容器的 SSH shell。
在 AZD 输出中,找到 SSH 会话的 URL,并在浏览器中导航到该 URL。 输出结果如下:
Open SSH session to App Service container at: <URL>
在 SSH 终端中运行
cat /usr/local/tomcat/conf/context.xml。 你应会看到已添加名为jdbc/AZURE_MYSQL_CONNECTIONSTRING_DS的 JNDI 资源。 稍后你将使用该数据源。 应用服务会自动创建此数据源,因为 AZD 模板将应用设置WEBSITE_AUTOCONFIGURE_DATABASE设置为true。
Note
只有对 /home 中文件的更改才能在应用重启之后持久保存。 例如,如果编辑/usr/local/tomcat/conf/server.xml,则在应用重启之后不会保存更改。
遇到问题? 检查 “故障排除”部分。
5.修改示例代码并重新部署
在 GitHub codespace 中,单击“聊天”视图,然后单击 ,即可开始新的聊天会话+。
问:“@workspace 应用如何连接到数据库?”Copilot 可能会提供有关
jdbc/MYSQLDS数据源以及如何配置它的一些说明。问:“@workspace 我想用 Tomcat 中现有的 JNDI 数据源替换 persistence.xml 中定义的数据源,但我想动态地执行此操作。”Copilot 可能会给你一个类似于下方的“选项 2:没有 GitHub Copilot”步骤中的建议的代码建议,甚至会告诉你在 ContextListener 类中进行更改。
在资源管理器中打开 src/main/java/com/microsoft/azure/appservice/examples/tomcatmysql/ContextListener.java,并在
contextInitialized方法中添加代码建议。GitHub Copilot 不会每次都给你相同的回复,你可能需要提出其他问题来优调其回复。 有关提示,请参阅 如何在代码空间中使用GitHub Copilot?。
在 codespace 终端,运行
azd deploy。azd deploy
Tip
也可以始终只使用 azd up,它会同时执行 azd package、azd provision 和 azd deploy。
要了解如何打包 WAR 文件,可以单独运行 azd package --debug。
遇到问题? 检查 “故障排除”部分。
6.打开应用程序
在 AZD 输出中,找到应用的 URL 并在浏览器中导航到该 URL。 该 URL 在 AZD 输出中如下所示:
Deploying services (azd deploy) (✓) Done: Deploying service web - Endpoint: <URL>
将一些任务添加到列表。
恭喜,你已在 Azure 应用服务中运行了一个 Web 应用,并安全连接到了 Azure Database for MySQL。
遇到问题? 检查 “故障排除”部分。
7. 实时传输诊断日志
Azure 应用服务可以捕获控制台日志,以帮助你诊断应用程序的问题。 为方便起见,AZD 模板已启用对本地文件系统的日志记录以及将日志传送到 Log Analytics 工作区。
示例应用程序包括标准 Log4j 日志记录语句,用于演示此功能,如以下代码片段所示:
@WebServlet(urlPatterns = "/")
public class ViewServlet extends HttpServlet {
private static Logger logger = LogManager.getLogger(ViewServlet.class.getName());
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
logger.info("GET /");
EntityManagerFactory emf = (EntityManagerFactory) req.getServletContext().getAttribute("EMFactory");
在 AZD 输出中,找到流式传输应用服务日志的链接,并在浏览器中导航到该链接。 该链接在 AZD 输出中如下所示:
Stream App Service logs at: <URL>
在为 .NET、Node.js、Python 和 Java 应用程序启用 Azure Monitor OpenTelemetry 系列教程中详细了解 Java 应用中的日志记录。
遇到问题? 检查 “故障排除”部分。
8.清理资源
若要删除当前部署环境中的所有 Azure 资源,请运行 azd down 并按照提示进行操作。
azd down
Troubleshooting
- 我看到从多个位置扫描的许多<类>警告与 mvn jetty:run
- Azure Database for MySQL 灵活服务器的门户部署视图显示冲突状态
- 已部署的示例应用未显示任务列表应用
- 我在部署的示例应用中看到“404 找不到页面”错误
我看到从多个位置扫描的许多<类>警告与 mvn jetty:run
你可以忽略这些警告。 Maven Jetty 插件显示警告,因为应用的 pom.xml 文件中包含了 Jetty 已经自带的 jakarta.servlet.jsp.jstl 依赖项。 需要 Tomcat 的依赖项。
Azure Database for MySQL 灵活服务器的门户部署视图显示冲突状态
根据订阅和所选区域,你可能会看到 Azure Database for MySQL 灵活服务器的部署状态为 Conflict,并且操作详细信息中显示以下消息:
InternalServerError: An unexpected error occurred while processing the request.
此错误很可能是由所选区域的订阅限制引起的。 请尝试为部署选择其他区域。
已部署的示例应用未显示任务列表应用
如果你看到 Hey, Java developers! 页,而不是任务列表应用程序,则很可能应用服务仍在从你最近的代码部署中加载更新的容器。 等待几分钟,然后刷新页面。
我在部署的示例应用中看到“404 找不到页面”错误
请确保已对代码进行更改,以使用 java:comp/env/jdbc/AZURE_MYSQL_CONNECTIONSTRING_DS 数据源。 如果已进行更改并重新部署了代码,应用服务很可能仍会加载更新的容器。 等待几分钟,然后刷新页面。
常见问题解答
- 此设置的成本是多少?
- 如何使用其他工具连接到虚拟网络后面的 MySQL 服务器?
- 如何使用 GitHub Actions 进行本地应用程序开发?
- 我无权创建用户分配的标识
- 我可以在我的代码空间中使用 GitHub Copilot 做些什么?
这套设备的成本是多少?
所创建资源的定价如下所示:
- 应用服务计划在基础层中创建,可以进行向上或向下扩展。 请参阅应用服务定价。
- MySQL 灵活服务器在 B1ms 层中创建,可以扩展或缩减规模。 使用 Azure 试用版时,B1ms 层免费 12 个月,最高可达每月限额。 参阅 Azure Database for MySQL 价格信息。
- Azure托管 Redis 实例是在具有最小缓存大小的均衡 B0 层中创建的。 此级别的成本较低。 你可将其纵向扩展到更高的性能层,以实现更高的可用性、聚类分析和其他功能。 请参阅Azure 托管 Redis 定价。
- 除非配置额外的功能(例如对等连接),否则虚拟网络不会产生费用。 请参阅 Azure 虚拟网络定价。
- 专用 DNS 区域会产生少量费用。 请参阅 Azure DNS 定价。
如何使用其他工具连接到虚拟网络后面的 MySQL 服务器?
- Tomcat 容器当前也没有
mysql-client终端。 如果需要,则必须手动安装它。 请记住,你安装的任何内容都不会在应用重启时保留。 - 若要从 MySQL Workbench 等桌面工具进行连接,计算机必须位于虚拟网络中。 例如,它可以是其中某个子网中的 Azure VM,也可以是与 Azure 虚拟网络建立站点到站点 VPN 连接的本地网络中的计算机。
本地应用开发如何与 GitHub Actions 协作?
以应用服务中自动生成的工作流文件为例,每个 git push 都会启动新的构建和部署过程。 从 GitHub 存储库的本地克隆中,进行所需更新并推送到 GitHub。 例如:
git add .
git commit -m "<some-message>"
git push origin main
我无权创建用户分配的标识
我可以在我的代码空间中使用 GitHub Copilot 做些什么?
你可能注意到,创建 codespace 时,GitHub Copilot 聊天视图已经存在。 为了你的方便,我们在容器定义中包含了 GitHub Copilot 聊天扩展(参见 .devcontainer/devcontainer.json)。 但是,需要 GitHub Copilot 帐户(提供 30 天试用期)。
下面是与 GitHub Copilot 交谈时的一些提示:
- 在单次聊天会话中,问题和答案相互关联,你可以调整问题来微调所获得的答案。
- 默认情况下,GitHub Copilot 无法访问你存储库中的任何文件。 若要询问有关文件的问题,请首先在编辑器中打开该文件。
- 若要让GitHub Copilot在准备答案时访问存储库中的所有文件,请使用
@workspace开始你的问题。 有关详细信息,请参阅 Use the @workspace agent。 - 在聊天会话中,GitHub Copilot 可以建议更改,甚至可以(在使用
@workspace时)建议在何处进行更改,但系统不允许它为你进行更改。 你可以自行添加建议的更改并对其进行测试。
你还可以说下面的一些话来微调得到的答案:
- 更改此代码以使用数据源 jdbc/AZURE_MYSQL_CONNECTIONSTRING_DS。
- 你的代码中的某些导入使用了 javax,但我使用的是 Jakarta 应用。
- 我希望只有在设置了环境变量 AZURE_MYSQL_CONNECTIONSTRING 的情况下才运行此代码。
- 我希望此代码仅在 Azure 应用服务中运行,而不在本地运行。
后续步骤
在开发人员指南中详细了解在应用服务上运行 Java 应用。
了解如何使用自定义域和证书保护应用。