使用 GitHub Actions 将 Python Web 应用部署到应用服务(Linux)

本文介绍如何使用 GitHub Actions 中的持续集成和持续交付(CI/CD)平台将 Python Web 应用部署到 Linux 上的 Azure 应用服务。 GitHub Actions 工作流会自动生成代码,并在向存储库提交时将其部署到应用服务实例。 可以在 GitHub Actions 工作流中添加其他自动化,例如测试脚本、安全检查和多阶段部署。

为应用代码创建存储库

若要完成本文中的过程,需要提交到 GitHub 存储库的 Python Web 应用。

注释

如果应用使用 DjangoSQLite 数据库,则它不适用于这些过程。 由于基于本地文件的存储限制,大多数云托管环境中不支持 SQLite。 请考虑切换到与云兼容的数据库,例如 PostgreSQL 或 Azure Cosmos DB。 有关详细信息,请参阅本文后面的 “查看 Django 注意事项 ”。

创建目标应用服务实例

创建应用服务实例的最快方法是通过交互式 Azure Cloud Shell 使用 Azure 命令行接口(CLI)。 Cloud Shell 包括 Git 和 Azure CLI。 在以下过程中,使用 az webapp up 命令创建应用服务实例并执行应用的初始部署。

  1. 通过 https://portal.azure.com 登录到 Azure 门户。

  2. 通过选择门户工具栏上的 Cloud Shell 选项打开 Azure CLI:

    屏幕截图显示如何通过在 Azure 门户工具栏上使用图标操作来打开 Azure Cloud Shell。

  3. 在 Cloud Shell 中,从下拉菜单中选择 Bash 选项:

    显示如何在 Cloud Shell 中选择 Bash 选项的屏幕截图。

  4. 在 Cloud Shell 中,使用命令 git clone 克隆存储库。

    小窍门

    若要将命令或文本粘贴到 Cloud Shell 中,请使用 Ctrl+Shift+V 键盘快捷方式,或右键单击并选择上下文菜单中的 “粘贴 ”。

    • 对于 Flask 示例应用,可以使用以下命令。 将 <github-user> 部分替换为创建存储库分支的 GitHub 帐户的名称:

      git clone https://github.com/<github-user>/python-sample-vscode-flask-tutorial.git
      
    • 如果应用位于其他存储库中,请为特定存储库设置 GitHub Actions。 将 <github-user> 部分替换为你创建存储库分支的 GitHub 帐户的名称,并在 <repo-name> 占位符中提供实际的存储库名称:

      git clone https://github.com/<github-user>/<repo-name>.git
      

    注释

    Cloud Shell 由名为 cloud-shell-storage-your-region<> 的资源组中的 Azure 存储帐户提供支持。 该存储帐户包含 Cloud Shell 文件系统的映像,用于存储克隆的存储库。 此存储的成本很小。 完成本文后,可以删除存储帐户以及创建的其他资源。

  5. 在 Cloud Shell 中,将目录更改为 Python 应用的存储库文件夹,因此 az webapp up 命令会将应用识别为 Python。 对于 Flask 示例应用,请使用以下命令:

    cd python-sample-vscode-flask-tutorial
    
  6. 在 Cloud Shell 中,使用 az webapp up 命令创建应用服务实例,并为应用执行初始部署:

    az webapp up --name <app-service-name> --runtime "PYTHON:3.9"
    
    • <app-service-name>对于占位符,请指定 Azure 中唯一的应用服务名称。 名称长度必须为 3-60 个字符,只能包含字母、数字和连字符。 名称必须以字母开头,并且必须以字母或数字结尾。

    • 有关系统上可用运行时的列表,请使用 az webapp list-runtimes 命令。

    • 在命令中输入运行时值时,请使用 PYTHON:X.Y 格式,即 X.Y Python 主版本和次要版本。

    • 还可以使用 --location 参数指定应用服务实例的区域位置。 若要获取可用位置的列表,请使用 az account list-locations --output table 命令。

  7. 如果应用具有自定义启动脚本,请使用 az webapp config 命令启动脚本。

    • 如果应用没有自定义启动脚本,请继续执行下一步。

    • 对于 Flask 示例应用,需要运行以下命令来访问 startup.txt 文件中的启动脚本:

      az webapp config set \
         --resource-group <resource-group-name> \
         --name <app-service-name> \
         --startup-file startup.txt
      

      请在<resource-group-name><app-service-name>占位符中输入资源组名称和应用服务实例名称。 若要查找资源组名称,请检查上一 az webapp up 命令的输出。 资源组名称包括 Azure 帐户名称,后跟 _rg 后缀,如 <azure-account-name>_rg所示。

  8. 若要查看正在运行的应用,请打开浏览器并转到应用服务实例的部署终结点。 在以下 URL 中,将 <app-service-name> 占位符替换为应用服务实例名称:

    http://<app-service-name>.azurewebsites.net
    

    如果看到泛型页面,请等待几秒钟,让应用服务实例启动并刷新页面。

    • 如果继续看到通用页面,请确认已从正确的文件夹部署。
    • 对于 Flask 示例应用,请确认已从 python-sample-vscode-flask-tutorial 文件夹部署。 另请检查是否已正确设置启动命令。

在应用服务中设置持续部署

在下一过程中,设置持续交付(CD),这意味着每当工作流触发时,就会进行新的代码部署。 本文示例中的触发器是对存储库的分支进行的任何更改,例如拉取请求 (PR)。

  1. 在 Cloud Shell 中,确认你位于系统的根目录中(~),而不是在应用子文件夹中,例如 python-sample-vscode-flask-tutorial

  2. 使用 az webapp deployment github-actions add 命令添加 GitHub Actions。 将任何占位符替换为你的特定值:

    az webapp deployment github-actions add \
      --repo "<github-user>/<github-repo>" \
      --resource-group <resource-group-name> \
      --branch <branch-name> \
      --name <app-service-name> \
      --login-with-github
    
    • --login-with-github 参数使用交互式方法检索个人访问令牌。 按照提示作并完成身份验证。

    • 如果系统遇到具有相同应用服务实例名称的现有工作流文件,请按照提示选择是否覆盖工作流。 可以将参数 --force 与命令一起使用,以自动覆盖任何冲突的工作流。

    add 命令完成以下任务:

    • 存储库中的 .github/workflows/<workflow-name>.yml 路径处创建新的工作流文件。 文件名包含应用服务实例的名称。
    • 为应用程序服务实例获取包含机密的发布配置文件,并将其添加为 GitHub Actions 机密。 机密的名称以 AZUREAPPSERVICE_PUBLISHPROFILE_开头。 此机密在工作流文件中引用。
  3. 使用 az webapp deployment source show 命令获取源代码管理部署配置的详细信息。 将占位符参数替换为你的特定值:

    az webapp deployment source show \
      --name <app-service-name> \
      --resource-group <resource-group-name>
    
  4. 在命令输出中,确认repoUrlbranch属性的值。 这些值应与使用命令指定的 add 值匹配。

检查 GitHub 工作流和操作

工作流定义在存储库中 /.github/workflows/ 路径的 YAML (.yml) 文件中指定。 此 YAML 文件包含构成工作流的各种步骤和参数,这是与 GitHub 存储库关联的自动化过程。 可以使用工作流在 GitHub 上生成、测试、打包、发布和部署任何项目。

每个工作流由一个或多个作业组成,每个作业都是一组步骤。 每个步骤都是 shell 脚本或是一个操作。 每个作业在工作流文件中都有一个 Action 节。

对于使用 Python 代码设置的、用于部署到 Azure 应用服务的工作流,该工作流具有以下操作:

行动 DESCRIPTION
结账 查看 运行器(GitHub Actions 代理)上的存储库。
setup-python 在运行器上安装 Python。
appservice-build 构建 Web 应用。
webapps-deploy 使用发布配置文件凭据在 Azure 中进行身份验证来部署 Web 应用。 凭据存储在 GitHub 机密中。

用于创建工作流的工作流模板是 Azure/actions-workflow-samples

工作流在将事件推送到指定的分支时触发。 事件和分支在工作流文件的开头定义。 例如,以下代码片段显示工作流是在将事件推送到 分支时触发的:

on:
  push:
    branches:
    - main

OAuth 授权的应用

设置持续部署时,可将 Azure 应用服务授权为 GitHub 帐户的授权 OAuth 应用。 应用服务使用授权访问在存储库的 .github/workflows/<workflow-name>.yml 路径创建一个 GitHub Action 的 YAML 文件。

若要查看授权的应用并在 GitHub 帐户下撤销权限,请转到“设置集成/应用程序”>:

显示如何查看 GitHub 帐户的授权 OAuth 应用的屏幕截图。

工作流发布配置文件机密

在添加到存储库的 .github/workflows/<workflow-name>.yml 工作流文件中,有一个占位符,用于发布工作流部署作业所需的配置文件凭据。 发布配置文件信息以加密形式存储在存储库中。

若要查看机密,请转到 “设置>安全>机密”和“变量>”:

显示如何在 GitHub 中查看存储库操作秘密的屏幕截图。

在本文中,GitHub 操作使用发布配置文件凭据进行身份验证。 可通过其他方法进行身份验证,例如使用服务主体或 OpenID Connect。 有关详细信息,请参阅 使用 GitHub Actions 部署到应用服务

运行和测试工作流

最后一步是通过更改存储库来测试工作流。

  1. 在浏览器中,转到示例存储库(或使用的存储库),然后选择你之前设置为触发器一部分的分支:

    显示如何转到定义 GitHub Actions 工作流的存储库和分支的屏幕截图。

  2. 对 Python Web 应用进行少量更改。

    对于 Flask 教程,以下是简单的更改:

    1. 转到触发器分支的 /hello-app/templates/home.html 文件。
    2. 选择 “编辑 ”(铅笔)。
    3. 在编辑器中,找到 print <p> 语句,并添加文本“重新部署!”
  3. 将更改直接提交到你正在工作的分支。

    1. 在编辑器中,选择右上角的 “提交更改 ”。 “ 提交更改 ”窗口随即打开。
    2. “提交更改 ”窗口中,根据需要修改提交消息,然后选择“ 提交更改”。

    提交过程会触发 GitHub Actions 工作流。

还可以手动触发工作流:

  1. 转到为持续部署设置的存储库的“操作”选项卡。

  2. 在工作流列表中选择工作流,然后选择“ 运行工作流”。

排查工作流故障

可以在应用存储库的 “作 ”选项卡上检查工作流的状态。 检查本文中创建的工作流文件时,会看到两个作业: 生成部署。 提醒一下,工作流基于 Azure/actions-workflow-samples 模板。

对于失败的作业,请查看作业任务的输出以确定失败原因。

下面是一些要调查的常见问题:

  • 如果应用由于缺少依赖项而失败,则部署期间未处理 requirements.txt 文件。 如果直接在门户上创建了 Web 应用,而不是使用 az webapp up 本文中所示的命令,则会发生此行为。

  • 如果通过门户配置了应用服务,则生成操作SCM_DO_BUILD_DURING_DEPLOYMENT设置可能未被设置。 此设置必须设置为 true。 该 az webapp up 命令会自动设置生成操作。

  • 如果看到有关“TLS 握手超时”的错误消息,请在应用存储库的“操作”选项卡下选择“触发自动部署”手动运行工作流。 可以确定超时是否是临时问题。

  • 如果为容器应用设置持续部署,如本文所示,则会自动为你创建初始工作流文件 .github/workflows/<workflow-name>.yml 。 如果修改了该文件,请删除修改,以查看它们是否导致失败。

运行部署后脚本

部署后脚本可以完成多个任务,例如定义应用代码预期的环境变量。 将脚本添加为应用代码的一部分,并使用启动命令执行脚本。

若要避免在工作流 YAML 文件中对变量值进行硬编码,请考虑在 GitHub 中配置变量并引用脚本中的变量名称。 可以为存储库或环境(帐户存储库)创建加密机密。 有关详细信息,请参阅 在 GitHub Actions 中使用机密

查看 Django 注意事项

如本文前面所述,如果使用单独的数据库,可以使用 GitHub Actions 将 Django 应用部署到 Linux 上的 Azure 应用服务。 无法使用 SQLite 数据库,因为应用服务会锁定 db.sqlite3 文件,这会阻止读取和写入。 此行为不会影响外部数据库。

应用服务上配置 Python 应用 - 容器启动过程 文章介绍了应用服务如何在应用代码中自动查找 wsgi.py 文件(通常包含应用对象)。 使用 webapp config set 命令设置启动命令时,使用 --startup-file 参数指定包含应用对象的文件。 该 webapp config set 命令在 webapps-deploy作中不可用。 相反,可以使用 startup-command 参数来指定启动命令。 例如,以下代码演示如何在工作流文件中指定启动命令:

startup-command: startup.txt

使用 Django 时,通常希望在部署应用代码后使用 python manage.py migrate 命令迁移数据模型。 可以在部署后脚本中运行 migrate 命令。

断开 GitHub Actions 的连接

通过断开 GitHub Actions 与应用服务实例的连接,可以重新配置应用部署。 可以在断开连接后选择工作流文件会发生什么情况,以及是否保存或删除该文件。

使用以下 Azure CLI 命令 az webapp deployment github-actions remove 断开 GitHub Actions 的连接。 将任何占位符替换为特定值:

az webapp deployment github-actions remove \
  --repo "<github-username>/<github-repo>" \
  --resource-group <resource-group-name> \
  --branch <branch-name> \
  --name <app-service-name> \
  --login-with-github

清理资源

若要避免对本文中创建的 Azure 资源产生费用,请删除包含应用服务实例和应用服务计划的资源组。

在安装 Azure CLI(包括 Azure Cloud Shell)的任何位置,都可以使用 az group delete 命令删除资源组:

az group delete --name <resource-group-name>

删除存储帐户

若要删除维护 Cloud Shell 文件系统的存储帐户(每月会产生少量费用),请删除以 cloud-shell-storage 开头的资源组。 如果你是组的唯一用户,则删除资源组是安全的。 如果有其他用户,则可以删除资源组中的存储帐户。

更新 GitHub 帐户和存储库

如果删除 Azure 资源组,请考虑对已连接进行持续部署的 GitHub 帐户和存储库进行以下修改:

  • 在应用存储库中,删除 .github/workflows/<workflow-name>.yml 文件。
  • 在应用存储库设置中,删除为工作流创建的 AZUREAPPSERVICE_PUBLISHPROFILE_ 密钥。
  • 在 GitHub 帐户设置中,删除 Azure 应用服务作为 GitHub 帐户的授权 Oauth 应用。