使用 Azure Pipelines 生成 Python Web 应用并将其部署到 Azure 应用服务

Azure DevOps Services

将 Azure Pipelines 用于持续集成和持续交付 (CI/CD),以生成 Python Web 应用并将其部署到 Linux 上的 Azure 应用服务。 每当有针对存储库的提交时,管道均会自动生成 Python Web 应用并将其部署到应用服务。

在本文中,学习如何:

  • 在 Azure 应用服务中创建 Web 应用。
  • 在 Azure DevOps 中创建一个项目。
  • 将 DevOps 项目连接到 Azure。
  • 创建特定于 Python 的管道。
  • 运行此管道,以在应用服务中生成应用并将其部署到 Web 应用。

先决条件

为应用代码创建存储库

https://github.com/Microsoft/python-sample-vscode-flask-tutorial 对 GitHub 帐户创建示例存储库分支。

在本地主机上,克隆 GitHub 存储库。 使用以下命令将 <repository-url> 替换为分支存储库的 URL。

git clone <repository-url>

在本地测试你的应用

在本地生成并运行应用,以确保其正常工作。

  1. 更改为已克隆的存储库文件夹。

    cd python-sample-vscode-flask-tutorial
    
  2. 生成并运行应用

    python -m venv .env
    source .env/bin/activate
    pip install --upgrade pip
    pip install -r ./requirements.txt
    export set FLASK_APP=hello_app.webapp
    python3 -m flask run
    
  3. 若要查看此应用,请打开浏览器窗口并转到 http://localhost:5000。 验证是否能看到标题 Visual Studio Flask Tutorial

  4. 完成后,关闭浏览器窗口并使用 Ctrl+C 来停止 Flask 服务器。

打开 Cloud Shell

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

  2. 通过选择门户工具栏上的“Cloud Shell”按钮来打开 Azure CLI。

    Azure 门户工具栏上的“Azure Cloud Shell”按钮的屏幕截图。

  3. Cloud Shell 显示在浏览器底部。 从下拉菜单中选择 Bash

    Azure Cloud Shell 的屏幕截图。

  4. 若要提供更多可用空间,请选择最大化按钮。

创建 Azure 应用服务 Web 应用

在 Azure 门户中,通过 Cloud Shell 来创建 Azure 应用服务 Web 应用。

提示

若要粘贴到 Cloud Shell,请使用 Ctrl+Shift+V,或者右键单击并从上下文菜单中选择粘贴

  1. 使用以下命令克隆存储库,并将 <repository-url> 替换为分支存储库的 URL。

    git clone <repository-url>
    
  2. 将目录更改为已克隆的存储库文件夹,以便 az webapp up 命令将此应用识别为 Python 应用。

    cd python-sample-vscode-flask-tutorial
    
  3. 使用 az webapp up 命令预配应用服务并执行应用的首次部署。 将 <your-web-app-name> 替换为在 Azure 中保持唯一的名称。 通常,可使用个人或公司名称以及应用标识符,例如 <your-name>-flaskpipelines。 应用 URL 将成为 <你的应用服务>.azurewebsites.net

    az webapp up --name <your-web-app-name>
    

    az webapp up 命令的 JSON 输出将显示:

    {
      "URL": <your-web-app-url>,
      "appserviceplan": <your-app-service-plan-name>,
      "location": <your-azure-location>,
      "name": <your-web-app-name>,
      "os": "Linux",
      "resourcegroup": <your-resource-group>,
      "runtime_version": "python|3.11",
      "runtime_version_detected": "-",
      "sku": <sku>,
      "src_path": <repository-source-path>
    }
    

    记下 URLruntime_version 值。 在管道 YAML 文件中使用 runtime_versionURL 为 Web 应用的 URL。 可使用它来验证应用是否正在运行。

    注意

    az webapp up 命令执行以下操作:

    • 创建一个默认的资源组

    • 创建一个默认的应用服务计划

    • 使用指定名称创建应用

    • 对当前工作目录中的所有文件进行 zip 部署,并启用生成自动化。

    • 将参数本地缓存在 .azure/config 文件中,使得以后使用项目文件夹中的 az webapp up 或其他 az webapp 命令部署时,无需再次指定它们。 默认情况下,自动使用缓存的值。

    可使用命令参数将默认操作替换为自己的值。 有关详细信息,请参阅 az webapp up

  4. python-sample-vscode-flask-tutorial 应用有一个 startup.txt 文件,其中包含针对该 Web 应用的特定启动命令。 将 Web 应用 startup-file 配置属性设为 startup.txt

    1. az webapp up 命令输出中,复制 resourcegroup 值。

    2. 使用资源组和应用名称输入以下命令。

    az webapp config set --resource-group <your-resource-group> --name <your-web-app-name> --startup-file startup.txt
    

    命令完成后,它会显示包含 Web 应用的所有配置设置的 JSON 输出。

  5. 若要查看正在运行的应用,请打开浏览器并转到 az webapp up 命令输出中显示的 URL。 如果看到一个通用页面,则请等待几秒钟以便应用服务启动,然后刷新此页面。 验证是否能看到标题 Visual Studio Flask Tutorial

创建 Azure DevOps 项目

创建一个新的 Azure DevOps 项目。

  1. 在浏览器中,转到 dev.azure.com 并登录。
  2. 选择你的组织。
  3. 通过选择新建项目创建项目(如果是在组织中创建第一个项目)来创建一个新项目。
  4. 输入项目名称
  5. 选择项目的可见性
  6. 选择创建
  1. 在浏览器中,转到 Azure DevOps Server。
  2. 选择你的集合。
  3. 通过选择新建项目创建项目(如果是在集合中创建第一个项目)来创建一个新项目。
  4. 输入项目名称
  5. 选择项目的可见性
  6. 选择创建

创建服务主体

服务主体是创建用于应用程序、托管服务和自动化工具以访问 Azure 资源的标识。 此访问权限仅限于分配给服务主体的角色,以便控制哪些资源可供访问以及在哪个级别进行访问。

若要创建服务主体,请转到 Cloud Shell (bash) 并运行以下命令。 将 <service-principal-name> 替换为服务主体的名称、将 <your-subscription-id> 替换为订阅 ID 并将 <your-resource-group> 替换为Web 应用的资源组。

az ad sp create-for-rbac --display-name <service-principal-name> --role contributor --scopes /subscriptions/<your-subscription-id>/resourceGroups/<your-resource-group>

此命令将返回类似以下示例的 JSON 对象:

{
  "clientId": "<client GUID>",
  "clientSecret": "<string-value>",
  "subscriptionId": "<subscription GUID>",
  "tenantId": "<tenant GUID>",
  ...
}

记下 clientIdclientSecretsubscriptionIdtenantId 值。 在下一节,需使用这些值来创建服务连接。

创建服务连接

服务连接允许你创建连接,以提供从 Azure Pipelines 到外部与远程服务的经过身份验证的访问权限。 若要部署到 Azure 应用服务 Web 应用,则请创建与包含该 Web 应用的资源组的服务连接。

  1. 在项目页面上,选择项目设置

    项目仪表板上“项目设置”按钮的屏幕截图。

  2. 在此菜单的管道部分,选择服务连接

  3. 选择创建服务连接

  4. 选择 Azure 资源管理器,然后选择下一步

    Azure 资源管理器服务连接选择的屏幕截图。

  5. 选择身份验证方法,然后选择下一步

  6. 新建 Azure 服务连接对话框中,输入特定于所选身份验证方法的信息。 有关身份验证方法的详细信息,请参阅使用 Azure 资源管理器服务连接以连接到 Azure

    例如,如果使用的是工作负荷标识联合(自动)服务主体(自动)身份验证方法,则请输入所需的信息。

    “新建服务连接”对话框的屏幕截图。

    字段 描述
    范围级别 选择订阅
    订阅 Azure 订阅名称。
    资源组 包含 Web 应用的资源组的名称。
    服务连接名称 此连接的描述性名称。
    向所有管道授予访问权限 选择此选项可授予对所有管道的访问权限。
  7. 选择保存

新连接将显示在服务连接列表中,且已可在 Azure Pipelines 中使用。

  1. 在项目页面上,选择项目设置

    项目仪表板上“项目设置”按钮的屏幕截图。

  2. 在此菜单的管道部分,选择服务连接

  3. 选择创建服务连接

  4. 选择 Azure 资源管理器,然后选择下一步

    Azure 资源管理器服务连接选择的屏幕截图。

  5. 新建 Azure 服务连接时,选择服务主体(手动),然后选择下一步

  6. 在下一对话框中,填写所需的信息。

    “新建服务连接”对话框的屏幕截图。

    字段 描述
    环境 选择 Azure Cloud
    范围级别 选择订阅
    订阅 ID 订阅 ID。
    订阅名称 Azure 订阅名称。
    服务主体 ID az ad sp create-for-rbac 命令所返回 JSON 对象中的 appId 值。
    服务主体密钥 az ad sp create-for-rbac 命令所返回 JSON 对象中的 password 值。
    租户 ID az ad sp create-for-rbac 命令所返回 JSON 对象中的 tenant 值。
  7. 选择验证以验证此连接。

  8. 输入服务连接名称

  9. 务必选中授予对所有管道的访问权限

  10. 选择验证并保存

新连接将显示在服务连接列表中,可供 Azure Pipelines 从项目使用。

配置自托管代理

如果使用的是自己的自托管代理,则需配置此代理以便运行 Python。 自托管代理不支持下载 Python 版本。 必须预安装 Python 版本。 使用完整的安装程序来获取与 pip 兼容的 Python 版本。

为避免出现不兼容问题,应将 Python 版本与 Azure 应用服务 Web 应用上的运行时版本进行匹配。 运行时版本会显示在 az webapp up 命令的 JSON 输出中。

需将所需的 Python 版本添加到自托管代理上的工具缓存中,以便任务可使用它。 通常,此工具缓存位于代理的 _work/_tool 目录下;或者,也可用环境变量 AGENT_TOOLSDIRECTORY 覆盖此路径。 在 tools 目录下,根据 Python 版本创建以下目录结构:

$AGENT_TOOLSDIRECTORY/
    Python/
        {version number}/
            {platform}/
                {tool files}
            {platform}.complete

版本号应遵循 1.2.3 格式。 平台应为 x86 或 x64。 工具文件应为解压缩的 Python 版本文件。 {platform}.complete 应为一个 0 字节文件,它类似 x86.completex64.complete 且仅表示该工具已正确安装在缓存中。

例如,如果使用的是 64 位 Windows 计算机上的 Python 3.11,目录结构则应如下所示:

$AGENT_TOOLSDIRECTORY/
    Python/
        3.11.4/
            x64/
                {python files}
            x64.complete

如果已在托管此代理的计算机上使用该 Python 版本,则可将这些文件复制到工具缓存。 如果没有该 Python 版本,则可从 Python 网站下载它。

创建管道

创建管道以生成 Python Web 应用并将其部署到 Azure 应用服务。 若要了解管道概念,请观看:

  1. 在左侧导航菜单中,选择管道

    项目仪表板上的“管道”选择的屏幕截图。

  2. 选择 Create Pipeline

    管道列表中的“新建管道”按钮的屏幕截图。

  3. 你的代码位于何处?对话框中,选择 GitHub。 系统可能会提示你登录 GitHub。

    选择 GitHub 以作为代码位置的屏幕截图。

  4. 选择存储库屏幕上,选择分支示例存储库。

    存储库选择的屏幕截图。

  5. 系统可能会提示再次输入 GitHub 密码以进行确认。

  6. 如果未在 GitHub 上安装 Azure Pipelines 扩展,GitHub 则会提示你安装 Azure Pipelines 扩展。

    在 GitHub 上安装 Azure Pipelines 扩展。

    在此页面上,向下滚动到存储库访问权限部分,选择是在所有存储库上安装此扩展还是仅在选定的存储库上安装此扩展,然后选择批准并安装

    GitHub 上的“批准并安装 Azure Pipelines 扩展”的屏幕截图。

  7. 配置管道对话框中,选择从 Python 到 Azure 上的 Linux Web 应用

  8. 选择 Azure 订阅,然后选择继续

  9. 如果使用的是用户名和密码进行身份验证,则会打开浏览器以便登录到 Microsoft 帐户。

  10. 从下拉列表中选择 Web 应用名称,然后选择验证并配置

Azure Pipelines 将创建 azure-pipelines.yml 文件,并将其显示在 YAML 管道编辑器中。 此管道文件将 CI/CD 管道定义为一系列阶段作业步骤,其中每个步骤均包含不同任务脚本的详细信息。 查看管道以了解其功能。 请确保所有默认输入都适用于你的代码。

  1. 在导航菜单中,选择管道

    项目仪表板上的“管道”选择的屏幕截图。

  2. 选择 Create Pipeline

    “新建管道”按钮的屏幕截图。

  3. 你的代码位于何处对话框中,选择 GitHub Enterprise Server。 系统可能会提示你登录 GitHub。

    选择 GitHub 以作为代码位置的屏幕截图。

  4. 选择存储库选项卡上,选择分支示例存储库。

    存储库选择的屏幕截图。

  5. 系统可能会提示再次输入 GitHub 密码以进行确认。

  6. 如果未在 GitHub 上安装 Azure Pipelines 扩展,GitHub 则会提示你安装 Azure Pipelines 扩展。

    GitHub 上 Azure Pipelines 扩展的屏幕截图。

    在此页面上,向下滚动到存储库访问权限部分,选择是在所有存储库上安装此扩展还是仅在选定的存储库上安装此扩展,然后选择批准并安装

    GitHub 上的“批准并安装 Azure Pipelines 扩展”的屏幕截图。

  7. 配置管道对话框中,选择入门管道

  8. azure-pipelines.yml 文件的内容替换为以下代码。

    trigger:
    - main
    
    variables:
      # Azure Resource Manager connection created during pipeline creation
      azureServiceConnectionId: '<your-service-connection-name>'
    
      # Web app name
      webAppName: '<your-web-app-name>'
    
      # Environment name
      environmentName: '<your-web-app-name>'
    
      # Project root folder. 
      projectRoot: $(System.DefaultWorkingDirectory)
    
      # Python version: 
      pythonVersion: '<your-python-version>'
    
    stages:
    - stage: Build
      displayName: Build stage
      jobs:
      - job: BuildJob
        pool:
          name: '<your-pool-name>'
          demands: python
        steps:
        - task: UsePythonVersion@0
          inputs:
            versionSpec: '$(pythonVersion)'
          displayName: 'Use Python $(pythonVersion)'
    
        - script: |
            python -m venv antenv
            source antenv/bin/activate
            python -m pip install --upgrade pip
            pip install -r requirements.txt
          workingDirectory: $(projectRoot)
          displayName: "Install requirements"
    
        - task: ArchiveFiles@2
          displayName: 'Archive files'
          inputs:
            rootFolderOrFile: '$(projectRoot)'
            includeRootFolder: false
            archiveType: zip
            archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
            replaceExistingArchive: true
    
        - task: PublishBuildArtifacts@1
          inputs:
            PathtoPublish: '$(Build.ArtifactStagingDirectory)'
            ArtifactName: 'drop'
            publishLocation: 'Container'
    
    - stage: Deploy
      displayName: 'Deploy Web App'
      dependsOn: Build
      condition: succeeded()
      jobs:
      - deployment: DeploymentJob
        pool:
          name: '<your-pool-name'
        environment: $(environmentName)
        strategy:
          runOnce:
            deploy:
              steps:
    
              - task: UsePythonVersion@0
                inputs:
                  versionSpec: '$(pythonVersion)'
                displayName: 'Use Python version'
    
              - task: AzureWebApp@1
                displayName: 'Deploy Azure Web App : <your-web-app-name>'
                inputs:
                  azureSubscription: $(azureServiceConnectionId)
                  appName: $(webAppName)
                  package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
                  startUpCommand: 'startup.txt'
    
    
  9. 将以下占位符替换为自己的值:

    占位符 描述
    <your-service-connection-name> 已创建服务连接的名称。
    <your-web-app-name> Azure 应用服务 Web 应用的名称。
    <your-pool-name> 要使用的代理池的名称。
    <your-python-version> 代理上运行的 Python 版本。 最好将此版本与 Web 应用上运行的 Python 版本进行匹配。 Web 应用版本会显示在 az webapp up 命令的 JSON 输出中。

YAML 管道文件

以下说明将介绍 YAML 管道文件。 若要了解管道 YAML 文件架构,请参阅 YAML 架构参考

完整的管道 YAML 文件示例如下所示:

trigger:
- main

variables:
  # Azure Resource Manager connection created during pipeline creation
  azureServiceConnectionId: '<GUID>'

  # Web app name
  webAppName: '<your-webapp-name>'

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

  # Environment name
  environmentName: '<your-webapp-name>'

  # Project root folder. Point to the folder containing manage.py file.
  projectRoot: $(System.DefaultWorkingDirectory)

  pythonVersion: '3.11'

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: BuildJob
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '$(pythonVersion)'
      displayName: 'Use Python $(pythonVersion)'

    - script: |
        python -m venv antenv
        source antenv/bin/activate
        python -m pip install --upgrade pip
        pip install setup
        pip install -r requirements.txt
      workingDirectory: $(projectRoot)
      displayName: "Install requirements"

    - task: ArchiveFiles@2
      displayName: 'Archive files'
      inputs:
        rootFolderOrFile: '$(projectRoot)'
        includeRootFolder: false
        archiveType: zip
        archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
        replaceExistingArchive: true

    - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
      displayName: 'Upload package'
      artifact: drop

- stage: Deploy
  displayName: 'Deploy Web App'
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeploymentJob
    pool:
      vmImage: $(vmImageName)
    environment: $(environmentName)
    strategy:
      runOnce:
        deploy:
          steps:

          - task: UsePythonVersion@0
            inputs:
              versionSpec: '$(pythonVersion)'
            displayName: 'Use Python version'

          - task: AzureWebApp@1
            displayName: 'Deploy Azure Web App : $(webAppName)'
            inputs:
              azureSubscription: $(azureServiceConnectionId)
              appName: $(webAppName)
              package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip

变量

variables 部分包含以下变量:

variables:
# Azure Resource Manager connection created during pipeline creation
azureServiceConnectionId: '<GUID>'

# Web app name
webAppName: '<your-webapp-name>'

# Agent VM image name
vmImageName: 'ubuntu-latest'

# Environment name
environmentName: '<your-webapp-name>'

# Project root folder.
projectRoot: $(System.DefaultWorkingDirectory)

# Python version: 3.11. Change this to match the Python runtime version running on your web app.
pythonVersion: '3.11'

变量 描述
azureServiceConnectionId Azure 资源管理器服务连接的 ID 或名称。
webAppName Azure 应用服务 Web 应用的名称。
vmImageName 要用于生成代理的操作系统的名称。
environmentName 在部署阶段中使用的环境的名称。 运行此阶段作业时,会自动创建环境。
projectRoot 包含应用代码的根文件夹。
pythonVersion 要在生成与部署代理上使用的 Python 版本。

variables 部分包含以下变量:

variables:
# Azure Resource Manager connection created during pipeline creation
azureServiceConnectionId: '<your-service-connection-name>'

# Web app name
webAppName: '<your-webapp-name>'

# Environment name
environmentName: '<your-webapp-name>'

# Project root folder. 
projectRoot: $(System.DefaultWorkingDirectory)

# Python version: 3.11. Change this to the version that is running on your agent and web app.
pythonVersion: '3.11'
变量 描述
azureServiceConnectionId Azure 资源管理器服务连接的名称。
webAppName Web 应用的名称。
environmentName 在部署阶段中使用的环境的名称。
projectRoot 包含应用代码的文件夹。 该值为自动系统变量。
pythonVersion 要在生成与部署代理上使用的 Python 版本。

生成阶段

生成阶段包含在 vmImageName 变量中定义的且运行于操作系统上的单个作业。

  - job: BuildJob
    pool:
      vmImage: $(vmImageName)

生成阶段包含一个作业,而该作业会在名称参数所标识的池中的某一代理上运行。 可使用 demands 关键字指定代理功能。 例如,demands: python 指定代理必须已安装 Python。 若要按名称指定自托管代理,可使用 demands: Agent.Name -equals <agent-name> 关键字。

  - job: BuildJob
    pool:
      name: <your-pool-name>
      demands: python

此作业包含多个步骤:

  1. UsePythonVersion 任务可选择要使用的 Python 版本。 此版本会在 pythonVersion 变量中定义。

       - task: UsePythonVersion@0
          inputs:
            versionSpec: '$(pythonVersion)'
            displayName: 'Use Python $(pythonVersion)'
    
  2. 此步骤使用脚本创建虚拟 Python 环境,并安装参数中包含的requirements.txtworkingDirectory应用依赖项,指定应用代码的位置。

      - script: |
           python -m venv antenv
           source antenv/bin/activate
           python -m pip install --upgrade pip
           pip install setup
           pip install  -r ./requirements.txt
         workingDirectory: $(projectRoot)
         displayName: "Install requirements"
    
  3. ArchiveFiles 任务可创建包含 Web 应用的 .zip 存档。 .zip 文件将作为名为 drop 的项目而上传到管道中。 .zip 文件会在部署阶段用于将此应用部署到 Web 应用。

       - task: ArchiveFiles@2
         displayName: 'Archive files'
         inputs:
           rootFolderOrFile: '$(projectRoot)'
           includeRootFolder: false
           archiveType: zip
           archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
           replaceExistingArchive: true
    
       - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
         displayName: 'Upload package'
         artifact: drop
    
    参数 描述
    rootFolderOrFile 应用代码的位置。
    includeRootFolder 表示是否要在 .zip 文件中包含根文件夹。 将此参数设为 false;否则,.zip 文件的内容会放入名为 s 的文件夹中,而 Linux 容器上的应用服务无法找到该应用代码。
    archiveType 要创建的存档的类型。 设置为 zip
    archiveFile 要创建的 .zip 文件的所在位置。
    replaceExistingArchive 表示当此文件已存在时是否替换现有存档。 设置为 true
    upload 要上传的 .zip 文件的所在位置。
    artifact 要创建的项目的名称。

部署阶段

如果生成阶段成功完成,则会运行部署阶段。 以下关键字可定义此行为:

  dependsOn: Build
  condition: succeeded()

部署阶段包含使用以下关键字所配置的单个部署作业:

  - deployment: DeploymentJob
    pool:
      vmImage: $(vmImageName)
    environment: $(environmentName)
关键字 描述
deployment 表示该作业是面向某一环境部署作业
pool 指定部署代理池。 如果未指定此名称,则为默认代理池。 vmImage 关键字可标识代理的虚拟机映像的对应操作系统
environment 指定要部署到的环境。 此运行作业时,会自动在项目中创建环境。
  - deployment: DeploymentJob
    pool:
      name: <your-pool-name>
    environment: $(environmentName)
关键字 描述
deployment 表示该作业是面向某一环境部署作业
pool 可指定要用于部署的代理池。 该池必须包含一个代理,且该代理可运行管道中指定的 Python 版本。
environment 指定要部署到的环境。 此运行作业时,会自动在项目中创建环境。

strategy 关键字可用于定义部署策略。 runOnce 关键字可指定该部署作业仅运行一次。 deploy 关键字可指定要在部署作业中运行的步骤。

  strategy:
    runOnce:
      deploy:
        steps:

管道中的 steps 为:

  1. 使用 UsePythonVersion 任务来指定要在代理上使用的 Python 版本。 此版本会在 pythonVersion 变量中定义。

     - task: UsePythonVersion@0
       inputs:
         versionSpec: '$(pythonVersion)'
       displayName: 'Use Python version'
    
  2. 使用 AzureWebApp@1 来部署 Web 应用。 此任务会将管道项目 drop 部署到 Web 应用。

    - task: AzureWebApp@1
       displayName: 'Deploy Azure Web App : <your-web-app-name>'
       inputs:
          azureSubscription: $(azureServiceConnectionId)
          appName: $(webAppName)
          package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
    
    参数 描述
    azureSubscription 要使用的 Azure 资源管理器服务连接 ID 或名称。
    appName Web 应用的名称。
    package 要部署的 .zip 文件的所在位置。

    此外,由于 python-vscode-flask-tutorial 存储库在名为 startup.txt 的文件中包含同一启动命令,因此可通过添加参数 startUpCommand: 'startup.txt' 来指定该文件。

管道中的 steps 为:

  1. 使用 UsePythonVersion 任务来指定要在代理上使用的 Python 版本。 此版本会在 pythonVersion 变量中定义。

     - task: UsePythonVersion@0
       inputs:
         versionSpec: '$(pythonVersion)'
       displayName: 'Use Python version'
    
  2. 使用 AzureWebApp@1 来部署 Web 应用。 此任务会将管道项目 drop 部署到 Web 应用。

    - task: AzureWebApp@1
       displayName: 'Deploy Azure Web App : <your-web-app-name>'
       inputs:
          azureSubscription: $(azureServiceConnectionId)
          appName: $(webAppName)
          package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
    
    参数 描述
    azureSubscription 要使用的 Azure 资源管理器服务连接 ID 或名称。
    appName Web 应用的名称。
    package 要部署的 .zip 文件的所在位置。

    此外,由于 python-vscode-flask-tutorial 存储库在名为 startup.txt 的文件中包含同一启动命令,因此可通过添加参数 startUpCommand: 'startup.txt' 来指定该文件。

      - task: AzureWebApp@1
         displayName: 'Deploy Azure Web App : $(webAppName)'
         inputs:
           azureSubscription: $(azureServiceConnectionId)
           appName: $(webAppName)
           package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
           startUpCommand: 'startup.txt'
    
    参数 描述
    azureSubscription 要使用的 Azure 资源管理器服务连接 ID 或名称。
    appName Web 应用的名称。
    package 要部署的 .zip 文件的所在位置。
    startUpCommand 部署应用后要运行的命令。 此示例应用使用 startup.txt

运行管道

你现在可以试用了!

  1. 在编辑器中,选择保存并运行

  2. 保存并运行对话框中,添加提交消息,然后选择保存并运行

    可通过在管道运行摘要中选择“阶段”或“作业”来监视运行中的管道。

    “管道运行摘要阶段”部分的屏幕截图。

    每个成功完成的阶段和作业旁均有绿色复选标记。 如果出现错误,它们则会显示在摘要或作业步骤中。

    管道阶段步骤的屏幕截图。

    通过选择摘要页面右上方的垂直点并选择编辑管道,可快速返回到 YAML 编辑器:

    生成报表中编辑管道注释的屏幕截图。

  3. 在部署作业中,选择部署 Azure Web 应用任务可显示其输出。 若要访问已部署的站点,请按住 Ctrl 键并选择 App Service Application URL 之后的 URL。

    如果使用的是示例应用,则该应用应显示如下内容:

    一个屏幕截图,其中显示了应用服务上运行的示例应用的视图。

重要

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

az webapp up 命令专门将生成操作 SCM_DO_BUILD_DURING_DEPLOYMENT 设置为 true。 如果已通过门户预配应用服务,则不会自动设置此操作。

以下步骤用于设置操作:

  1. 打开 Azure 门户,选择“应用服务”,然后选择配置
  2. 应用程序设置选项卡下,选择新建应用程序设置
  3. 在显示的弹出窗口中,将名称设置为 SCM_DO_BUILD_DURING_DEPLOYMENT,将设置为 true,然后选择确定
  4. 选择配置页顶部的保存
  5. 再次运行管道。 应在部署期间安装依赖项。

触发管道运行

若要触发管道运行,请将某一更改提交到此存储库。 例如,可向该应用添加新功能,或更新该应用的依赖项。

  1. 转到 GitHub 存储库。
  2. 更改代码,例如更改此应用的标题。
  3. 将此更改提交到存储库。
  4. 转到管道并验证是否已创建新运行。
  5. 运行完成后,验证新生成是否已部署到 Web 应用。
    1. 在 Azure 门户中,转到自己的 Web 应用。
    2. 选择部署中心,然后选择日志选项卡。
    3. 验证是否已列出新部署。

Django 的注意事项

如果使用的是单独的数据库,则可使用 Azure Pipelines 将 Django 应用部署到 Linux 上的 Azure 应用服务。 不能使用 SQLite 数据库,因为应用服务会锁定 db.sqlite3 文件,从而阻止读取和写入。 此行为不会影响外部数据库。

在应用服务上配置 Python 应用 - 容器启动过程中所述,应用服务在应用代码中自动查找 wsgi.py 文件,该文件通常包含应用对象。 如果你要以任何方式自定义启动命令,请在 YAML 管道文件的 AzureWebApp@1 步骤中使用 startUpCommand 参数,如上一部分所述。

使用 Django 时,通常需要在部署应用代码后使用 manage.py migrate 迁移数据模型。 为此,可使用部署后脚本添加 startUpCommand。 例如,下面是 AzureWebApp@1 任务中的 startUpCommand 属性。

  - task: AzureWebApp@1
      displayName: 'Deploy Azure Web App : $(webAppName)'
      inputs:
        azureSubscription: $(azureServiceConnectionId)
        appName: $(webAppName)
        package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip
        startUpCommand: 'python manage.py migrate'

在生成代理上运行测试

生成过程中,你可能想对应用代码运行测试。 由于测试会在生成代理上运行,因此需将依赖项安装到生成代理的虚拟环境中。 测试运行后,请先删除虚拟环境,然后再创建用于部署的 .zip 文件。 以下脚本元素演示了此过程。 将它们放在 azure-pipelines.yml 文件中的 ArchiveFiles@2 任务之前。 有关详细信息,请参阅运行跨平台脚本

# The | symbol is a continuation character, indicating a multi-line script.
# A single-line script can immediately follow "- script:".
- script: |
    python -m venv .env
    source .env/bin/activate
    pip install setuptools
    pip install -r requirements.txt

  # The displayName shows in the pipeline UI when a build runs
  displayName: 'Install dependencies on build agent'

- script: |
    # Put commands to run tests here
    displayName: 'Run tests'

- script: |
    echo Deleting .env
    deactivate
    rm -rf .env
  displayName: 'Remove .env before zip'

此外,还可使用 PublishTestResults@2 等任务将测试结果发布到管道。 有关详细信息,请参阅生成 Python 应用 - 运行测试

清理资源

为避免在本教程中创建的 Azure 资源产生费用,请执行以下操作:

  • 删除所创建的项目。 删除此项目会同时删除管道和服务连接。

  • 删除包含应用服务和应用服务计划的 Azure 资源组。 在 Azure 门户中,转到资源组,选择删除资源组,然后按提示进行操作。

  • 删除用于维护 Cloud Shell 的文件系统的存储帐户。 关闭 Cloud Shell,然后转到以 cloud-shell-storage- 开头的资源组,选择删除资源组,然后按提示进行操作。

后续步骤