尝试在 Azure DevOps 上进行 CI/CD

想做的事情 zuò de

因为想要试用Azure DevOps的持续集成/持续交付,所以尝试了一下,并记录下了试用过程。由于是试用性质较强,仅供参考!

管道内容

在管道中进行的是使用Terraform对Azure资源进行管理,其配置如下所示。

overview.png

开发人员发布公关后,将触发公关用的流程,执行各种验证。然后,进行terraform plan并要求(手动)确认其内容。如果确认成功,公关流程就会成功并可进行合并。

合并后,将触发用于合并的流程,首先要求批准者批准发布,如果批准通过,则执行实际的terraform apply,这就是整个流程。

创建管道

在Azure DevOps上,有两种创建流水线的方式:经典流水线和YAML流水线。经典流水线是通过GUI进行创建,而YAML流水线则是通过YAML文件进行创建,正如其名称所示。

本次将使用其他 SCM 工具中使用的 YAML 文件进行 CI/CD 的创建。将参考以下文档进行创建。

 

在创建时,可以使用像VSCode这样的编辑器进行创建,但是在Azure DevOps上进行编辑,可以使用Intelligence功能,非常方便。

 

阶段、工作、步骤的关系

请注意,每个任务都由一个代理人执行。由于每个任务有不同的环境,因此在一个任务中安装的工具在另一个任务中无法使用。因此,需要对每个任务进行工具安装等操作。此外,基本上不能在一个任务中引用另一个任务创建的文件(如果将其视为工件可能可以实现?)。

连接到 Azure

连接到Azure需要几种方法,但本次我们将创建专用的服务主体并使用其认证信息。为了使权限范围最小化以适应用途,最好为每个存储库创建一个服务主体。

 

事先创建Azure到服务连接器,并从管道中调用其身份验证信息。

- task: AzureCLI@2
  inputs:
    azureSubscription: {YOUR_SERVICE_CONNECTION}
    scriptType: 'bash'
    scriptLocation: 'inlineScript'
    inlineScript: |
      az --version
      az account show
    addSpnToEnvironment: true

Terraform 扩展功能 (Terraform

使用Terraform时,可以选择自己编写脚本进行安装,但因为这样会比较麻烦,所以可以使用扩展功能。

 

点击「免费获取」并将其安装到存储库的组织上。
在使用时,根据以下方式调用任务并设置参数。

- task: TerraformTaskV4@4
  displayName: terraform init
  inputs:
    provider: 'azurerm'
    command: 'init'
    workingDirectory: {WORKING_DIR}
    backendServiceArm: {YOUR_SERVICE_CONNECTION}
    backendAzureRmResourceGroupName: {YOUR_RESOURCE_GROUP}
    backendAzureRmStorageAccountName: {YOUR_STORAGE_ACCOUNT}
    backendAzureRmContainerName: {YOUR_CONATINER}
    backendAzureRmKey: {YOUR_STATEFILE}

PR触发

这是最不容易理解的地方。
在 YMAL 模式中有触发器(trigger)和公共关系(pr),我最初打算使用它们,但似乎没有正常运作。经过仔细调查,发现需要在GUI设置中进行覆盖。

 

认可(验证)

当需要在某种发布时确认或需要批准内容时,可以使用手动验证和批准检查。

手动验证

 

通过使用手动验证任务,可以使后续流程能够暂停、再开始或拒绝确认。

认可检查

 

在 DevOps 上预先创建(定义)发布环境,并将该环境分配给 YAML 文件内的作业,以便在执行该作业之前需要获得批准。

PR 管道和合并管道

在 Azure DevOps 中,可以创建多个流水线,并可以将每个流水线的配置信息分别写入到不同的 YAML 文件中。
尽管可以在一个文件中触发这两个流水线,但这样会导致不易理解,所以选择将文件进行分割。

制作好的YAML文件

我创建了两个 YAML 文件,如下所示。说实话,管道的完成度不太好,只供参考!

pool: 
  vmImage: ubuntu-latest

# trigger 設定は Pull Request 時に CI を動作させるために、
# DevOps の GUI 設定で無効化している
# ファイルに残している理由:
# 1. trigger 設定を削除するとすべてのブランチへの Merge 時にトリガされてしまう
# 2. trigger: none にすると PR 時のトリガも動作しなくなってしまう
# https://zenn.dev/nuits_jp/articles/2023-07-02-azure-pipelines-pr-trigger
trigger:
  - main

stages:
- stage: Validation
  jobs:
  - job: Format
    steps:
    - task: TerraformInstaller@0
      displayName: install terraform
      inputs:
        terraformVersion: 'latest'

    - script: |
        cd infra/ && pwd
        terraform fmt -check
        if [ $? -ne 0 ]; then echo "You need to format"; exit 1; fi
      displayName: terraform fmt

  - job: Lint
    steps:
      - script: |
          curl -s https://raw.githubusercontent.com/terraform-linters/tflint/master/install_linux.sh | bash
          tflint --version
        displayName: install tflint
      - script: |
          cd infra/ && pwd
          tflint --init
          tflint
        displayName: tflint

  - job: Validate
    steps:
      - task: TerraformInstaller@0
        displayName: install terraform
        inputs:
          terraformVersion: 'latest'

      - task: TerraformTaskV4@4
        displayName: terraform init
        inputs:
          provider: 'azurerm'
          command: 'init'
          workingDirectory: {WORKING_DIR}
          backendServiceArm: {YOUR_SERVICE_CONNECTION}
          backendAzureRmResourceGroupName: {YOUR_RESOURCE_GROUP}
          backendAzureRmStorageAccountName: {YOUR_STORAGE_ACCOUNT}
          backendAzureRmContainerName: {YOUR_CONATINER}
          backendAzureRmKey: {YOUR_STATEFILE}

      - task: TerraformTaskV4@4
        displayName: terraform validate
        inputs:
          provider: 'azurerm'
          command: 'validate'
          workingDirectory: {YOUR_WORKING_DIR}

- stage: Planning
  jobs:
  - job: Plan
    steps:
    - task: TerraformInstaller@0
      displayName: install terraform
      inputs:
        terraformVersion: 'latest'

    - task: TerraformTaskV4@4
      displayName: terraform init
      inputs:
        provider: 'azurerm'
        command: 'init'
        workingDirectory: {WORKING_DIR}
        backendServiceArm: {YOUR_SERVICE_CONNECTION}
        backendAzureRmResourceGroupName: {YOUR_RESOURCE_GROUP}
        backendAzureRmStorageAccountName: {YOUR_STORAGE_ACCOUNT}
        backendAzureRmContainerName: {YOUR_CONATINER}
        backendAzureRmKey: {YOUR_STATEFILE}

    - task: TerraformTaskV4@4
      displayName: terraform plan
      inputs:
        provider: 'azurerm'
        command: 'plan'
        workingDirectory: {YOUR_WORKING_DIR}
        environmentServiceNameAzureRM: {YOUR_SERVICE_CONNECTION}

- stage: RequestManualValidation
  jobs:
  - job: ManualValidation
    pool: server
    steps:
    - task: ManualValidation@0
      displayName: check terraform plan
      timeoutInMinutes: 1440 # task times out in 1 day
      inputs:
          notifyUsers: |
              {USER_EMAIL}
          instructions: 'Please validate the build configuration and resume'
          onTimeout: 'reject'
pool: 
  vmImage: ubuntu-latest

trigger:
  branches:
    include:
      - main
  paths:
    include:
      - {TARGET_PATH}

stages:
- stage: Provisioning
  jobs:
  - deployment: Apply
    environment: Check Terraform Plan
    strategy:
      runOnce:
        deploy:
          steps:
          - checkout: self

          - task: TerraformInstaller@0
            displayName: install terraform
            inputs:
              terraformVersion: 'latest'

          - task: TerraformTaskV4@4
            displayName: terraform init
            inputs:
              provider: 'azurerm'
              command: 'init'
              workingDirectory: {WORKING_DIR}
              backendServiceArm: {YOUR_SERVICE_CONNECTION}
              backendAzureRmResourceGroupName: {YOUR_RESOURCE_GROUP}
              backendAzureRmStorageAccountName: {YOUR_STORAGE_ACCOUNT}
              backendAzureRmContainerName: {YOUR_CONATINER}
              backendAzureRmKey: {YOUR_STATEFILE}

          - task: TerraformTaskV4@4
            displayName: terraform apply
            inputs:
              provider: 'azurerm'
              command: 'apply'
              workingDirectory: {WORKING_DIR}
              environmentServiceNameAzureRM: {YOUR_SERVICE_CONNECTION}

以上就是。

广告
将在 10 秒后关闭
bannerAds