教程:使用 Azure DevOps 创建多阶段管道

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

可以使用 Azure DevOps 多阶段管道将 CI/CD 过程划分为表示开发周期不同部分的多个阶段。 使用多阶段管道可以更深入地了解部署过程,并且更轻松地集成审批和检查

在本文中,你将创建两个应用服务实例,并生成包含三个阶段的 YAML 管道:

在实际方案中,可能还有另一个阶段用于部署到生产环境,具体取决于 DevOps 过程。

本练习中的示例代码是一项模拟太空游戏的 .NET Web 应用程序,其中包含用于显示高分的排行榜。 你将部署到适用于 Linux 的 Azure Web 应用的开发和过渡实例。

先决条件

为项目创建分支

在 GitHub 上创建以下示例存储库的分支。

https://github.com/MicrosoftDocs/mslearn-tailspin-spacegame-web-deploy

创建服务实例实例

在部署管道之前,需要先创建要部署到的应用服务实例。 你将使用 Azure CLI 创建实例。

  1. 登录到 Azure 门户

  2. 从菜单中选择“Cloud Shell”和“Bash”体验。

  3. 生成一个使 Web 应用域名唯一的随机数。 具有唯一值的优点是应用服务实例不会与要完成本教程的其他学习者发生名称冲突。

    webappsuffix=$RANDOM    
    
  4. 打开命令提示符,并使用az group create命令创建名为tailspin-space-game-rg的资源组,其中包含你的所有应用服务实例。 更新location值以使用最近的区域。

    az group create --location eastus --name tailspin-space-game-rg
    
  5. 使用命令提示符创建应用服务计划。

    az appservice plan create \
      --name tailspin-space-game-asp \
      --resource-group tailspin-space-game-rg \
      --sku B1 \
      --is-linux
    
  6. 在命令提示符下,使用az webapp create命令创建两个应用服务实例,每个实例(开发和过渡)各一个。

    az webapp create \
      --name tailspin-space-game-web-dev-$webappsuffix \
      --resource-group tailspin-space-game-rg \
      --plan tailspin-space-game-asp \
      --runtime "DOTNET|6.0"
    
    az webapp create \
      --name tailspin-space-game-web-staging-$webappsuffix \
      --resource-group tailspin-space-game-rg \
      --plan tailspin-space-game-asp \
      --runtime "DOTNET|6.0"
    
  7. 使用命令提示符,通过az webapp list命令列出两个应用服务实例,验证它们是否正在运行。

    az webapp list \
      --resource-group tailspin-space-game-rg \
      --query "[].{hostName: defaultHostName, state: state}" \
      --output table
    
  8. 复制应用服务实例的名称,用作下一部分中的变量。

创建 Azure DevOps 项目和变量

设置 Azure DevOps 项目和生成管道。 你还将为开发和过渡实例添加变量。

你的生成管道:

  • 包含一个触发器,该触发器在分支代码发生更改时运行
  • 定义两个变量,buildConfigurationreleaseBranchName
  • 包含一个名为 Build 的阶段,该阶段生成 Web 应用程序
  • 发布稍后阶段要使用的项目

添加生成阶段

  1. 登录到你的 Azure DevOps 组织,并转到你的项目。

  2. 转到“管道”,然后选择“新建管道”或是“创建管道”(如果是首次创建管道)。

  3. 完成向导中的各个步骤。首先选择 GitHub 作为源代码位置。

  4. 可能会重定向到 GitHub 进行登录。 如果是这样,请输入 GitHub 凭据。

  5. 看到存储库列表时,请选择你的存储库。

  6. 你可能会被重定向到 GitHub 来安装 Azure Pipelines 应用。 如果是,请选择批准并安装

  1. 出现“配置”选项卡时,选择“初学者管道”。

  2. 用以下代码替换 azure-pipelines.yml 的内容。

    trigger:
    - '*'
    
    variables:
      buildConfiguration: 'Release'
      releaseBranchName: 'release'
    
    stages:
    - stage: 'Build'
      displayName: 'Build the web application'
      jobs: 
      - job: 'Build'
        displayName: 'Build job'
        pool:
          vmImage: 'ubuntu-20.04'
          demands:
          - npm
    
        variables:
          wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
          dotnetSdkVersion: '6.x'
    
        steps:
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
    
        - task: Npm@1
          displayName: 'Run npm install'
          inputs:
            verbose: false
    
        - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
          displayName: 'Compile Sass assets'
    
        - task: gulp@1
          displayName: 'Run gulp tasks'
    
        - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
          displayName: 'Write build info'
          workingDirectory: $(wwwrootDir)
    
        - task: DotNetCoreCLI@2
          displayName: 'Restore project dependencies'
          inputs:
            command: 'restore'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--no-restore --configuration $(buildConfiguration)'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true
    
        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
    
  3. 准备就绪后,选择“保存并运行”。

添加实例变量

  1. 在 Azure DevOps 中,转到“管道”>“库”。

  2. 选择“+ Variable group”。

  3. 在“属性”下,为变量组名称添加“Release”。

  4. 创建两个变量来引用开发和过渡主机名。 将1234变量替换为实例的正确值。

    变量名称 示例值
    WebAppNameDev tailspin-space-game-web-dev-1234
    WebAppNameTest tailspin-space-game-web-test-1234
  5. 选择“保存”以保存变量。

添加“开发”阶段

接下来,更新管道,将 Build 提升到 Dev 阶段。

  1. 在 Azure Pipelines 中,转到“管道”>“管道”。

  2. 在上下文菜单中选择“编辑”以编辑管道。

    选择“编辑”菜单项的屏幕截图。

  3. 更新 azure-pipelines.yml 以包含 Dev 阶段。 在 Dev 阶段,管道将执行以下操作:

    • 在 Build 阶段由于某个条件而成功时运行

    • drop 下载项目

    • 使用 Azure 资源管理器服务连接部署到 Azure 应用服务

      trigger:
      - '*'
      
      variables:
        buildConfiguration: 'Release'
        releaseBranchName: 'release'
      
      stages:
      - stage: 'Build'
        displayName: 'Build the web application'
        jobs: 
        - job: 'Build'
          displayName: 'Build job'
          pool:
            vmImage: 'ubuntu-20.04'
            demands:
            - npm
      
          variables:
            wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
            dotnetSdkVersion: '6.x'
      
          steps:
          - task: UseDotNet@2
            displayName: 'Use .NET SDK $(dotnetSdkVersion)'
            inputs:
              version: '$(dotnetSdkVersion)'
      
          - task: Npm@1
            displayName: 'Run npm install'
            inputs:
              verbose: false
      
          - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
            displayName: 'Compile Sass assets'
      
          - task: gulp@1
            displayName: 'Run gulp tasks'
      
          - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
            displayName: 'Write build info'
            workingDirectory: $(wwwrootDir)
      
          - task: DotNetCoreCLI@2
            displayName: 'Restore project dependencies'
            inputs:
              command: 'restore'
              projects: '**/*.csproj'
      
          - task: DotNetCoreCLI@2
            displayName: 'Build the project - $(buildConfiguration)'
            inputs:
              command: 'build'
              arguments: '--no-restore --configuration $(buildConfiguration)'
              projects: '**/*.csproj'
      
          - task: DotNetCoreCLI@2
            displayName: 'Publish the project - $(buildConfiguration)'
            inputs:
              command: 'publish'
              projects: '**/*.csproj'
              publishWebProjects: false
              arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
              zipAfterPublish: true
      
          - publish: '$(Build.ArtifactStagingDirectory)'
            artifact: drop
      
      - stage: 'Dev'
        displayName: 'Deploy to the dev environment'
        dependsOn: Build
        condition:  succeeded()
        jobs:
        - deployment: Deploy
          pool:
            vmImage: 'ubuntu-20.04'
          environment: dev
          variables:
          - group: Release
          strategy:
            runOnce:
              deploy:
                steps:
                - download: current
                  artifact: drop
                - task: AzureWebApp@1
                  displayName: 'Azure App Service Deploy: website'
                  inputs:
                    azureSubscription: 'your-subscription'
                    appType: 'webAppLinux'
                    appName: '$(WebAppNameDev)'
                    package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
      
  4. AzureWebApp@1 任务更改为使用订阅。

    1. 为任务选择“设置”。

      YAML 编辑器任务中的“设置”选项的屏幕截图。

    2. your-subscription更新 Azure 订阅的值以使用你自己的订阅。 在此过程中,可能需要授予访问权限。 如果在 YAML 编辑器中授权资源时遇到问题,另一种方法是创建服务连接

      “Azure 订阅”菜单项的屏幕截图。

    3. 在 Linux 上,将“应用类型”设置为“Web 应用”。

    4. 选择“添加”以更新任务。

  5. 保存并运行管道。

添加“过渡”阶段

最后,将 Dev 阶段提升为 Staging。 与 Dev 环境不同,你希望在过渡环境中拥有更多的控制权,你将添加手动审批。

创建过渡环境

  1. 在 Azure Pipelines 中,选择“Environments”。

  2. 选择“新建环境”。

  3. 创建名为 Staging 且“资源”设置为“无”的新环境。

  4. 在过渡环境页面上,然后选择“审批和检查”。

    “审批和检查”菜单选项的屏幕截图。

  5. 选择“审批”。

  6. 在“审批者”下,选择“添加用户和组”,然后选择你的帐户。

  7. 在“审批者说明”下,写下“在准备好进行过渡时批准此更改”。

  8. 选择“保存” 。

向管道中添加新阶段

你将向管道中添加一个包含手动审批的新阶段 Staging

  1. 编辑管道文件并添加 Staging 部分。

    trigger:
    - '*'
    
    variables:
      buildConfiguration: 'Release'
      releaseBranchName: 'release'
    
    stages:
    - stage: 'Build'
      displayName: 'Build the web application'
      jobs: 
      - job: 'Build'
        displayName: 'Build job'
        pool:
          vmImage: 'ubuntu-20.04'
          demands:
          - npm
    
        variables:
          wwwrootDir: 'Tailspin.SpaceGame.Web/wwwroot'
          dotnetSdkVersion: '6.x'
    
        steps:
        - task: UseDotNet@2
          displayName: 'Use .NET SDK $(dotnetSdkVersion)'
          inputs:
            version: '$(dotnetSdkVersion)'
    
        - task: Npm@1
          displayName: 'Run npm install'
          inputs:
            verbose: false
    
        - script: './node_modules/.bin/node-sass $(wwwrootDir) --output $(wwwrootDir)'
          displayName: 'Compile Sass assets'
    
        - task: gulp@1
          displayName: 'Run gulp tasks'
    
        - script: 'echo "$(Build.DefinitionName), $(Build.BuildId), $(Build.BuildNumber)" > buildinfo.txt'
          displayName: 'Write build info'
          workingDirectory: $(wwwrootDir)
    
        - task: DotNetCoreCLI@2
          displayName: 'Restore project dependencies'
          inputs:
            command: 'restore'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Build the project - $(buildConfiguration)'
          inputs:
            command: 'build'
            arguments: '--no-restore --configuration $(buildConfiguration)'
            projects: '**/*.csproj'
    
        - task: DotNetCoreCLI@2
          displayName: 'Publish the project - $(buildConfiguration)'
          inputs:
            command: 'publish'
            projects: '**/*.csproj'
            publishWebProjects: false
            arguments: '--no-build --configuration $(buildConfiguration) --output $(Build.ArtifactStagingDirectory)/$(buildConfiguration)'
            zipAfterPublish: true
    
        - publish: '$(Build.ArtifactStagingDirectory)'
          artifact: drop
    
    - stage: 'Dev'
      displayName: 'Deploy to the dev environment'
      dependsOn: Build
      condition:  succeeded()
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: dev
        variables:
        - group: Release
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'your-subscription'
                  appType: 'webAppLinux'
                  appName: '$(WebAppNameDev)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Staging'
      displayName: 'Deploy to the staging environment'
      dependsOn: Dev
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: staging
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'your-subscription'
                  appType: 'webAppLinux'
                  appName: '$(WebAppNameDev)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
  2. 将 Staging 阶段中的 AzureWebApp@1 任务更改为使用订阅。

    1. 为任务选择“设置”。

      YAML 编辑器任务中的“设置”选项的屏幕截图。

    2. your-subscription更新 Azure 订阅的值以使用你自己的订阅。 在此过程中,可能需要授予访问权限。

      “Azure 订阅”菜单项的屏幕截图。

    3. 在 Linux 上,将“应用类型”设置为“Web 应用”。

    4. 选择“添加”以更新任务。

  3. 转到管道运行。 管道运行时观察 Build 阶段的变化情况。 当它到达 Staging 时,管道将等待手动发布审批。 你还会收到一封电子邮件,指出你有一个等待审批的管道。

    等待管道审批的屏幕截图。

  4. 查看审批并允许管道运行。

    手动验证检查的屏幕截图。

清理资源

如果不打算继续使用此应用程序,请通过以下步骤删除 Azure 门户中的资源组和 Azure DevOps 中的项目:

若要清理资源组:

  1. 转到 Azure 门户并登录。

  2. 从菜单栏中选择 Cloud Shell。 出现提示时,选择“Bash”体验。

    显示选择 Cloud Shell 菜单项的 Azure 门户屏幕截图。

  3. 运行以下 az group delete 命令,以删除所使用的资源组 tailspin-space-game-rg

    az group delete --name tailspin-space-game-rg
    

要删除 Azure DevOps 项目(包括生成管道),请执行以下操作:

  1. 在 Azure DevOps 中,导航到你的项目。

  2. 选择“Project settings”。

  3. 在“项目详细信息”中,选择“删除”。