前面我們花了好幾個篇幅將幾個不同的Job改成step和job範本,但是除了step和job可以改成範本設計之外,stage也能夠設計成範本。不過stage和job兩者設計成範本的差異並不大,主要差異如下:
- Stage預設依序執行,除非透過dependsOn指定依賴;Job則不一定會依序執行,除非透過dependsOn指定依賴。
- Stage在手動執行的畫面可以進行選擇哪些不要執行,Job則不行。
至於在指定Agent Pool的部份則是兩個都可以設定,也就是說JobA和JobB可以設定在不同條件的Agent上執行,Stage亦同。
另外,如果有付費增加平行作業(Parallel jobs)數量的話,同一個Stage內的多個Job若是沒有設定dependsOn屬性,那麼它們將可能會一起執行,視當時可用的平行作業數量而定。但是Stage因為是依序執行,前一個階段的作業都完成之後才會進入下一個階段,所以並不會有同一個Pipeline內同時執行兩個Stage的情況。
當使用的專案數量變多的時候,不同專案可能會頻繁的碰到CI/CD Pipeline等候執行的情況,這時候付費增加平行作業數量是一個緩解的方式,不過在設計Jobs的時候就需要多加留意和考量,尤其是非預期的執行順序問題。
以前面幾篇的設計來看,其實三個不同的Job都可以改成不同的Stage,並且它們都是依序執行的,順序分別是:
- Build Source Code
- Build Docker Image
- 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
更改過程中幾個要留意的點如下:
- deploy-cloudrun-stage裡面只有一個Job,就是jobs/deployCloudRun.yaml,原本有設定dependsOn屬性,改放在stage底下之後,因為前面沒有別的Job,所以要把dependsOn的設定移除。
- stage別忘了設定名稱,這樣在手動執行的時候才方便識別。
- CI Pipeline YAML內使用template的前面原本是以jobs開頭,要改為stages。