练习 - 实现蓝绿部署模式

已完成

在使用 Azure Pipelines 创建多阶段管道中,你构建了一个基本部署管道,用于在这些阶段将 Web 应用程序部署到 Azure 应用服务:开发测试和过渡

在这里,可以通过在过渡期间应用蓝绿部署模式来添加到该工作流。

为此,需要:

  • 将部署槽添加到与 暂存环境相对应的应用服务实例。
  • 向管道添加一个任务来交换部署槽位。

添加部署槽位

在这里,将部署槽添加到与 预生产相对应的应用服务实例。

默认情况下,每个应用服务实例都提供名为 生产的默认槽。 在上一部分设置管道时,你已部署到生产槽位

应用服务实例可以有多个槽位。 向与暂存相对应的应用服务实例添加第二个部署槽位。 该部署槽位被命名为“交换”

若要添加槽:

  1. 转到 Azure 门户并登录。

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

  3. 运行以下命令以获取与 暂存 对应的应用服务实例的名称,并将结果存储在命名 staging的 Bash 变量中。

    staging=$(az webapp list \
      --resource-group tailspin-space-game-rg \
      --query "[?contains(@.name, 'tailspin-space-game-web-staging')].{name: name}" \
      --output tsv)
    

    --query 参数使用 JMESPath,这是 JSON 的查询语言。 该参数选用 name 字段包含“tailspin-space-game-web-staging”的应用服务实例。

  4. 打印变量 staging 以验证是否获得正确的名称。

    echo $staging
    

    下面是输出示例:

    tailspin-space-game-web-staging-1234
    
  5. 运行以下命令,将名为 swap 的槽添加到 暂存 环境。

    az webapp deployment slot create \
      --name $staging \
      --resource-group tailspin-space-game-rg \
      --slot swap
    
  6. 运行以下命令来列出您的部署插槽的主机名。

    az webapp deployment slot list \
        --name $staging \
        --resource-group tailspin-space-game-rg \
        --query [].hostNames \
        --output tsv
    

    结果类似于以下输出:

    tailspin-space-game-web-staging-25391-swap.azurewebsites.net
    

    请记下此主机名供以后使用。

  7. 作为可选步骤,请在浏览器中转到您的网站。 你会看到默认主页,因为你尚未将代码部署到此槽。

    Azure 应用服务中默认主页的屏幕截图。

默认情况下,可从 Internet 访问部署槽位。 实际上,您可以配置一个 Azure 虚拟网络,将您的swap槽放置在一个无法从互联网路由但仅限您的团队访问的网络中。 仍可从 Internet 访问生产槽位

在过渡环境中交换部署槽位

此处使用 AzureAppServiceManage@0 任务来交换 过渡 环境中的部署槽位。

还可以使用此任务启动、停止或删除一个插槽。 或者,可以使用它来安装站点扩展或在应用服务上启用持续监视。

  1. 在 Visual Studio Code 中,使用以下代码修改 azure-pipelines.yml

    小窍门

    可以替换整个文件,也可以只更新突出显示的部分。

    trigger:
    - '*'
    
    variables:
      buildConfiguration: '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
      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: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameDev)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Test'
      displayName: 'Deploy to the test environment'
      dependsOn: Dev
      jobs:
      - deployment: Deploy
        pool:
          vmImage: 'ubuntu-20.04'
        environment: test
        variables:
        - group: 'Release'
        strategy:
          runOnce:
            deploy:
              steps:
              - download: current
                artifact: drop
              - task: AzureWebApp@1
                displayName: 'Azure App Service Deploy: website'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  appName: '$(WebAppNameTest)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
    
    - stage: 'Staging'
      displayName: 'Deploy to the staging environment'
      dependsOn: Test
      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: 'Resource Manager - Tailspin - Space Game'
                  deployToSlotOrASE: 'true'
                  resourceGroupName: 'tailspin-space-game-rg'
                  slotName: 'swap'
                  appName: '$(WebAppNameStaging)'
                  package: '$(Pipeline.Workspace)/drop/$(buildConfiguration)/*.zip'
              - task: AzureAppServiceManage@0
                displayName: 'Swap deployment slots'
                inputs:
                  azureSubscription: 'Resource Manager - Tailspin - Space Game'
                  resourceGroupName: 'tailspin-space-game-rg'
                  webAppName: '$(WebAppNameStaging)'
                  sourceSlot: 'swap'
                  targetSlot: 'production'
                  action: 'Swap Slots'
    

    请注意以下更改:

    • 现在,任务 AzureWebApp@1 指定了以下值:
      • deployToSlotOrASE 设置为 true 时,部署到现有的部署槽位。
      • resourceGroupName 指定资源组的名称。 此值在deployToSlotOrASEtrue时是必需的。
      • slotName 指定部署槽的名称。 在这里,你部署到名为“交换”的槽
    • 新任务 AzureAppServiceManage@0 交换部署槽位。
      • sourceSlottargetSlot 指定要交换的槽。
      • action 指定要执行的动作。 回忆一下,你可执行此任务来启动、停止或删除槽。 此处,“插槽交换”表示交换源槽和目标槽。

    此配置始终部署到 交换 插槽。 然后,它将 生产 槽和 备用 槽进行交换。 交换过程可确保生产槽位指向更新的部署

  2. 在集成终端中,将 azure-pipelines.yml 添加到索引。 提交更改,然后将分支推送到 GitHub。

    小窍门

    运行这些 Git 命令之前保存 azure-pipelines.yml

    git add azure-pipelines.yml
    git commit -m "Swap deployment slots"
    git push origin blue-green
    
  3. 在 Azure Pipelines 中,跟踪生成的每个步骤。

注释

如果遇到以下错误, ...'staging' slot did not respond to http ping. (CODE: 417) 请尝试重启应用服务。 如果问题仍然存在,请重置插槽的自动切换。

  1. 作为可选步骤,在浏览器中,转到对应于每个阶段的 URL。

    虽然尚未对网站进行更改,但可以看到 Space Game 网站已成功部署到每个应用服务环境。

    一张展示开发环境中 Space Game 网站的浏览器屏幕截图。