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

教程:使用托管标识从 Java Quarkus 容器应用连接到 PostgreSQL 数据库,而无需使用机密

Azure 容器应用为应用提供托管标识,这是一项统包解决方案,可以确保安全地访问 Azure Database for PostgreSQL 和其他 Azure 服务。 容器应用中的托管标识可以让应用更安全,因为不需在应用中存储机密,例如环境变量中的凭据。

本教程将指导你完成在 Azure 上生成、配置、部署和缩放 Java 容器应用的过程。 在本教程结束时,你将有一个 Quarkus 应用程序,该应用程序在 PostgreSQL 数据库中存储数据,并在容器应用上运行一个托管标识。

要学习的知识:

  • 将 Quarkus 应用配置为使用 Microsoft Entra ID 和 PostgreSQL 数据库进行身份验证。
  • 创建 Azure 容器注册表并向其推送 Java 应用映像。
  • 在 Azure 中创建容器应用。
  • 在 Azure 中创建 PostgreSQL 数据库。
  • 使用服务连接器通过托管标识连接到 PostgreSQL 数据库。

如果没有 Azure 订阅,请在开始之前创建一个 Azure 免费帐户

1.先决条件

2. 创建容器注册表

使用“az group create”命令创建资源组。 Azure 资源组是在其中部署和管理 Azure 资源的逻辑容器。

以下示例在“美国东部”Azure 区域创建一个名为 myResourceGroup 的资源组。

az group create --name myResourceGroup --location eastus

使用 az acr create 命令创建 Azure 容器注册表实例。 注册表名称在 Azure 中必须唯一,包含 5-50 个字母数字字符。 必须以小写形式指定所有字母。 在以下示例中,使用了 mycontainerregistry007。 将其更新为唯一值。

az acr create \
    --resource-group myResourceGroup \
    --name mycontainerregistry007 \
    --sku Basic

3. 克隆示例应用并准备容器映像

本教程使用示例 Fruits 列表应用,该应用的 Web UI 可以调用 Azure Database for PostgreSQL 支持的 Quarkus REST API。 GitHub 上提供了该应用的代码。 如需详细了解如何使用 Quarkus 和 PostgreSQL 编写 Java 应用,请参阅 Quarkus Hibernate ORM with Panache 指南Quarkus 数据源指南

在终端中运行以下命令,以克隆示例存储库并设置示例应用环境。

git clone https://github.com/quarkusio/quarkus-quickstarts
cd quarkus-quickstarts/hibernate-orm-panache-quickstart

修改项目

  1. 向项目 BOM 文件中添加所需的依赖项。

    <dependency>
        <groupId>com.azure</groupId>
        <artifactId>azure-identity-providers-jdbc-postgresql</artifactId>
        <version>1.0.0-beta.1</version>
    </dependency>
    
  2. 配置 Quarkus 应用属性。

    Quarkus 配置位于 src/main/resources/application.properties 文件中。 在编辑器中打开此文件,并观察几个默认属性。 只有当生成和部署应用程序时,才会使用前缀为%prod的属性,例如部署到Azure 应用服务时。 当应用程序在本地运行时, 将忽略%prod属性。 同样,%dev属性在 Quarkus 的实时编码/开发模式下使用,并在持续测试期间使用%test属性。

    删除 application.properties 中的现有内容,将其替换为以下内容,以将数据库配置为在开发、测试和生产模式下使用:

    quarkus.package.type=uber-jar
    
    quarkus.hibernate-orm.database.generation=drop-and-create
    quarkus.datasource.db-kind=postgresql
    quarkus.datasource.jdbc.max-size=8
    quarkus.datasource.jdbc.min-size=2
    quarkus.hibernate-orm.log.sql=true
    quarkus.hibernate-orm.sql-load-script=import.sql
    quarkus.datasource.jdbc.acquisition-timeout = 10
    
    %dev.quarkus.datasource.username=${AZURE_CLIENT_NAME}
    %dev.quarkus.datasource.jdbc.url=jdbc:postgresql://${DBHOST}.postgres.database.azure.com:5432/${DBNAME}?\
    authenticationPluginClassName=com.azure.identity.providers.postgresql.AzureIdentityPostgresqlAuthenticationPlugin\
    &sslmode=require\
    &azure.clientId=${AZURE_CLIENT_ID}\
    &azure.clientSecret=${AZURE_CLIENT_SECRET}\
    &azure.tenantId=${AZURE_TENANT_ID}
    
    %prod.quarkus.datasource.username=${AZURE_MI_NAME}
    %prod.quarkus.datasource.jdbc.url=jdbc:postgresql://${DBHOST}.postgres.database.azure.com:5432/${DBNAME}?\
    authenticationPluginClassName=com.azure.identity.providers.postgresql.AzureIdentityPostgresqlAuthenticationPlugin\
    &sslmode=require
    
    %dev.quarkus.class-loading.parent-first-artifacts=com.azure:azure-core::jar,\
    com.azure:azure-core-http-netty::jar,\
    io.projectreactor.netty:reactor-netty-core::jar,\
    io.projectreactor.netty:reactor-netty-http::jar,\
    io.netty:netty-resolver-dns::jar,\
    io.netty:netty-codec::jar,\
    io.netty:netty-codec-http::jar,\
    io.netty:netty-codec-http2::jar,\
    io.netty:netty-handler::jar,\
    io.netty:netty-resolver::jar,\
    io.netty:netty-common::jar,\
    io.netty:netty-transport::jar,\
    io.netty:netty-buffer::jar,\
    com.azure:azure-identity::jar,\
    com.azure:azure-identity-providers-core::jar,\
    com.azure:azure-identity-providers-jdbc-postgresql::jar,\
    com.fasterxml.jackson.core:jackson-core::jar,\
    com.fasterxml.jackson.core:jackson-annotations::jar,\
    com.fasterxml.jackson.core:jackson-databind::jar,\
    com.fasterxml.jackson.dataformat:jackson-dataformat-xml::jar,\
    com.fasterxml.jackson.datatype:jackson-datatype-jsr310::jar,\
    org.reactivestreams:reactive-streams::jar,\
    io.projectreactor:reactor-core::jar,\
    com.microsoft.azure:msal4j::jar,\
    com.microsoft.azure:msal4j-persistence-extension::jar,\
    org.codehaus.woodstox:stax2-api::jar,\
    com.fasterxml.woodstox:woodstox-core::jar,\
    com.nimbusds:oauth2-oidc-sdk::jar,\
    com.nimbusds:content-type::jar,\
    com.nimbusds:nimbus-jose-jwt::jar,\
    net.minidev:json-smart::jar,\
    net.minidev:accessors-smart::jar,\
    io.netty:netty-transport-native-unix-common::jar
    

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

  1. 生成容器映像。

    运行以下命令以生成 Quarkus 应用映像。 必须使用注册表登录服务器的完全限定的名称对它进行标记。 登录服务器名称采用 <注册表名称>.azurecr.io 格式(必须全小写),例如 mycontainerregistry007.azurecr.io。 将名称替换为自己的注册表名称。

    mvnw quarkus:add-extension -Dextensions="container-image-jib"
    mvnw clean package -Pnative -Dquarkus.native.container-build=true -Dquarkus.container-image.build=true -Dquarkus.container-image.registry=mycontainerregistry007 -Dquarkus.container-image.name=quarkus-postgres-passwordless-app -Dquarkus.container-image.tag=v1
    
  2. 登录到注册表。

    在推送容器映像之前,必须登录到注册表。 为此,请使用 [az acr login][az-acr-login] 命令。 使用 Azure CLI 登录时仅指定注册表资源名称。 请勿使用完全限定的登录服务器名称。

    az acr login --name <registry-name>
    

    该命令在完成后会返回消息 Login Succeeded

  3. 将映像推送到注册表。

    使用 [docker push][docker-push] 将映像推送到注册表实例。 使用注册表实例的登录服务器名称替换 mycontainerregistry007。 此示例创建 quarkus-postgres-passwordless-app 存储库,其中包含 quarkus-postgres-passwordless-app:v1 映像。

    docker push mycontainerregistry007/quarkus-postgres-passwordless-app:v1
    

4. 在 Azure 上创建容器应用

  1. 通过运行以下命令创建容器应用实例。 请确保将环境变量的值替换为要使用的实际名称和位置。

    RESOURCE_GROUP="myResourceGroup"
    LOCATION="eastus"
    CONTAINERAPPS_ENVIRONMENT="my-environment"
    
    az containerapp env create \
        --resource-group $RESOURCE_GROUP \
        --name $CONTAINERAPPS_ENVIRONMENT \
        --location $LOCATION
    
  2. 通过运行以下命令来使用应用映像创建容器应用。 将占位符替换成自己的值。 若要查找容器注册表管理员帐户详细信息,请参阅使用 Azure 容器注册表进行身份验证

    CONTAINER_IMAGE_NAME=quarkus-postgres-passwordless-app:v1
    REGISTRY_SERVER=mycontainerregistry007
    REGISTRY_USERNAME=<REGISTRY_USERNAME>
    REGISTRY_PASSWORD=<REGISTRY_PASSWORD>
    
    az containerapp create \
        --resource-group $RESOURCE_GROUP \
        --name my-container-app \
        --image $CONTAINER_IMAGE_NAME \
        --environment $CONTAINERAPPS_ENVIRONMENT \
        --registry-server $REGISTRY_SERVER \
        --registry-username $REGISTRY_USERNAME \
        --registry-password $REGISTRY_PASSWORD
    

5.创建 PostgreSQL 数据库并使用标识连接性来连接它

接下来,创建 PostgreSQL 数据库,并将容器应用配置为使用系统分配的托管标识连接到 PostgreSQL 数据库。 Quarkus 应用会在运行时连接到此数据库并存储自己的数据,无论你在哪里运行此应用程序,都会保存应用程序状态。

  1. 创建数据库服务。

    DB_SERVER_NAME='msdocs-quarkus-postgres-webapp-db'
    ADMIN_USERNAME='demoadmin'
    ADMIN_PASSWORD='<admin-password>'
    
    az postgres flexible-server create \
        --resource-group $RESOURCE_GROUP \
        --name $DB_SERVER_NAME \
        --location $LOCATION \
        --admin-user $DB_USERNAME \
        --admin-password $DB_PASSWORD \
        --sku-name GP_Gen5_2
    

上述 Azure CLI 命令使用以下参数:

  • resource-group → 使用在其中创建了 Web 应用的同一个资源组的名称,例如 msdocs-quarkus-postgres-webapp-rg

  • name → PostgreSQL 数据库服务器名称。 此名称必须在整个 Azure 中唯一(服务器终结点将变为 https://<name>.postgres.database.azure.com)。 允许的字符有 A-Z0-9-。 良好的模式是结合使用公司名称和服务器标识符。 (msdocs-quarkus-postgres-webapp-db)

  • location → 使用用于 Web 应用的同一个位置。

  • admin-user → 管理员帐户的用户名。 它不能是 azure_superuseradminadministratorrootguestpublic。 例如,可以是 demoadmin

  • admin-password → 管理员用户的密码。 密码必须包含以下三个类别的 8 到 128 个字符:英文大写字母、英文小写字母、数字和非字母数字字符。

    重要

    创建用户名或密码时不要使用 $ 字符。 在本教程后面,我们将使用这些值创建环境变量,其中的字符 $ 在用于运行 Java 应用的 Linux 容器中具有特殊含义。

  • public-access → None,即,将服务器设置为不使用防火墙规则的公共访问模式。 将在后面的步骤中创建规则。

  • sku-name → 定价层和计算配置的名称,例如 GP_Gen5_2。 有关详细信息,请参阅 Azure Database for PostgreSQL 定价

  1. 使用以下命令在 PostgreSQL 服务中创建名为 fruits 的数据库:

    az postgres flexible-server db create \
        --resource-group $RESOURCE_GROUP \
        --server-name $DB_SERVER_NAME \
        --database-name fruits
    
  2. 为 Azure CLI 安装服务连接器无密码扩展:

    az extension add --name serviceconnector-passwordless --upgrade
    
  3. 通过连接命令使用系统分配的托管标识将数据库连接到容器应用。

    az containerapp connection create postgres-flexible \
        --resource-group $RESOURCE_GROUP \
        --name my-container-app \
        --target-resource-group $RESOURCE_GROUP \
        --server $DB_SERVER_NAME \
        --database fruits \
        --managed-identity
    

6. 查看所作更改

可以使用以下命令找到应用程序 URL (FQDN):

az containerapp list --resource-group $RESOURCE_GROUP

当新网页显示水果列表时,表明应用使用了托管标识连接到数据库。 现在应该可以像以前一样编辑水果列表了。

清理资源

在前面的步骤中,你在资源组中创建了 Azure 资源。 如果认为将来不需要这些资源,请在 Cloud Shell 中运行以下命令删除资源组:

az group delete --name myResourceGroup

此命令可能需要花费一点时间运行。

后续步骤

在开发人员指南中详细了解如何在 Azure 上运行 Java 应用。