ハードコーディングされた値は死すべし!! ということで Azure DevOps の Pipelines で変数使っていこうと思います。
ハローワールド
何事もハローワルドから。variables で変数を定義できます。定義した変数は $(変数名)
で参照できます。ということでさくっと以下のようはパイプラインの yaml を作ってみました。後々の確認のために特に必要はないのですが stage から定義しています。
trigger: - master variables: var1: Hello var2: World pool: vmImage: 'ubuntu-latest' stages: - stage: build displayName: build jobs: - job: test1 steps: - pwsh: | Write-Host '$(var1)' Write-Host '$(var2)'
pwsh
タスクで定義した変数を参照しています。このパイプラインが実行されると以下のように表示されます。
Hello World
いい感じ。
その他にも ${{ xxx }}
のように書いて実行時じゃなくてコンパイル時に変数を評価するような書き方や $[xxx]
のように書く方法もあります。$[xxx]
という書き方も実行時に評価されるらしいですが、これは pwsh とかの中には書けませんでした。
trigger: - master variables: var1: Hello var2: World pool: vmImage: 'ubuntu-latest' stages: - stage: build displayName: build jobs: - job: test1 variables: jobVar1: $[variables.var1] jobVar2: $[variables.var2] steps: - pwsh: | Write-Host '$(var1)' Write-Host '$(var2)' - pwsh: | Write-Host '${{variables.var1}}' Write-Host '${{variables.var2}}' - pwsh: | Write-Host '$(jobVar1)' Write-Host '$(jobVar2)'
しれっと使ってますが job レベルとかでも変数を定義できます。上の yaml でいう jobVar1
と jobVar2
を定義しているところですね。
スクリプトの中で変数を定義したい
pwsh タスクなどの中で特別なフォーマットで標準出力に書き込むことでスクリプト内で変数を定義できます。出力する内容は "##vso[task.setvariable variable=変数名]値"
です。これで変数を定義できます。やってみましょう。
trigger: - master variables: var1: Hello var2: World pool: vmImage: 'ubuntu-latest' stages: - stage: build displayName: build jobs: - job: test1 steps: - pwsh: | Write-Host '##vso[task.setvariable variable=fromScript]Hello from Script' - pwsh: | Write-Host '$(fromScript)'
これで2つ目の pwsh のほうで Hello from Script
が表示されます。
同じ job 内の task からなら $(変数名)
でいけるのですが、これが job を跨ぐと参照できなくなります。試しにこうしてみましょう。
trigger: - master variables: var1: Hello var2: World pool: vmImage: 'ubuntu-latest' stages: - stage: build displayName: build jobs: - job: test1 steps: - pwsh: | Write-Host '##vso[task.setvariable variable=fromScript]Hello from Script' - job: test2 dependsOn: test1 steps: - pwsh: | Write-Host '$(fromScript)'
これを実行すると悲しいことに $(fromScript)
が表示されます。これは定義されていない変数を参照したとき表示されるやつですね。job を跨いだ変数の参照には一工夫がいります。
まず、script 内で変数を定義するときに isOutput=true
を定義して出力に含めるようにします。こうすることで job の出力として別の job から参照できます。参照する側では $[dependencies.依存先job名.outputs['タスク名.変数名']]
のようになります。あと、dependencies として参照するので dependsOn にも依存先として明示しておきます。以下のような感じです。
trigger: - master variables: var1: Hello var2: World pool: vmImage: 'ubuntu-latest' stages: - stage: build displayName: build jobs: - job: test1 steps: - pwsh: | Write-Host '##vso[task.setvariable variable=fromScript;isOutput=true]Hello from Script' name: scriptTask - job: test2 dependsOn: test1 variables: fromScriptInTest1: $[dependencies.test1.outputs['scriptTask.fromScript']] steps: - pwsh: | Write-Host '$(fromScriptInTest1)'
これで、fromScriptInTest1 変数に test1 ジョブで定義した fromScript 変数が入ります。
このスクリプト内での変数の宣言を応用すると、ARM Template の outputs を変数として定義することができるようになります。以下のような感じでいけます。
stages: - stage: build_and_deploy displayName: Build and deploy jobs: - job: infrastructure displayName: Create Azure resources steps: - task: AzureResourceManagerTemplateDeployment@3 displayName: Deploy ARM template to Azure inputs: deploymentScope: 'Resource Group' azureResourceManagerConnection: 'KazukiOta1' subscriptionId: 'xxxxxx-xxxxx-xxxxx-xxxxxx' action: 'Create Or Update Resource Group' resourceGroupName: $(resourceGroupName) location: 'Japan East' templateLocation: 'Linked artifact' csmFile: 'azuredeploy.json' csmParametersFile: 'azuredeploy.parameters.json' deploymentMode: 'Incremental' deploymentOutputs: armOutputs - pwsh: | $outputs = ConvertFrom-Json '$(armOutputs)' foreach ($x in $outputs.PSObject.Properties) { Write-Host "##vso[task.setvariable variable=armOutputs_$($x.Name);isSecure=true;isOutput=true]$($x.Value.value)" }
deploymentOutputs で ARM Template の出力の JSON を受け取って PowerShell 内でパースして ##vso...
を使って変数にしています。
ステージ間の変数の参照
これは正攻法ではできないみたいなので頑張るしかないみたいです。
以下の medium に、アーティファクトに変数の内容を出力しておいて、別のステージではアーティファクトをダウンロードして読み込んで使うという方法が書いてありました。
ちょっと大変ですね。
variable group
Pipelines の Library の中に Variable Group というものが作れます。ここで以下のように変数のグループを定義できます。
もう 1 つグループ作りました。こっちは日本語
このようにしておくと、以下のように stage 単位や job 単位でさくっと変数を切り替えれます。
trigger: - master pool: vmImage: 'ubuntu-latest' stages: - stage: development variables: - group: vargroup1 - name: var2 value: localVar jobs: - job: test1 steps: - pwsh: | Write-Host '$(message)' Write-Host '$(var2)' - stage: production variables: - group: vargroup2 - name: var2 value: 'ローカル変数' jobs: - job: test1 steps: - pwsh: | Write-Host '$(message)' Write-Host '$(var2)'
これを実行すると英語と日本語でそれぞれでますね。ばっちり。
template
template を使って variables を yaml として定義しておいて取り込むことで同じようなこともできます。 例えば vartemplate1.yml を以下の内容で作って
variables: message: Hello world
vartemplate2.yml を以下の内容で作って
variables: message: 'こんにちは世界'
そして、azurepipeline.yml を group から template に置き換えます。
trigger: - master pool: vmImage: 'ubuntu-latest' stages: - stage: development variables: - template: vartemplate1.yml - name: var2 value: localVar jobs: - job: test1 steps: - pwsh: | Write-Host '$(message)' Write-Host '$(var2)' - stage: production variables: - template: vartemplate2.yml - name: var2 value: 'ローカル変数' jobs: - job: test1 steps: - pwsh: | Write-Host '$(message)' Write-Host '$(var2)'
これでも Variable group と同じ結果が得られます。違いとしては、template の方はリポジトリーに入るけど Variable group はリポジトリには入らないという点です。リポジトリに入ったらまずい情報とかをまとめて置いておきたいとか時に気軽に使えます。
秘密な情報
その他にパイプラインの画面から変数を定義できます。こちらは、もうちょっと秘密なものを置けそう。
さらに、もっと秘密な情報を保存しておきたい時は Variable Group に Azure KeyVault との連携もあります。(これは自分ではまだ動作確認してない)
ということで秘密なものをきちんと全体で管理したいなら Azure KeyVault で、そうじゃないならパイプラインの変数でという感じでしょうか。もうちょっとゆるいやつは Variable group に限定的な人しか読めないようにしておいておくとか?
まとめ
ということで、Azure DevOps の Pipelines ネタのブログなら iPad で書けるのではないかと思って書いてみました。意外と画像編集もできるし workingcopy という git クライアント買えば Azure DevOps から clone してローカルで Textastic で編集して push とかも出来ていい感じでした。
でも、パソコンの方がやっぱりこういう作業は今のところ快適でした。