本文是一个关于如何将 Python Web 应用程序容器化并部署到 Azure 容器应用的系列教程的一部分。 容器应用让你能够部署容器化应用,而无需管理复杂的基础结构。
在本教程中,你将:
- 通过在云中生成容器映像来容器化 Python 示例 Web 应用(Django 或 Flask)。
- 将容器映像部署到 Azure 容器应用。
- 定义环境变量,使容器应用能够连接到 Azure Database for PostgreSQL 灵活服务器 实例,其中示例应用存储数据。
下图重点介绍了本教程中的任务:生成和部署容器映像。
先决条件
如果没有 Azure 订阅,请在开始之前创建 免费帐户。
可以在 Azure Cloud Shell 或安装了 Azure CLI 的工作站上运行 Azure CLI 命令。
如果在本地运行,请按照以下步骤登录并安装本教程所需的模块:
如有必要,请登录到 Azure 并进行身份验证:
az login请确保运行最新版本的 Azure CLI:
az upgrade使用 az extension add 命令来安装或升级 containerapp 和 rdbms-connect Azure CLI 扩展:
az extension add --name containerapp --upgrade az extension add --name rdbms-connect --upgrade
获取示例应用
分叉并将示例代码克隆到开发人员环境:
转到示例应用程序(Django 或 Flask)的 GitHub 存储库,然后选择“分叉”。
请按照以下步骤将存储库分叉到 GitHub 帐户。 还可以直接将代码存储库下载到本地计算机,而无需分叉或 GitHub 帐户。 但是,如果使用下载方法,将无法在本系列的下一教程中设置持续集成和持续交付(CI/CD)。
在控制台中的命令提示符下,使用 git clone 命令将分叉存储库克隆到 python-container 文件夹中:
# Django git clone https://github.com/<github-username>/msdocs-python-django-azure-container-apps.git python-container # Flask # git clone https://github.com/<github-username>/msdocs-python-flask-azure-container-apps.git python-container更改目录:
cd python-container
从 Web 应用代码生成容器映像
执行这些步骤后,你将有一个 Azure 容器注册表实例,该实例包含从示例代码生成的 Docker 容器映像。
如果在 Windows 计算机上的 Git Bash shell 中运行命令,请在继续操作之前输入以下命令:
#!/bin/bash export MSYS_NO_PATHCONV=1使用 az group create 命令创建资源组:
#!/bin/bash RESOURCE_GROUP_NAME=<resource-group-name> LOCATION=<location> az group create \ --name $RESOURCE_GROUP_NAME \ --location $LOCATION使用 az acr create 命令创建容器注册表:
#!/bin/bash REGISTRY_NAME=<registry-name> #The name that you use for *\<registry-name>* must be unique within Azure, and it must contain 5 to 50 alphanumeric characters. az acr create \ --resource-group $RESOURCE_GROUP_NAME \ --name $REGISTRY_NAME \ --sku Basic \ --admin-enabled true使用 az acr login 命令登录到注册表:
az acr login --name $REGISTRY_NAME该命令会在名称中添加“azurecr.io”,以创建完全限定的注册表名称。 如果登录成功,将显示消息“登录成功”。 如果访问注册表的订阅不同于创建注册表的订阅,请使用
--suffix开关。如果登录失败,请确保 Docker 守护程序正在系统上运行。
使用 az acr build 命令生成映像:
#!/bin/bash az acr build \ --registry $REGISTRY_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --image pythoncontainer:latest .以下注意事项适用:
命令末尾的点(
.)指示要生成的源代码的位置。 如果未在示例应用的根目录中运行此命令,请指定代码的路径。如果在 Azure Cloud Shell 中运行命令,请使用
git clone先将存储库拉取到 Cloud Shell 环境中。 然后将目录更改为项目的根目录,以便正确解释点 (.)。如果不使用
-t(与--image相同)选项,则命令会将本地上下文生成排入队列,而不会将其推送到注册表。 在不推送的情况下生成映像可用于检查映像是否已生成。
使用 az acr repository list 命令确认已创建容器映像:
az acr repository list --name $REGISTRY_NAME
注意
本部分中的步骤在基本服务层中创建容器注册表。 此层经过成本优化,具有面向开发人员方案的功能集和吞吐量,适用于本教程的要求。 在生产环境中,您最有可能使用标准或高级服务层级。 这些层提供增强的存储和吞吐量级别。
若要了解详细信息,请参阅 Azure 容器注册表服务层。 有关定价的信息,请参阅 Azure 容器注册表定价。
创建 PostgreSQL 灵活服务器实例
示例应用程序(Django 或 Flask)将餐厅评论数据存储在 PostgreSQL 数据库中。 在这些步骤中,将创建包含数据库的服务器。
使用 az postgres flexible-server create 命令在 Azure 中创建 PostgreSQL 服务器。 此命令通常会运行几分钟才能完成。
#!/bin/bash ADMIN_USERNAME=demoadmin ADMIN_PASSWORD=<admin-password> # Use a strong password that meets the requirements for PostgreSQL. POSTGRES_SERVER_NAME=<postgres-server-name> az postgres flexible-server create \ --resource-group $RESOURCE_GROUP_NAME \ --name $POSTGRES_SERVER_NAME \ --location $LOCATION \ --admin-user $ADMIN_USERNAME \ --admin-password $ADMIN_PASSWORD \ --version 16 \ --tier Burstable \ --sku-name Standard_B1ms \ --public-access 0.0.0.0 \ --microsoft-entra-auth Enabled \ --storage-size 32 \ --backup-retention 7 \ --high-availability Disabled \ --yes使用以下值:
<postgres-server-name>:PostgreSQL 数据库服务器名称。 此名称在所有 Azure 中必须是唯一的。 服务器终结点为
https://<postgres-server-name>.postgres.database.azure.com。 允许的字符AZ、09和连字符(-)。<位置>:使用用于 Web 应用的相同位置。 <位置> 是命令
Name输出中的 Azure 位置az account list-locations -o table值之一。<管理员用户名>:管理员帐户的用户名。 它不能
azure_superuser、admin、administrator、root、guest或public。 在本教程中使用demoadmin。<管理员密码>:管理员用户的密码。 密码必须包含以下三个类别的 8 到 128 个字符:英文大写字母、英文小写字母、数字和非字母数字字符。
重要说明
创建用户名或密码时,不要使用美元符号 ($) 字符。 稍后,使用这些值创建环境变量时,该字符在用于运行 Python 应用的 Linux 容器中具有特殊含义。
--version:使用16。 它指定要用于服务器的 PostgreSQL 版本。--tier:使用Burstable。 它指定服务器的定价层。 可突发层是一种较低成本的选项,适用于不需要持续使用完整 CPU 的工作负荷,并且适合本教程的要求。--sku-name:定价层和计算配置的名称;例如,Standard_B1ms。 有关详细信息,请参阅 Azure Database for PostgreSQL 定价。 要列出可用层级,请使用az postgres flexible-server list-skus --location <location>。--public-access:使用0.0.0.0。 它允许从任何 Azure 服务(例如容器应用)公开访问服务器。--microsoft-entra-auth:使用Enabled。 它在服务器上启用Microsoft Entra 身份验证。--storage-size:使用32。 它指定服务器的存储大小(GB)。 最小值为 32 GB。--backup-retention:使用7。 它指定保留服务器的备份的天数。 最小值为 7 天。--high-availability:使用Disabled。 它禁用服务器的高可用性。 本教程不需要高可用性。--yes:它接受 PostgreSQL 服务器的使用条款。
注意
如果你计划从本地工作站通过工具访问 PostgreSQL 服务器,则需要使用 az postgres flexible-server firewall-rule create 命令为工作站的 IP 地址添加防火墙规则。
使用 az ad signed-in-user show 命令来获取用户帐户的对象 ID。 在下一个命令中将会用到此 ID。
#!/bin/bash CALLER_OBJECT_ID=$(az ad signed-in-user show --query id -o tsv) CALLER_DISPLAY_NAME=$(az ad signed-in-user show --query userPrincipalName -o tsv)使用 az postgres flexible-server ad-admin create 命令将用户帐户添加为 PostgreSQL 服务器上的 Microsoft Entra 管理员:
#!/bin/bash az postgres flexible-server microsoft-entra-admin create \ --server-name "$POSTGRES_SERVER_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --display-name "$CALLER_DISPLAY_NAME" \ --object-id "$CALLER_OBJECT_ID" \ --type User使用 az postgres flexible-server firewall-rule create 命令添加一条允许 Web 应用访问 PostgreSQL 灵活服务器的规则。 在以下命令中,将服务器的防火墙配置为使用公共 IP 地址接受来自开发工作站的连接:
MY_IP=$(curl -s ifconfig.me) az postgres flexible-server firewall-rule create \ --name "$POSTGRES_SERVER_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --rule-name allow-my-ip \ --start-ip-address "$MY_IP" \ --end-ip-address "$MY_IP" ```
注意
本部分中的步骤在可突发定价层中创建具有单个 vCore 和有限内存的 PostgreSQL 服务器。 可突发层是一种较低成本的选项,适用于不需要持续使用完整 CPU 的工作负荷,并且适合本教程的要求。 对于生产工作负荷,可以升级到“常规用途”或“内存优化”定价层。 这些层提供更高的性能,但会增加成本。
若要了解详细信息,请参阅 Azure Database for PostgreSQL 灵活服务器中的
在服务器上创建数据库
至此,你就拥有了一个 PostgreSQL 服务器。 在本部分中,你将在服务器上创建一个数据库。
使用 az postgres flexible-server db create 命令来创建名为 restaurants_reviews 的数据库:
#!/bin/bash
DATABASE_NAME=restaurants_reviews
az postgres flexible-server db create \
--resource-group $RESOURCE_GROUP_NAME \
--server-name $POSTGRES_SERVER_NAME \
--database-name $DATABASE_NAME
还可以使用 az postgres flexible-server connect 命令来连接到数据库,然后再使用 psql 命令。 在使用 psql 时,通常更容易使用 Azure Cloud Shell,因为该 shell 为你包含了所有所需的依赖项。
还可以连接到 Azure Database for PostgreSQL 灵活服务器,并使用 psql 或支持 PostgreSQL 的 IDE 创建数据库,例如 Azure Data Studio。 有关使用 psql 的步骤,请参阅本文后面的 在 PostgreSQL 数据库上配置托管标识。
创建用户分配的托管标识
创建用户分配的托管标识,以便在 Azure 中运行时用作容器应用的标识。
注意
若要创建用户分配的托管标识,你的帐户需要托管标识参与者角色分配。
使用 az identity create 命令创建用户分配的托管标识:
UA_MANAGED_IDENTITY_NAME=<managed-identity-name> # Use a unique name for the managed identity, such as-"my-ua-managed-id".
az identity create \
--name $UA_MANAGED_IDENTITY_NAME
--resource-group $RESOURCE_GROUP_NAME
在 PostgreSQL 数据库上配置托管标识
将托管标识配置为 PostgreSQL 服务器上的角色,然后向其授予对 restaurants_reviews 数据库所需的权限。 无论是使用 Azure CLI 还是 psql,都必须使用服务器实例中配置为 Microsoft Entra 管理员的用户连接到 Azure PostgreSQL 服务器。 只有被配置为 PostgreSQL 管理员的 Microsoft Entra 帐户才能在您的服务器上配置托管标识和其他 Microsoft 管理员角色。
使用 az account get-access-token 命令获取 Azure 帐户的访问令牌。 后续步骤中使用访问令牌。
#!/bin/bash MY_ACCESS_TOKEN=$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken) echo $MY_ACCESS_TOKEN使用 az postgres flexible-server execute 命令,将用户分配的托管标识添加为 PostgreSQL 服务器上的数据库角色。
#!/bin/bash az postgres flexible-server execute \ --name "$POSTGRES_SERVER_NAME" \ --admin-user "$CALLER_DISPLAY_NAME" \ --admin-password "$ACCESS_TOKEN" \ --database-name postgres \ --querytext "SELECT * FROM pgaadauth_create_principal('$UA_MANAGED_IDENTITY_NAME', false, false);"注意
如果在本地工作站上运行
az postgres flexible-server execute命令,请确保为工作站的 IP 地址添加了防火墙规则。 可以使用 az postgres flexible-server firewall-rule create 命令添加规则。 对于下一步中的命令也存在相同的要求。使用以下 az postgres flexible-server execute 命令授予用户分配的托管标识对 restaurants_reviews 数据库的必要权限:
#!/bin/bash SQL_GRANTS=$(cat <<EOF GRANT CONNECT ON DATABASE $DATABASE_NAME TO "$UA_MANAGED_IDENTITY_NAME"; GRANT USAGE, CREATE ON SCHEMA public TO "$UA_MANAGED_IDENTITY_NAME"; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "$UA_MANAGED_IDENTITY_NAME"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "$UA_MANAGED_IDENTITY_NAME"; EOF ) az postgres flexible-server execute \ --name "$POSTGRES_SERVER_NAME" \ --admin-user "$CALLER_DISPLAY_NAME" \ --admin-password "$MY_ACCESS_TOKEN" \ --database-name "$DATABASE_NAME" \ --querytext "$SQL_GRANTS"此 Azure CLI 命令连接到服务器上的 restaurants_reviews 数据库,并发出以下 SQL 命令:
GRANT CONNECT ON DATABASE restaurants_reviews TO "my-ua-managed-id"; GRANT USAGE ON SCHEMA public TO "my-ua-managed-id"; GRANT CREATE ON SCHEMA public TO "my-ua-managed-id"; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "my-ua-managed-id"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "my-ua-managed-id";
将 Web 应用部署到容器应用中
容器应用部署到 Azure 容器应用 环境,该环境充当安全边界。 在以下步骤中,将创建环境和环境内的容器。 然后配置容器,以便网站在外部可见。
这些步骤需要 Azure 容器应用扩展,containerapp。
使用 az containerapp env create 命令创建容器应用环境:
#!/bin/bash APP_ENV_NAME=<app-env-name> # Use a unique name for the environment, such as "python-container-env". az containerapp env create \ --name $APP_ENV_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --location $LOCATION使用 az acr credential show 命令获取 Azure 容器注册表实例的登录凭据:
#!/bin/bash REGISTRY_CREDS=$(az acr credential show -n "$REGISTRY_NAME" --query "[username,passwords[0].value]" -o tsv) REGISTRY_USERNAME=$(echo "$REGISTRY_CREDS" | head -n1) REGISTRY_PASSWORD=$(echo "$REGISTRY_CREDS" | tail -n1)在步骤 5 中创建容器应用时,可以使用命令输出中返回的用户名和密码之一。
使用 az identity show 命令,以获取用户分配的托管标识的客户端 ID 和资源 ID:
UA_CLIENT_ID=$(az identity show \ --name "$UA_MANAGED_IDENTITY_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query clientId -o tsv) UA_RESOURCE_ID=$(az identity show \ --name "$UA_MANAGED_IDENTITY_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query id -o tsv)在步骤 5 中创建容器应用时,可以使用命令输出中的客户端 ID(GUID)值和资源 ID。 资源 ID 具有以下形式:
/subscriptions/<subscription-id>/resourcegroups/pythoncontainer-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-ua-managed-id。运行以下命令以生成密钥值:
AZURE_SECRET_KEY=$(python -c 'import secrets; print(secrets.token_hex())')在步骤 5 中创建容器应用时,可以使用密钥值设置环境变量。
注意
此步骤显示的命令适用于 Bash shell。 根据环境,可能需要使用
python3调用 Python。 在 Windows 上,需要将命令用双引号而不是单引号括在-c参数中。 可能还需要使用py或py -3调用 Python,具体取决于环境。使用 az containerapp create 命令在环境中创建容器应用:
az containerapp create \ --name "$CONTAINER_APP_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --environment "$APP_ENV_NAME" \ --image "$REGISTRY_NAME.azurecr.io/$IMAGE_NAME" \ --target-port "$TARGET_PORT" \ --ingress external \ --registry-server "$REGISTRY_NAME.azurecr.io" \ --registry-username "$REGISTRY_USERNAME" \ --registry-password "$REGISTRY_PASSWORD" \ --user-assigned "$UA_RESOURCE_ID" \ --env-vars \ DBHOST="$POSTGRES_SERVER_NAME" \ DBNAME="$DATABASE_NAME" \ DBUSER="$UA_MANAGED_IDENTITY_NAME" \ RUNNING_IN_PRODUCTION=1 \ AZURE_CLIENT_ID="$UA_CLIENT_ID" \ AZURE_SECRET_KEY="$AZURE_SECRET_KEY"仅对 Django 迁移并创建数据库架构。 (在 Flask 示例应用中,这一步将自动完成,因此你可以跳过。)
使用 az containerapp exec 命令进行连接:
az containerapp exec \ --name $CONTAINER_APP_NAME \ --resource-group $RESOURCE_GROUP_NAME然后,在 shell 命令提示符处输入
python manage.py migrate。不需要为容器的修订版本进行迁移。
测试网站。
之前输入的
az containerapp create命令会输出一个应用程序 URL,您可以使用此 URL 浏览到应用程序。 URL 以azurecontainerapps.io结尾。 在浏览器中打开该 URL。 或者,也可以使用 az containerapp browse 命令。
下面是增加了一家餐厅和两条评论后的示例网站。
排查部署问题
你忘记了用于访问网站的应用程序 URL
在 Azure 门户中:
- 转到容器应用的 概述 页,查找 应用程序 URL。
在 VS Code 中:
- 转到 Azure 视图 (Ctrl+Shift+A),并展开正在处理的订阅。
- 展开容器应用节点,展开托管环境,右键单击 python-container-app,并选择浏览。 VS Code 使用应用程序 URL 打开浏览器。
在 Azure CLI 中:
- 使用命令
az containerapp show -g pythoncontainer-rg -n python-container-app --query properties.configuration.ingress.fqdn。
在 VS Code 中,Azure 任务中的生成映像返回错误
如果“错误:未能下载上下文。 请检查 VS Code 输出 窗口中的 URL 是否不正确,请在 Docker 扩展中刷新注册表。 若要刷新,请选择 Docker 扩展,转到 注册表 部分,找到注册表,然后选择它。
如果再次运行在 Azure 中生成映像任务,请检查上次运行的注册表是否存在。 如果存在,请使用它。
在 Azure 门户中,在创建容器应用期间出现访问错误
禁用 Azure 容器注册表实例上的管理员凭据时,会出现包含“无法访问 ACR'<名称>.azurecr.io'”的访问错误。
若要在门户中检查管理员状态,请转到 Azure 容器注册表实例,选择 访问密钥 资源,并确保启用 管理员用户。
容器映像不会显示在 Azure 容器注册表实例中
- 检查 Azure CLI 命令或 VS Code 输出的输出,并查找消息以确认成功。
- 检查使用 Azure CLI 的构建命令或 VS Code 任务提示中是否正确指定了注册表的名称。
- 确保证书没有过期。 例如,在 VS Code 中,在 Docker 扩展中找到目标注册表并刷新。 在 Azure CLI 中,运行
az login。
网站返回“错误请求(400)”
如果收到“错误请求(400)”错误,请检查传递到容器的 PostgreSQL 环境变量。 400 错误通常表示 Python 代码无法连接 PostgreSQL 实例。
本教程中使用的示例代码检查容器环境变量是否存在 RUNNING_IN_PRODUCTION,该变量可以设置为任何值(如 1)。
网站返回“未找到(404)”
- 检查概述页面上容器的应用程序 Url 值。 如果应用程序 URL 包含“内部”一词,则未正确设置入口。
- 检查容器的入口。 例如,在 Azure 门户中,转到容器的入口资源。 确保启用了 HTTP 入口,并选择了接受来自任何位置的流量。
网站无法启动,你会看到“流超时”,或者未返回任何结果
- 检查日志:
- 在 Azure 门户中,转到容器应用的修订管理功能资源,并查看容器的 预配状态:
- 如果状态为正在预配,请等待预配完成。
- 如果状态是失败,请选择修订并查看控制台日志。 选择显示生成时间、Stream_s 和 Log_s 列的顺序。 按最新日志进行排序,并在
stderr列中查找 Pythonstdout和 消息。 Pythonprint输出stdout消息。
- 在 Azure CLI 中,使用 az containerapp logs show 命令。
- 在 Azure 门户中,转到容器应用的修订管理功能资源,并查看容器的 预配状态:
- 如果使用 Django 框架,请检查数据库中是否存在 restaurants_reviews 表。 如果没有,请使用控制台访问容器并运行
python manage.py migrate。