iT邦幫忙

2022 iThome 鐵人賽

DAY 19
0
DevOps

Azure DevOps進階應用系列 第 19

【Azure DevOps進階應用】CloudRun環境變數檔與多個Git Repo

  • 分享至 

  • xImage
  •  

前面的BuildCode、BuildImage兩個Job都已經拆解成job template了,最後就剩下DeployCloudRun這個Job,不過裡面只有一個task,倒是也沒什麼好拆解的,而且我們是利用script的方式跑docker container在裡面執行gcloud sdk的指令,所以也沒什麼再拆細成為step template的必要。

雖然沒有要拆細到steps的範本,不過job template還是ok的。

先前我們在gcloud指令中設定了一個環境變數為Ironman,不過若是有多個環境變數會讓指令變得很長,如果寫在檔案裡面就會方便許多,這部份在官方文件的可用參數列表當中可以查得到。我們原本使用的是–-set-env-vars來設定環境變數,但是如果是要改用檔案的方式來設定的話,則是改成使用–-env-vars-file來給它檔案路徑。

說到檔案,就必須好好正視這個問題了。

我們將Pipeline的YAML檔案拆解為不同的範本,其實很大一個目的是希望讓多個不同的專案共用範本的YAML檔案,也就是說範本的檔案可能會存在名為「DevOps」這個Azure DevOps專案中的「templates」Git Repository,之後其它的A、B、C專案可能都會有自己的一個「Pipelines」Git Repository,用來存放各別專案的Pipeline YAML檔案,以及一些專案使用的設定檔。

那麼,我們前面使用到的檔案像是GCP的身份驗證json檔,或是上面提到的CloudRun的環境變數設定檔共通的部份,這些比較好的放置地就是「templates」這個Git Repository,其它專案可能也會需要設定特有的CloudRun環境變數,這時候檔案應該是放在各別專案內的「Pipelines」Git Repository。

所以,有一些Job裡面的內容可能就會需要針對不同的情況取得「templates」和「Pipelines」以及Source code存放的Git Repository裡面的檔案,這時候就需要在Job裡面使用checkout關鍵字來分別取得不同Repository的檔案,而這些Repository就是定義在resources底下的內容(前面用過囉)。

說了那麼多,還是直接看YAML內容會比較容易理解吧?同樣把修改前和修改後的內容都貼上來方便對照。

DeployCloudRun Job

  - job: DeployCloudRun
    dependsOn: BuildImage
    steps:
      - task: Bash@3
        displayName: Deploy docker image to cloudrun
        inputs:
          targetType: 'inline'
          script: |
            docker run --rm \
            -v $(Build.SourcesDirectory)/$(gcpAuthJsonFile):/gcp/cloudKey.json \
            asia.gcr.io/google.com/cloudsdktool/google-cloud-cli:latest \
            bash -c "gcloud auth login --cred-file=/gcp/cloudKey.json && gcloud run deploy $(cloudRunServiceName) --set-env-vars=Ironman=$(Build.BuildId) --image $(imgRepository) --region $(cloudRunRegion) --project $(cloudRunProjectId) --allow-unauthenticated"
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

jobs:
  - job: DeployCloudRun
    dependsOn: BuildImage
    steps:
      - script: |    
          echo '${{ convertToJson(parameters) }}' >> parameters.json
          cat parameters.json
        displayName: Print template parameters
      - checkout: ${{ parameters.templateResourceName }}
        path: ${{ parameters.templateResourceName }}
        clean: true
      - checkout: ${{ parameters.pipelineResourceName }}
        path: ${{ parameters.pipelineResourceName }}
        clean: true
      - template: ../steps/merge-cloudRun-envVars.yaml
        parameters:
          templateResourceName: ${{ parameters.templateResourceName }}
          pipelineResourceName: ${{ parameters.pipelineResourceName }}
          projectEnvVarsFile: variables/cloudrun-envVars.yaml
          sharedEnvVarsFile: variables/cloudrun-envVars.yaml
          mergedNewFileFullPath: $(Agent.BuildDirectory)/mergedEnvVars.yaml
      - task: Bash@3
        displayName: Deploy docker image to cloudrun
        inputs:
          targetType: 'inline'
          script: |
            docker run --rm \
            -v $(Agent.BuildDirectory)/${{ parameters.templateResourceName }}/ironman2022-gcp-key.json:/gcp/cloudKey.json \
            -v $(Agent.BuildDirectory)/mergedEnvVars.yaml:/gcp/env-vars.yaml \
            asia.gcr.io/google.com/cloudsdktool/google-cloud-cli:latest \
            bash -c "gcloud auth login --cred-file=/gcp/cloudKey.json && gcloud run deploy ${{ parameters.cloudRunServiceName }} --env-vars-file /gcp/env-vars.yaml --image ${{ parameters.imgRepository }} --region ${{ parameters.cloudRunRegion }} --project ${{ parameters.cloudRunProjectId }} --allow-unauthenticated"

從修改後的YAML內容來看,是不是好像比預期的內容多了一些?

前面幾個參數是deploy cloudrun使用的,後面的templateResourceName、pipelineResourceName則是希望使用到範本的Pipeline可以告知在Pipeline YAML的resources底下的repository定義的名稱是什麼,這樣才可以在範本裡面正確的checkout,並且這個名稱也會被用在path的部份。

convertToJson印出參數內容

在修改後的YAML內容中我增加了一個script,在前面文章的內容都沒有出現過,但是其實它對於在設計YAML範本是一個滿有用的小技巧,就是在Pipeline執行時可以在Logs輸出我們所設定的參數內容,方便查看該次執行的時候使用的參數內容是什麼。(參考官方文件)

合併不同的環境變數檔案內容

除了上面多增加的script之外,其實在這裡雖然沒有將使用gcloud的script改為step範本,但是多做了一個合併環境變數檔案內容的step範本,YAML內容如下:

# steps/merge-cloudRun-envVars.yaml

parameters:
  - name: templateResourceName
    type: string
  - name: pipelineResourceName
    type: string

  - name: projectEnvVarsFile
    type: string
  - name: sharedEnvVarsFile
    type: string

  - name: mergedNewFileFullPath
    type: string

steps:
  - script: |
      if [ -f "$(Agent.BuildDirectory)/${{ parameters.pipelineResourceName }}/${{ parameters.projectEnvVarsFile }}" ]; then
        cat \
        $(Agent.BuildDirectory)/${{ parameters.pipelineResourceName }}/${{ parameters.projectEnvVarsFile }} \
        $(Agent.BuildDirectory)/${{ parameters.templateResourceName }}/${{ parameters.sharedEnvVarsFile }} >> \
        ${{ parameters.mergedNewFileFullPath }};
      else
        cat \
        $(Agent.BuildDirectory)/${{ parameters.templateResourceName }}/${{ parameters.sharedEnvVarsFile }} >> \
        ${{ parameters.mergedNewFileFullPath }};
      fi
    displayName: merge env vars files

這邊的設計是假設在template和專案的pipelines兩個Git Repository都有在固定的位置放指定檔名的檔案(variables/cloudrun-envVars.yaml),合併之後將它mapping到container裡面提供給gcloud設定環境變數檔案路徑使用,這樣我們就可以將共用的設定內容放在template的Git Repository裡面,專案額外要設定的則放在它自己pipelines的Git Repository裡面。

最後就是GCP用的身份驗證檔案,因為已經改放在template的Git Repository裡面,所以就不需要再從外部傳入檔名,所以直接把檔名寫在YAML內容中。

最後,下面這個是CI Pipeline將三個Job都改用template之後的內容:

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


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

下面的截圖是convertToJson印出參數的範例:

https://ithelp.ithome.com.tw/upload/images/20221004/20033961OPaXY7iH0v.png

對了,CloudRun的環境變數檔案內容的格式是每一行一個環境變數設定,key跟value之間使用一個半形冒號和一個空白字元相隔,跟YAML的設定方式一樣。


上一篇
【Azure DevOps進階應用】拆解BuildImage Job成為job範本
下一篇
【Azure DevOps進階應用】設計Stage範本
系列文
Azure DevOps進階應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言