在本教程中,你要将一个使用 Azure Database for PostgreSQL 关系数据库服务的数据驱动 Python Web 应用( Django Flask )部署到 Azure 应用服务 。 Azure 应用服务支持 Linux 服务器环境中的 Python 3.7 或更高版本

若要完成本教程,你需要:

  • 具有活动订阅的 Azure 帐户。 如果没有 Azure 帐户,可以 免费创建一个
  • 了解使用 Flask 的 Python 开发或 使用 Django 的 Python 开发
  • 示例应用程序

    我们提供了使用 Flask 和 Django 框架的示例 Python 应用程序来帮助你学习本教程。 若要部署这些应用程序但不在本地运行它们,请跳过本部分。

    若要在本地运行应用程序,请确保在本地安装 Python 3.7 或更高版本 PostgreSQL 。 然后下载或克隆应用:

    Flask Django

    使用 .env.sample 文件作为指南创建 .env 文件,如下所示。 将 DBNAME 的值设置为本地 PostgreSQL 实例中现有数据库的名称。 根据本地 PostgreSQL 实例设置相应的 DBHOST DBUSER DBPASS 值。

    DBNAME=<database name>
    DBHOST=<database-hostname>
    DBUSER=<db-user-name>
    DBPASS=<db-password>
    

    通过在终端提示符下运行以下命令,为应用创建 SECRET_KEY 值:python -c 'import secrets; print(secrets.token_hex())'

    将返回的值设置为 .env 文件中 SECRET_KEY 的值。

    SECRET_KEY=<secret-key>
    

    为应用创建一个虚拟环境:

    Windows macOS/Linux

    1. 创建应用服务和 PostgreSQL

    此步骤创建 Azure 资源。 本教程中使用的步骤创建一组默认安全的资源,其中包括应用服务和 Azure Database for PostgreSQL。 此创建过程中,你将指定:

  • Web 应用的名称。 此名称用作 Web 应用的 DNS 名称的一部分,其格式为 https://<app-name>.azurewebsites.net
  • “区域”,在世界上以物理方式运行应用。
  • 应用的运行时堆栈。 在此处选择要用于应用的 Python 版本。
  • 应用的托管计划。 它是定价层,包括应用的一组功能和缩放容量。
  • 应用的资源组。 使用资源组可将应用程序所需的所有 Azure 资源分组到一个逻辑容器中。
  • 登录到 Azure 门户并按照以下步骤创建 Azure 应用服务资源。

    步骤 1。 在 Azure 门户中:

  • 在 Azure 门户顶部的搜索栏中,输入“Web 应用数据库”。
  • 选择“市场”标题下标记为“Web 应用 + 数据库”的项目。 还可以直接导航到创建向导
  • 步骤 2. 在“创建 Web 应用 + 数据库”页上,按如下所述填写表单。

  • 资源组 → 选择“新建”,然后使用名称 msdocs-python-postgres-tutorial。
  • 区域 → 与你靠近的任何 Azure 区域。
  • 名称 → msdocs-python-postgres-XYZ,其中 XYZ 是任意三个随机字符。 该名称在 Azure 中必须唯一。
  • 运行时堆栈Python 3.10
  • 数据库 → 默认已选择“PostgreSQL 灵活服务器”作为数据库引擎。 默认情况下,服务器名称和数据库名称也会设置为适当的值。
  • 托管计划 → 基本。 准备就绪后,可以稍后纵向扩展到生产定价层。
  • 选择“查看 + 创建”。
  • 验证完成后,选择“创建”。
  • 应用服务计划 → 定义应用服务的计算资源。 将创建基本层中的 Linux 计划。
  • 应用服务 → 表示应用,且在应用服务计划中运行。
  • 虚拟网络 → 与应用服务应用集成,并隔离后端网络流量。
  • Azure Database for PostgreSQL 灵活服务器 → 只能从虚拟网络内部访问。 你的数据库和用户创建于此服务器上。
  • 专用 DNS 区域 → 在虚拟网络中启用 PostgreSQL 服务器的 DNS 解析。
  • 2. 验证连接设置

    创建向导已经为你生成了连接变量作为应用设置。 使用应用设置可以将连接机密保留在代码存储库之外。 准备好将机密移动到更安全的位置后,下面提供了一篇有关在 Azure 密钥保管库中存储的文章

    步骤 1。 在左侧菜单的“应用服务”页面中,选择“配置”。

  • 登录到 GitHub 帐户。
  • 导航到 https://github.com/Azure-Samples/msdocs-flask-postgresql-sample-app
  • 选择“Fork”。
  • 选择“创建分支”。
  • 在“源”中,选择“GitHub”。 默认情况下,选择 GitHub Actions 作为生成提供程序。
  • 登录到 GitHub 帐户,并按照提示授权 Azure。
  • 在“组织”中,选择你的帐户。
  • 在“存储库”中,选择“msdocs-flask-postgresql-sample-app”。
  • 在“分支”中,选择“主”。
  • 保留所选的默认选项以添加工作流
  • 在顶部菜单中,选择“保存”。 应用服务会将工作流文件提交到所选 GitHub 存储库中(在 .github/workflows 目录中)。
  • 登录到 GitHub 帐户。
  • 导航到 https://github.com/Azure-Samples/msdocs-django-postgresql-sample-app
  • 选择“Fork”。
  • 选择“创建分支”。
  • 在“源”中,选择“GitHub”。 默认情况下,选择 GitHub Actions 作为生成提供程序。
  • 登录到 GitHub 帐户,并按照提示授权 Azure。
  • 在“组织”中,选择你的帐户。
  • 在“存储库”中,选择“msdocs-django-postgresql-sample-app”。
  • 在“分支”中,选择“主”。
  • 在顶部菜单中,选择“保存”。 应用服务会将工作流文件提交到所选 GitHub 存储库中(在 .github/workflows 目录中)。
  • def index(request): print('Request for index page received') restaurants = Restaurant.objects.annotate(avg_rating=Avg('review__rating')).annotate(review_count=Count('review')) return render(request, 'restaurant_review/index.html', {'restaurants': restaurants})

    为 Python 应用程序设置 Azure Monitor 系列文章中,详细了解 Python 应用中的日志记录。

    7.清理资源

    完成后,可以通过删除资源组从 Azure 订阅中删除所有资源。

    步骤 1。 在 Azure 门户顶部的搜索栏中:

  • 输入资源组名称。
  • 选择前面创建的资源组。
  • 下面列出了尝试完成本教程时可能遇到的问题以及解决这些问题的步骤。

    无法连接到 SSH 会话

    如果你无法连接到 SSH 会话,则表示应用本身已启动失败。 请查看诊断日志了解详细信息。 例如,如果看到类似于 KeyError: 'AZURE_POSTGRESQL_CONNECTIONSTRING' 的错误,则可能表示缺少环境变量(你可能已删除应用设置)。

    运行数据库迁移时出错

    如果遇到与连接数据库相关的任何错误,请检查应用设置 (AZURE_POSTGRESQL_CONNECTIONSTRING) 是否已更改。 如果没有该连接字符串,则 migrate 命令将无法与数据库通信。

    使用 Azure Developer CLI 进行预配和部署

    我们提供了使用 Flask 和 Django 框架的示例 Python 应用程序模板来帮助你学习本教程。 Azure Developer CLI 大大简化了在 Azure 上预配应用程序资源和部署代码的过程。 有关使用 Azure 门户和其他工具的更详细的分步方法,请切换到页面顶部的 Azure 门户方法。

    Azure Developer CLI (azd) 将为项目初始化、预配、部署、监视和搭建用于针对实际 Azure 资源运行的 CI/CD 管道提供端到端支持。 你可以使用 azd 以自动化的简化方式为示例应用程序预配和部署资源。

    按照以下步骤设置 Azure Developer CLI 并预配和部署示例应用程序:

  • 安装 Azure Developer CLI。 有关受支持的安装选项和工具的完整列表,请访问安装指南

    Windows macOS/Linux
  • azd up 命令运行完毕后,将打印控制台中显示的所部署 Web 应用的 URL。 单击或复制 Web 应用 URL 并将其粘贴到浏览器中,以浏览正在运行的应用并验证其是否可正常使用。 azd up 命令已为你设置所有 Azure 资源和应用程序代码。

    创建的资源组的名称也会显示在控制台输出中。 在 Azure 门户中找到资源组,查看所有预配的资源。

    借助 Azure Developer CLI,你还可以将应用程序配置为使用 CI/CD 管道来完成部署、设置监视功能,甚至移除预配的资源(如果想要删除所有资源)。 有关这些附加工作流的详细信息,请访问自述文件项目。

    浏览已完成的 azd 项目模板工作流

    前面的部分更深入地回顾了 azd 为你处理的步骤。 你可以浏览此工作流,以便更好地了解将自己的应用部署到 Azure 时所需满足的要求。 在你运行 azd up 时,Azure Developer CLI 完成了以下步骤:

    你还可以使用此工作流的 Azure 门户版本中概述的步骤来深入了解 azd 为你完成的任务。

    1. 克隆并初始化项目

    azd up 命令将示例应用项目模板克隆到了你的计算机上。 该项目模板包括以下组件:

  • 源代码:Flask 或 Django Web 应用的代码和资产,可用于本地开发或部署到 Azure。
  • Bicep 文件:基础结构即代码 (IaC) 文件,供 azd 用于在 Azure 中创建必要的资源。
  • 配置文件:基本配置文件,例如可由 azd 用于预配、部署和连接资源以生成完备的应用程序的 azure.yaml
  • 2. 预配 Azure 资源

    azd up 命令使用项目模板的 infra 文件夹中的 Bicep 文件为 Azure 中的示例应用程序创建了所有资源。 Bicep 是一种声明性语言,用于在 Azure 中管理基础结构即代码。 模板创建的一些关键资源和配置包括:

  • 资源组:创建了一个资源组来保存所有其他预配的 Azure 资源。 资源组可使资源井然有序,且更易于管理。 资源组的名称将基于你在 azd up 初始化过程中指定的环境名称。
  • Azure 虚拟网络:创建了一个虚拟网络,从而使预配的资源能够安全地相互连接和通信。 还应用了相关配置,例如设置专用 DNS 区域链路。
  • Azure 应用服务计划:创建了一个应用服务计划来托管应用服务实例。 应用服务计划会定义哪些计算资源可用于一个或多个 Web 应用。
  • Azure 应用服务:在新的应用服务计划中创建了一个应用服务实例,用于托管和运行部署的应用程序。 在本例中,创建了一个 Linux 实例,并将其配置为运行 Python 应用。 应用服务还应用了其他配置,例如设置 Postgres 连接字符串和密钥。
  • Azure Database for PostgreSQL:为托管在要连接到的应用服务上的应用创建了 Postgres 数据库和服务器。 还配置了所需的管理员用户、网络和连接设置。
  • Azure Application Insights:为托管在应用服务上的应用设置和配置的 Application Insights。 此服务可为你的应用程序启用详细的遥测和监视。
  • 你可以检查项目的 infra 文件夹中的 Bicep 文件,以更详细地了解其中每个资源的预配方式。 resources.bicep 文件会定义在 Azure 中创建的大多数不同服务。 例如,应用服务计划和应用服务 Web 应用实例便是使用以下 Bicep 代码创建并连接的:

    Flask Django
    resource appServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
      name: '${prefix}-service-plan'
      location: location
      tags: tags
      sku: {
        name: 'B1'
      properties: {
        reserved: true
    resource web 'Microsoft.Web/sites@2022-03-01' = {
      name: '${prefix}-app-service'
      location: location
      tags: union(tags, { 'azd-service-name': 'web' })
      kind: 'app,linux'
      properties: {
        serverFarmId: appServicePlan.id
        siteConfig: {
          alwaysOn: true
          linuxFxVersion: 'PYTHON|3.10'
          ftpsState: 'Disabled'
          appCommandLine: 'startup.sh'
        httpsOnly: true
      identity: {
        type: 'SystemAssigned'
    
    resource appServicePlan 'Microsoft.Web/serverfarms@2021-03-01' = {
      name: '${prefix}-service-plan'
      location: location
      tags: tags
      sku: {
        name: 'B1'
      properties: {
        reserved: true
    resource web 'Microsoft.Web/sites@2022-03-01' = {
      name: '${prefix}-app-service'
      location: location
      tags: union(tags, { 'azd-service-name': 'web' })
      kind: 'app,linux'
      properties: {
        serverFarmId: appServicePlan.id
        siteConfig: {
          alwaysOn: true
          linuxFxVersion: 'PYTHON|3.10'
          ftpsState: 'Disabled'
          appCommandLine: 'startup.sh'
        httpsOnly: true
      identity: {
        type: 'SystemAssigned'
    

    Azure Database for PostgreSQL 也是使用以下 Bicep 创建的:

    resource postgresServer 'Microsoft.DBforPostgreSQL/flexibleServers@2022-01-20-preview' = {
      location: location
      tags: tags
      name: pgServerName
      sku: {
        name: 'Standard_B1ms'
        tier: 'Burstable'
      properties: {
        version: '12'
        administratorLogin: 'postgresadmin'
        administratorLoginPassword: databasePassword
        storage: {
          storageSizeGB: 128
        backup: {
          backupRetentionDays: 7
          geoRedundantBackup: 'Disabled'
        network: {
          delegatedSubnetResourceId: virtualNetwork::databaseSubnet.id
          privateDnsZoneArmResourceId: privateDnsZone.id
        highAvailability: {
          mode: 'Disabled'
        maintenanceWindow: {
          customWindow: 'Disabled'
          dayOfWeek: 0
          startHour: 0
          startMinute: 0
      dependsOn: [
        privateDnsZoneLink
    

    3. 部署应用程序

    azd up 命令还向预配的 Azure 资源部署了示例应用程序代码。 Developer CLI 了解如何使用项目根目录中的 azure.yaml 文件将应用程序代码的不同部分部署到 Azure 中的不同服务。 azure.yaml 文件会指定应用源代码的位置、应用类型和应托管该应用的 Azure 服务。

    请考虑以下 azure.yaml 文件。 这些配置会告诉 Azure Developer CLI,应将位于项目根目录中的 Python 代码部署到所创建的应用服务。

    Flask Django
    name: flask-postgresql-sample-app
    metadata:
      template: flask-postgresql-sample-app@0.0.1-beta
    services:
        project: .
        language: py
        host: appservice
    
    name: django-postgresql-sample-app
    metadata:
      template: django-postgresql-sample-app@0.0.1-beta
    services:
        project: .
        language: py
        host: appservice
    

    使用示例应用程序完成试验后,可以运行 azd down 命令从 Azure 中移除该应用。 移除资源有助于避免 Azure 订阅中出现意外费用或未使用的服务。

    azd down
    
  • 此设置花费有多大?
  • 如何使用其他工具连接到在虚拟网络后面受保护的 PostgreSQL 服务器?
  • 本地应用开发如何处理 GitHub Actions?
  • 如何将 Django 示例配置为在 Azure 应用服务上运行?
  • 此设置花费有多大?

    所创建资源的定价如下所示:

  • 应用服务计划在基本层中创建,可以进行纵向扩展或缩减。 请参阅应用服务定价
  • PostgreSQL 灵活服务器是在最低可突发层 Standard_B1ms 中创建的,该层提供最小的存储大小,但可以纵向扩展或缩减。 请参阅 Azure Database for PostgreSQL 定价
  • 除非配置额外的功能(例如对等互连),否则虚拟网络不会产生费用。 请参阅 Azure 虚拟网络定价
  • 专用 DNS 区域会产生少量费用。 请参阅 Azure DNS 定价
  • 如何使用其他工具连接到在虚拟网络后面受保护的 PostgreSQL 服务器?

  • 若要从 commmand-line 工具进行基本访问,可以从应用的 SSH 终端运行 psql
  • 若要从桌面工具进行连接,计算机必须位于虚拟网络中。 例如,它可以是连接到其中一个子网的 Azure VM,也可以是与 Azure 虚拟网络建立了站点到站点 VPN 连接的本地网络中的计算机。
  • 还可以将 Azure Cloud Shell 与虚拟网络集成。
  • 本地应用开发如何与 GitHub Actions 配合使用?

    以应用服务中自动生成的工作流文件为例,每个 git push 都会启动新的生成和部署运行。 从 GitHub 存储库的本地克隆中,进行所需更新并推送到 GitHub。 例如:

    git add .
    git commit -m "<some-message>"
    git push origin main
    

    如何将 Django 示例配置为在 Azure 应用服务上运行?

    如果使用自己的应用按照本教程中所述内容进行操作,请查看每个项目的 README.md 文件中的 requirements.txt 文件说明(FlaskDjango),以了解自己需要的包。

    Django 示例应用程序在 azureproject/production.py 文件中配置设置,使它可以在 Azure 应用服务中运行。 将 Django 部署到生产环境时经常会做出这些更改,它们并非特定于应用服务。

  • Django 验证传入请求中的 HTTP_HOST 标头。 示例代码使用应用服务中的 WEBSITE_HOSTNAME 环境变量将应用的域名添加到 Django 的 ALLOWED_HOSTS 设置。

    # Configure the domain name using the environment variable # that Azure automatically creates for us. ALLOWED_HOSTS = [os.environ['WEBSITE_HOSTNAME']] if 'WEBSITE_HOSTNAME' in os.environ else []
  • Django 不支持在生产中提供静态文件。 对于本教程,请使用 WhiteNoise 来支持提供文件。 WhiteNoise 包已与 requirements.txt 一起安装,其中间件已添加到列表中。

    # WhiteNoise configuration MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', # Add whitenoise middleware after the security middleware 'whitenoise.middleware.WhiteNoiseMiddleware',

    然后根据 Django 文档配置静态文件设置。

    STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')

    有关详细信息,请参阅 Django 应用的生产设置

    请继续学习下一教程,了解如何使用自定义域和证书保护应用。

     使用自定义域和证书进行保护

    了解应用服务如何运行 Python 应用:

    配置 Python 应用

  •