教程:使用托管标识从 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 的资源组。

RESOURCE_GROUP="myResourceGroup"
LOCATION="eastus"

az group create --name $RESOURCE_GROUP --___location $LOCATION

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

REGISTRY_NAME=mycontainerregistry007
az acr create \
    --resource-group $RESOURCE_GROUP \
    --name $REGISTRY_NAME \
    --sku Basic

REGISTRY_SERVER=$(az acr show \
    --name $REGISTRY_NAME \
    --query 'loginServer' \
    --output tsv | tr -d '\r')

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

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

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

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

修改项目

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

    <dependency>
       <groupId>com.azure</groupId>
       <artifactId>azure-identity-extensions</artifactId>
       <version>1.2.0</version>
    </dependency>
    
  2. 配置 Quarkus 应用属性。

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

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

    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=${CURRENT_USERNAME}
    %dev.quarkus.datasource.jdbc.url=jdbc:postgresql://${AZURE_POSTGRESQL_HOST}:${AZURE_POSTGRESQL_PORT}/${AZURE_POSTGRESQL_DATABASE}?\
    authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin\
    &sslmode=require
    
    %prod.quarkus.datasource.username=${AZURE_POSTGRESQL_USERNAME}
    %prod.quarkus.datasource.jdbc.url=jdbc:postgresql://${AZURE_POSTGRESQL_HOST}:${AZURE_POSTGRESQL_PORT}/${AZURE_POSTGRESQL_DATABASE}?\
    authenticationPluginClassName=com.azure.identity.extensions.jdbc.postgresql.AzurePostgresqlAuthenticationPlugin\
    &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-extensions::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,\
    net.java.dev.jna:jna::jar
    

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

  1. 生成容器映像。

    运行以下命令以生成 Quarkus 应用映像。 必须使用注册表登录服务器的完全限定的名称对它进行标记。

    CONTAINER_IMAGE=${REGISTRY_SERVER}/quarkus-postgres-passwordless-app:v1
    
    mvn quarkus:add-extension -Dextensions="container-image-jib"
    mvn clean package -Dquarkus.container-image.build=true -Dquarkus.container-image.image=${CONTAINER_IMAGE}
    
  2. 登录到注册表。

    在推送容器映像之前,必须登录到注册表。 为此,请使用 [az acr login][az-acr-login] 命令。

    az acr login --name $REGISTRY_NAME
    

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

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

    使用 docker push 将映像推送到注册表实例。 此示例创建 quarkus-postgres-passwordless-app 存储库,其中包含 quarkus-postgres-passwordless-app:v1 映像。

    docker push $CONTAINER_IMAGE
    

4. 在 Azure 上创建容器应用

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

    CONTAINERAPPS_ENVIRONMENT="my-environment"
    
    az containerapp env create \
        --resource-group $RESOURCE_GROUP \
        --name $CONTAINERAPPS_ENVIRONMENT \
        --___location $LOCATION
    
  2. 通过运行以下命令来创建一个包含你的应用映像的容器应用:

    APP_NAME=my-container-app
    az containerapp create \
        --resource-group $RESOURCE_GROUP \
        --name $APP_NAME \
        --image $CONTAINER_IMAGE \
        --environment $CONTAINERAPPS_ENVIRONMENT \
        --registry-server $REGISTRY_SERVER \
        --registry-identity system \
        --ingress 'external' \
        --target-port 8080 \
        --min-replicas 1
    

    注意

    仍支持 --registry-username--registry-password 选项,但不建议使用,因为使用标识系统更安全。

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

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

  1. 创建数据库服务。

    DB_SERVER_NAME='msdocs-quarkus-postgres-webapp-db'
    
    az postgres flexible-server create \
        --resource-group $RESOURCE_GROUP \
        --name $DB_SERVER_NAME \
        --___location $LOCATION \
        --public-access None \
        --sku-name Standard_B1ms \
        --tier Burstable \
        --active-directory-auth Enabled
    

    注意

    仍支持 --admin-user--admin-password 选项,但不建议使用,因为使用标识系统更安全。

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

    • resource-group → 使用在其中创建 Web 应用的相同资源组名称,例如 msdocs-quarkus-postgres-webapp-rg
    • name → PostgreSQL 数据库服务器名称。 此名称必须在整个 Azure 中唯一(服务器终结点将变为 )。 允许的字符有 A-Z0-9-。 良好的模式是结合使用公司名称和服务器标识符。 (msdocs-quarkus-postgres-webapp-db)
    • ___location → 使用用于 Web 应用的同一个位置。 如果它不起作用,请更换到其他位置。
    • public-access → ,即,将服务器设置为不使用防火墙规则的公共访问模式。 将在后面的步骤中创建规则。
    • sku-name → 定价层和计算配置的名称,例如 Standard_B1ms。 有关详细信息,请参阅 Azure Database for PostgreSQL 定价
    • 层级 →服务器的计算层。 有关详细信息,请参阅 Azure Database for PostgreSQL 定价
    • active-directory-auth → 设置为 Enabled 以启用 Microsoft Entra 身份验证。
  2. 使用以下命令在 PostgreSQL 服务中创建名为 fruits 的数据库:

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

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

    az containerapp connection create postgres-flexible \
        --resource-group $RESOURCE_GROUP \
        --name $APP_NAME \
        --target-resource-group $RESOURCE_GROUP \
        --server $DB_SERVER_NAME \
        --database $DB_NAME \
        --system-identity \
        --container $APP_NAME
    

6. 查看所作更改

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

echo https://$(az containerapp show \
    --name $APP_NAME \
    --resource-group $RESOURCE_GROUP \
    --query properties.configuration.ingress.fqdn \
    --output tsv)

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

清理资源

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

az group delete --name myResourceGroup

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

后续步骤

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