本教程系列的这一部分介绍如何将容器化 Python Web 应用程序部署到 用于容器的 Azure 应用服务 Web 应用。 此完全托管服务使你无需维护自己的容器业务流程协调程序即可运行容器化应用。
Azure 应用服务通过持续集成/持续部署(CI/CD)管道简化了部署,该管道可与 Docker Hub、Azure 容器注册表、Azure Key Vault 以及其他 DevOps 工具配合使用。 本教程是 5 部分教程系列的第 4 部分。
本文末尾有一个安全且生产就绪的应用服务 Web 应用,该应用从 Docker 容器映像运行。 应用使用 系统分配的托管标识 从 Azure 容器注册表拉取映像,并从 Azure Key Vault 检索机密。
此服务关系图突出显示了本文中介绍的组件。
可以在 Azure Cloud Shell 或 安装了 Azure CLI 的本地计算机上运行 Azure CLI 命令。
重要
建议对本教程中所有基于 CLI 的步骤使用 Azure Cloud Shell ,因为它:
- 使用 Azure 帐户预先进行身份验证,避免登录问题
- 包括所有必需的 Azure CLI 扩展,即开箱即用。
- 无论本地 OS 或环境如何,确保一致的行为
- 无需本地安装,非常适合没有管理员权限的用户
- 提供从门户直接访问 Azure 服务 - 无需本地 Docker 或网络设置
- 避免本地防火墙或网络配置问题
使用 RBAC 授权创建 Key Vault
Azure Key Vault 是用于存储机密、API 密钥、连接字符串和证书的安全服务。 在此脚本中,它将存储 MongoDB 连接字符串 和 Web 应用的 SECRET_KEY
连接字符串。
Key Vault 配置为使用 基于角色的访问控制(RBAC) 通过 Azure 角色而不是传统访问策略来管理访问权限。 Web 应用使用系统 分配的托管标识 在运行时安全地检索机密。
注意
提前创建 Key Vault 可确保在尝试访问机密之前分配角色。 它还有助于避免角色分配中的传播延迟。 由于 Key Vault 不依赖于应用服务,因此提前预配它可提高可靠性和排序性。
在此步骤中,使用 az keyvault create 命令创建已启用 RBAC 的 Azure Key Vault。
#!/bin/bash RESOURCE_GROUP_NAME="msdocs-web-app-rg" LOCATION="westus" KEYVAULT_NAME="${RESOURCE_GROUP_NAME}-kv" az keyvault create \ --name "$KEYVAULT_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --___location "$LOCATION" \ --enable-rbac-authorization true
创建应用服务计划和 Web 应用
应用服务计划定义 Web 应用的计算资源、定价层和区域。 Web 应用运行容器化应用程序,并使用系统分配的托管标识进行预配,该标识用于安全地向 Azure 容器注册表(ACR)和 Azure Key Vault 进行身份验证。
在此步骤中,将执行以下任务:
- 创建应用服务计划
- 使用其托管标识创建 Web 应用
- 将 Web 应用配置为使用特定容器映像进行部署
- 通过 ACR 准备持续部署
注意
必须在分配对 ACR 或 Key Vault 的访问权限之前创建 Web 应用,因为 托管标识仅在部署时创建。 此外,在创建过程中分配容器映像可确保应用使用预期配置正确启动。
在此步骤中,使用 az appservice plan create 命令为应用预配计算环境。
#!/bin/bash APP_SERVICE_PLAN_NAME="msdocs-web-app-plan" az appservice plan create \ --name "$APP_SERVICE_PLAN_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --sku B1 \ --is-linux
在此步骤中,使用 az webapp create 命令创建 Web 应用。 此命令还启用 系统分配的托管标识 ,并设置应用运行的容器映像。
#!/bin/bash APP_SERVICE_NAME="msdocs-website-name" #APP_SERVICE_NAME must be globally unique as it becomes the website name in the URL `https://<website-name>.azurewebsites.net`. # Use the same registry name as in part 2 of this tutorial series. REGISTRY_NAME="msdocscontainerregistryname" #REGISTRY_NAME is the registry name you used in part 2 of this tutorial. CONTAINER_NAME="$REGISTRY_NAME.azurecr.io/msdocspythoncontainerwebapp:latest" #CONTAINER_NAME is of the form "yourregistryname.azurecr.io/repo_name:tag". az webapp create \ --resource-group "$RESOURCE_GROUP_NAME" \ --plan "$APP_SERVICE_PLAN_NAME" \ --name "$APP_SERVICE_NAME" \ --assign-identity '[system]' \ --deployment-container-image-name "$CONTAINER_NAME"
注意
运行此命令时,可能会看到以下错误:
No credential was provided to access Azure Container Registry. Trying to look up... Retrieving credentials failed with an exception:'Failed to retrieve container registry credentials. Please either provide the credentials or run 'az acr update -n msdocscontainerregistryname --admin-enabled true' to enable admin first.'
发生此错误的原因是 Web 应用尝试使用管理员凭据访问 ACR,默认情况下禁用了哪些凭据。 忽略此消息是安全的:下一步将 Web 应用配置为使用其托管标识向 ACR 进行身份验证。
向已登录用户授予机密官员角色
若要将机密存储在 Azure Key Vault 中,运行脚本的用户必须具有 Key Vault 机密官员 角色。 此角色允许在保管库中创建和管理机密。
在此步骤中,脚本将该角色分配给当前登录的用户。 然后,此用户可以安全地存储应用程序机密,例如 MongoDB 连接字符串和应用的 SECRET_KEY
机密。
此角色分配是两个 Key Vault 相关角色分配中的第一个。 稍后,向 Web 应用的系统分配托管标识授予从保管库中检索机密的权限。
使用 Azure RBAC 可确保基于标识的安全、可审核的访问,而无需硬编码凭据。
注意
在尝试将任何机密存储在密钥保管库之前,必须先为用户分配 Key Vault 机密官员角色。 此分配是使用作用域为 Key Vault 的 az role assignment create 命令完成的。
在此步骤中,使用 az role assignment create 命令在 Key Vault 范围内分配角色。
#!/bin/bash CALLER_ID=$(az ad signed-in-user show --query id -o tsv) echo $CALLER_ID # Verify this value retrieved successfully. In production, poll to verify this value is retrieved successfully. az role assignment create \ --role "Key Vault Secrets Officer" \ --assignee "$CALLER_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
使用托管标识授予对 ACR 的 Web 访问权限
若要安全地从 Azure 容器注册表(ACR)拉取映像,必须将 Web 应用配置为使用其 系统分配的托管标识。 使用托管标识可避免管理员凭据需求,并支持安全的无凭据部署。
此过程涉及两个关键步骤:
- 允许 Web 应用在访问 ACR 时使用其托管标识
- 将 AcrPull 角色分配给目标 ACR 上的该标识
在此步骤中,你将使用 az webapp identity show 命令检索 Web 应用的托管标识的主体 ID(唯一对象 ID)。 接下来,通过使用 az webapp config set 命令,将属性
acrUseManagedIdentityCreds
设置为true
,以启用 ACR 身份验证的托管标识。 然后,使用 az role assignment create 命令将 AcrPull 角色分配给 Web 应用的托管标识。 此角色授予 Web 应用从注册表中拉取镜像的权限。#!/bin/bash PRINCIPAL_ID=$(az webapp identity show \ --name "$APP_SERVICE_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query principalId \ -o tsv) echo $PRINCIPAL_ID # Verify this value retrieved successfully. In production, poll for successful 'AcrPull' role assignment using `az role assignment list`. az webapp config set \ --resource-group "$RESOURCE_GROUP_NAME" \ --name "$APP_SERVICE_NAME" \ --generic-configurations '{"acrUseManagedIdentityCreds": true}' az role assignment create \ --role "AcrPull" \ --assignee "$PRINCIPAL_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.ContainerRegistry/registries/$REGISTRY_NAME"
授予密钥保管库对 Web 应用的托管标识的访问权限
Web 应用需要权限才能访问 MongoDB 连接字符串和 SECRET_KEY
机密。 若要授予这些权限,必须将 Key Vault 机密用户 角色分配给 Web 应用的 系统分配托管标识。
在此步骤中,您将使用 Web 应用系统分配的托管标识的唯一标识符(主体 ID),通过 az role assignment create 命令,将 Key Vault 机密用户 角色授予 Web 应用,以便访问 Key Vault。
#!/bin/bash az role assignment create \ --role "Key Vault Secrets User" \ --assignee "$PRINCIPAL_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
在 Key Vault 中存储机密
为了避免在应用程序中硬编码机密,此步骤将 MongoDB 连接字符串 和 Web 应用的 密钥 存储在 Azure Key Vault 中。 然后,Web 应用可以通过托管标识在运行时安全地访问这些机密,而无需在代码或配置中存储凭据。
注意
虽然本教程仅将连接字符串和密钥存储在密钥保管库中,但可以选择性地将其他应用程序设置(例如 MongoDB 数据库名称或集合名称)存储在 Key Vault 中。
在此步骤中,使用 az cosmosdb keys list 命令检索 MongoDB 连接字符串。 然后使用 az keyvault secret set 命令在 Key Vault 中存储连接字符串和随机生成的密钥。
#!/bin/bash ACCOUNT_NAME="msdocs-cosmos-db-account-name" MONGO_CONNECTION_STRING=$(az cosmosdb keys list \ --name "$ACCOUNT_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --type connection-strings \ --query "connectionStrings[?description=='Primary MongoDB Connection String'].connectionString" -o tsv) SECRET_KEY=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9') # This key is cryptographically secure, using OpenSSL’s strong random number generator. az keyvault secret set \ --vault-name "$KEYVAULT_NAME" \ --name "MongoConnectionString" \ --value "$MONGO_CONNECTION_STRING" az keyvault secret set \ --vault-name "$KEYVAULT_NAME" \ --name "MongoSecretKey" \ --value "$SECRET_KEY"
将 Web 应用配置为使用 Kay Vault 机密
若要在运行时安全地访问机密,必须将 Web 应用配置为引用 Azure Key Vault 中存储的机密。 此步骤是使用 Key Vault 引用完成的,该引用通过其 系统分配的托管标识将机密值注入到应用的环境中。
此方法可避免硬编码机密,并允许应用在执行过程中安全地检索敏感值,例如 MongoDB 连接字符串和密钥。
在此步骤中,使用 az webapp config appsettings set 命令添加引用 Key Vault 机密的应用程序设置。 具体而言,这会设置
MongoConnectionString
和MongoSecretKey
应用设置以引用 Key Vault 中存储的相应机密。#!/bin/bash MONGODB_NAME="restaurants_reviews" MONGODB_COLLECTION_NAME="restaurants_reviews" az webapp config appsettings set \ --resource-group "$RESOURCE_GROUP_NAME" \ --name "$APP_SERVICE_NAME" \ --settings \ CONNECTION_STRING="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoConnectionString)" \ SECRET_KEY="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoSecretKey)" \ DB_NAME="$MONGODB_NAME" \ COLLECTION_NAME="$MONGODB_COLLECTION_NAME"
在 ACR 上启用持续部署
启用持续部署允许 Web 应用在推送到 Azure 容器注册表(ACR)时自动拉取和运行最新的容器映像。 这会减少手动部署步骤,并帮助确保应用保持最新状态。
注意
在下一步中,你将在 ACR 中注册 Webhook,以在推送新映像时通知 Web 应用。
在此步骤中,将使用 az webapp deployment container config 命令启用从 ACR 到 Web 应用的连续部署。
#!/bin/bash az webapp deployment container config \ --name "$APP_SERVICE_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --enable-cd true
为持续部署注册一个 ACR Webhook
若要自动执行部署,请注册 Azure 容器注册表(ACR)中的 Webhook,以在推送新的容器映像时通知 Web 应用。 Webhook 允许应用自动拉取和运行最新版本。
每当将新映像推送到 msdocspythoncontainerwebapp 存储库时,在 Azure 容器注册表(ACR)中配置的 Webhook 会将 POST 请求发送到 Web 应用的 SCM 终结点(SERVICE_URI)。 此作触发 Web 应用拉取和部署更新的映像,完成 ACR 和 Azure 应用服务之间的持续部署管道。
注意
Webhook URI 必须遵循以下格式:
https://<app-name>.scm.azurewebsites.net/api/registry/webhook
它 必须以结束/api/registry/webhook
. 如果收到 URI 错误,请确认路径正确。
在此步骤中,使用 az acr webhook create 命令注册 webhook,并将其配置为在
push
事件上触发。#!/bin/bash CREDENTIAL=$(az webapp deployment list-publishing-credentials \ --resource-group "$RESOURCE_GROUP_NAME" \ --name "$APP_SERVICE_NAME" \ --query publishingPassword --output tsv) # Web app publishing credentials may not be available immediately. In production, poll until non-empty. SERVICE_URI="https://$APP_SERVICE_NAME:$CREDENTIAL@$APP_SERVICE_NAME.scm.azurewebsites.net/api/registry/webhook" az acr webhook create \ --name webhookforwebapp \ --registry "$REGISTRY_NAME" \ --scope msdocspythoncontainerwebapp:* \ --uri "$SERVICE_URI" \ --actions push
浏览网站
若要验证 Web 应用是否正在运行,请打开 https://<website-name>.azurewebsites.net
,将其 <website-name>
替换为应用服务的名称。 你应该看到餐厅点评示例应用程序。 首次加载可能需要一些时间。
网站出现后,请尝试添加餐厅并提交评论以确认应用正常运行。
注意
Cloud Shell 不支持 az webapp browse
命令。 如果使用 Cloud Shell,请手动打开浏览器并导航到站点 URL。
如果在本地使用 Azure CLI,可以使用 az webapp browse 命令在默认浏览器中打开站点:
az webapp browse --name $APP_SERVICE_NAME --resource-group $RESOURCE_GROUP_NAME
注意
Cloud Shell 不支持 az webapp browse
命令。 打开浏览器窗口,然后改为导航到网站 URL。
排查部署问题
如果未看到示例应用,请尝试以下步骤。
- 使用容器部署和应用服务时,请始终在 Azure 门户中检查 部署中心 / 日志 页面。 确认已拉取并正在运行容器。 容器的初始拉取和运行可能需要一些时间。
- 尝试重启应用服务,看看这是否解决了你的问题。
- 如果存在编程错误,这些错误会显示在应用程序日志中。 在应用服务的 Azure 门户页上,选择 诊断并解决/应用程序日志的问题。
- 示例应用依赖于与 Azure Cosmos DB for MongoDB 的连接。 确认应用服务具有具有正确连接信息的应用程序设置。
- 确认已为 Azure 应用服务启用托管身份,并在部署中心中使用。 在应用服务的 Azure 门户页上,转到应用服务 部署中心 资源,确认 身份验证 设置为 托管标识。
- 检查 Webhook 是否已在 Azure 容器注册表中定义。 Webhook 使应用程序服务能够拉取容器映像。 具体而言,请检查服务 URI 是否以“/api/registry/webhook”结尾。 如果没有,请添加它。
- 不同的 Azure 容器注册表 SKU 具有不同的功能,包括 Webhook 的数量。 如果要重用现有注册表,则可能会看到消息:“注册表基本 SKU 的资源类型 Webhook 已超出配额。 详细了解不同的 SKU 配额和升级过程:https://aka.ms/acr/tiers"。 如果看到此消息,请使用新注册表,或减少正在使用的注册表 Webhook 数量。