【2022鐵人賽】設計Stage範本

前面我們花了好幾個篇幅將幾個不同的Job改成step和job範本,但是除了step和job可以改成範本設計之外,stage也能夠設計成範本。不過stage和job兩者設計成範本的差異並不大,主要差異如下:

  1. Stage預設依序執行,除非透過dependsOn指定依賴;Job則不一定會依序執行,除非透過dependsOn指定依賴。
  2. Stage在手動執行的畫面可以進行選擇哪些不要執行,Job則不行。
不同Stage在手動執行時可以選擇哪些不執行

至於在指定Agent Pool的部份則是兩個都可以設定,也就是說JobA和JobB可以設定在不同條件的Agent上執行,Stage亦同。

另外,如果有付費增加平行作業(Parallel jobs)數量的話,同一個Stage內的多個Job若是沒有設定dependsOn屬性,那麼它們將可能會一起執行,視當時可用的平行作業數量而定。但是Stage因為是依序執行,前一個階段的作業都完成之後才會進入下一個階段,所以並不會有同一個Pipeline內同時執行兩個Stage的情況。

付費增加平行作業數量
平行作業價格

當使用的專案數量變多的時候,不同專案可能會頻繁的碰到CI/CD Pipeline等候執行的情況,這時候付費增加平行作業數量是一個緩解的方式,不過在設計Jobs的時候就需要多加留意和考量,尤其是非預期的執行順序問題。

以前面幾篇的設計來看,其實三個不同的Job都可以改成不同的Stage,並且它們都是依序執行的,順序分別是:

  1. Build Source Code
  2. Build Docker Image
  3. Deploy to CloudRun

所以將它們改為Stage範本也是OK的,可以每一個Job都改成各別的Stage,也可以一個Stage裡面包含一個以上的Job。

例如下面的設計:

  • dotnet-build-stage
    • dotnet-build-job
    • docker-build-job
  • deploy-cloudrun-stage
    • deploy-cloudrun-job
  • ios-build-stage
    • ios-build-job
    • publish-ipa-job

前面設計的job範本並不會因為這樣就白做工,只是我們會再增加stage的範本,然後在CI Pipeline的YAML裡面改為參考stage的範本,接下來就按照上面的例子來增加stage的範本吧!

# stages/dotnet-build-stage.yaml

parameters:
  # buildCode.yaml parameters
  - name: sourcePath
    type: string
    default: $(Build.SourcesDirectory)
  - name: slnOrCsprojName
    type: string
    default: Pipeline.sln

  # buildImage.yaml parameters
  - name: artifactName
    type: string
    default: OutputFiles
  - name: unzip
    type: boolean
    default: false
  - name: zipFileName
    type: string
    default: ''
  - name: unzipToFolderPath
    type: string
    default: ''
  - name: imgRepository
    type: string
  - name: imgTags
    type: object
  - name: buildDockerfile
    type: string
    default: Build.Dockerfile
  - name: buildContext
    type: string
  - name: containerRegistry
    type: string

stages:
- stage: BuildSourceAndImage
  displayName: 編譯程式碼和建立Docker Image
  jobs:
    - template: ../jobs/buildCode.yaml
      parameters:
        sourcePath: ${{ parameters.sourcePath }}
        slnOrCsprojName: ${{ parameters.slnOrCsprojName }}
    - template: ../jobs/buildImage.yaml
      parameters:
        artifactName: ${{ parameters.artifactName }}
        unzip: ${{ parameters.unzip }}
        zipFileName: ${{ parameters.zipFileName }}
        unzipToFolderPath: ${{ parameters.unzipToFolderPath }}
        imgRepository: ${{ parameters.imgRepository }}
        imgTags: ${{ parameters.imgTags }}
        buildDockerfile: ${{ parameters.buildDockerfile }}
        buildContext: ${{ parameters.buildContext }}
        containerRegistry: ${{ parameters.containerRegistry }}
# stages/deploy-cloudrun-stage.yaml

parameters:
  # deployCloudRun.yaml parameters
  - name: cloudRunProjectId
    type: string
  - name: imgRepository
    type: string
  - name: cloudRunRegion
    type: string
  - name: cloudRunServiceName
    type: string
  - name: templateResourceName
    type: string
    default: templates
  - name: pipelineResourceName
    type: string
    default: pipelines

stages:
- stage: DeployCloudRun
  displayName: 佈署Cloud Run
  jobs:
    - template: ../jobs/deployCloudRun.yaml
      parameters:
        cloudRunProjectId: ${{ parameters.cloudRunProjectId }}
        imgRepository: ${{ parameters.imgRepository }}
        cloudRunRegion: ${{ parameters.cloudRunRegion }}
        cloudRunServiceName: ${{ parameters.cloudRunServiceName }}
        templateResourceName: ${{ parameters.templateResourceName }}
        pipelineResourceName: ${{ parameters.pipelineResourceName }}

將stage範本完成之後,接下來就是修改CI Pipeline的YAML內容了

trigger:
- none

resources:
  repositories:
  - repository: sources
    type: git
    name: ironman2022/NetApp
    ref: Develop
    trigger:
      branches:
        include:
          - Develop
  - repository: pipelines
    type: git
    name: ironman2022/Pipelines
    ref: main
  - repository: templates
    type: git
    name: ironman2022/templates
    ref: main

variables:
  pipelineArtifact: output
  buildResultZipName: buildResult.zip
  slnOrCsprojName: IronmanWeb.sln
  imgRepository: 'asia-east1-docker.pkg.dev/feisty-mechanic-363012/ironman2022/ironmanweb'
  buildDockerfile: 'Dockerfile'
  imgRegistryService: 'GCPArtifactRegistry'
  cloudRunServiceName: ironmanweb
  cloudRunRegion: asia-east1
  cloudRunProjectId: feisty-mechanic-363012
  gcpAuthJsonFile: ironman2022-gcp-key.json


stages:
  - template: stages/dotnet-build-stage.yaml@templates
    parameters:
      sourcePath: $(Build.SourcesDirectory)
      slnOrCsprojName: $(slnOrCsprojName)
      artifactName: '$(pipelineArtifact)'
      unzip: true
      zipFileName: buildResult.zip
      unzipToFolderPath: $(System.ArtifactsDirectory)/buildImage
      imgRepository: $(imgRepository)
      imgTags: |
        latest
      buildDockerfile: $(buildDockerfile)
      buildContext: $(System.ArtifactsDirectory)/buildImage
      containerRegistry: $(imgRegistryService)
  - template: stages/deploy-cloudrun-stage.yaml@templates
    parameters:
      cloudRunProjectId: $(cloudRunProjectId)
      imgRepository: $(imgRepository)
      cloudRunRegion: $(cloudRunRegion)
      cloudRunServiceName: $(cloudRunServiceName)
      templateResourceName: templates
      pipelineResourceName: pipelines

更改過程中幾個要留意的點如下:

  1. deploy-cloudrun-stage裡面只有一個Job,就是jobs/deployCloudRun.yaml,原本有設定dependsOn屬性,改放在stage底下之後,因為前面沒有別的Job,所以要把dependsOn的設定移除。
  2. stage別忘了設定名稱,這樣在手動執行的時候才方便識別。
  3. CI Pipeline YAML內使用template的前面原本是以jobs開頭,要改為stages。

發佈留言