tech.guitarrapc.cóm

Technical updates

Azure DevOps Pipeline をYAML で定義しよう

何度か挙げている Azure DevOps Pipeline ですが、ずっとYAML で紹介してきたかと思います。

実際に私はAzure DevOps にYAML がPreview で来てからずっとYAML にしています。

これはほかのCIサービスも複数触っていたことからもYAML でかけることに大きなメリットを見出していたからですが、改めてAzure DevOps でPipeline をYAML で定義するのをなぜススメるのか一部を書いておきます。

目次

TL;DR

ビルドは、そのプロジェクトを透明に維持するための大きなファクタの1つです。 コードとの密な連携を求められるCI/CD において、ビルドの定義はコードと近いほうがイテレーションを短くできます。 YAML はその手段の一つであり、現時点において大勢をなす方法の一つです。

Pipeline first な開発をするためにも、開発者自身が主体的にビルドを組めるYAML はいい方法になるでしょう。

個人的には、YAML で定義できないビルドサービスはなるべく避けたほうがいいと判断します。

YAML 定義のメリット

YAMLで定義できるということは、そのプロジェクトのビルド設定を、そのプロジェクトのリポジトリに置けます。結果として、アプリケーションの変更で生じたビルドの変更も適用しやすく素早くビルドを開発に合わせられるメリットがあります。(Config as Code の1つと言われたりするようですね)

Azure Pipeline でもYAML で定義することで、どのようなビルドをしているかが定義でわかります。

また、Multi Stage Pipeline でワークフローっぽく複数のジョブの連携を1つのYAMLで定義できるようになっています。*1 GUI では難しかった同じような内容のビルドでパラメータが違うだけ、というのも、YAMLならJob/Step Template を使うことで、なんども同じ定義をせず再利用が可能です。*2

YAMLでパイプラインを組みたいときの流れ

YAML Pieplineを選択してビルドパイプラインを設定しましょう。

Azure DevOps Pipeline は、後付けでYAML定義がきました。 そのため、ほかのYAML定義ができるCI サービス に比べると処理をタスクという単位で設定することが多い傾向にあります。 このタスクの中身は、Pipeline で実行したい特定の操作を TypeScript で定義してMarket Store で公開、利用するものです。 CircleCI だとOrb が近いでしょう。

Orbがそうであるように、タスクを利用するときはそのタスクに渡すパラメーターを知る必要があります。 この時、Orbなら Explore Orbsで定義が探すとOrbの利用方法が一緒に公開されているので困ることがほぼありません。

circleci.com

しかし タスクを配布している Market Place にこの仕組みがないため、どのように利用するかのリファレンスはタスクの作者がGitHub で紹介しているか頼みです。で、GUI でタスクを設定するときの画面を見つつやることが多いという悪循環があります。

Azure DevOps でUnity Tools for Azure DevOpsタスクをLegacyパイプラインでUIから設定する

YAML ではこういう入力は見れないでしょうか? そうでもありません。 Azure DevOps Pipeline のサービス上で Pipeline の Edit を行うとUIからのUIからの入力がされます。*3 GUI -> YAML がまとめて提供されているCIサービスって珍しいのでなかなか不思議な感覚です。

Azure DevOpsのPipeline 画面から Unity Tools for Azure DevOps を設定する

あるいは 以前のUIからのパイプラインを組んでおいてYAML にExport という手もあります。 以前はカスタムタスクで必ずと言っていいほど使っていましたが、UI からのYAML入力ができてからは使わなくなりました。

Legacy Pipeline でUI上で組んだ設定をYAML でPreviewする

YAML で困ること

Azure DevOps Pipeline のYAML は、Multi Stage Pipeline がきて、一般的なSaaS 型CI のYAML 定義に比べてもかなり近づきました。 とはいえ、YAML だけ未サポートだったり、アンドキュメントな挙動はあります。

そのあたりを見てみましょう。

Multi Stage Pipeline と失敗ジョブの再開

ありません。つらい。

CircleCI でいうところの、Workflow 中の失敗Job だけの再実行 (Rerun from failed)はないので、ビルドをやり直すしかありません。

CircleCI のWorkflow 失敗時の選択

Failed Job の再開くればいいんですけど。

Reference variable などの未サポート機能

Reference Variable はYAMLでは定義できません。 しかし、タスクが出力変数を設定しているなら、タスクの name: を設定することで後続で利用できます。

こういった未サポート機能でも、なんかやる方法があったりします。アンドキュメントですが。

適当にフィードバックの各種や GitHub Issue をみるといいでしょう。

docs.microsoft.com

github.com

リリースとYAML定義

ReleaseにはYAMLがありません。そのためReleaseはどうしようかと思ってしばらくしましたが、2019/6にMulti Stage Pipeline がきました。

これでRelease はオワコンっぽい雰囲気しつつあります。

ただしDeployment Group が YAML では扱えないのでそこは置いておきましょう。Gate 機能も使えないので困ったものです。

一方でビルドトリガーに関しては、Multi Stage Pipeline + Pipeline Artifact (Build Artifact はLegacyです) で checkout: none にして、Condition をかければいいでしょう。

approve などのGate と Deployment Group だけ困りますが、ほかまぁ何とかなります。

Display Name のうざさ

Azure DevOps では ビルドタスクで DisplayName: をつけなかった場合、ステップの名称はタスクの名称 になります。 Comand Line タスクなら、CmdLine となってしまい、実行しているコマンドが自動的に付けられません。

DisplayName: を省いたときのタスク実行時の表示

結果、DisplayName: を設定することになり、ビルド定義が冗長になっていくことが多いでしょう。

一方のCircleCI では、ビルドタスクに名前をつけず、YAMLをなるべく最小限にしても困りません。 ビルドステップに名前を使えなかった時に、実行ログのstep 名にはコマンドがそのまま名称になるからです。

CircleCIでステップの名称を付けないと、ステップの実行内容がそのまま表示される

こういう細かいところが、まだまだ改善の余地を感じます。

キャッシュ機能

AzureDevOps には現状ビルドstep のキャッシュ機能はありません。 これがこないと毎ビルドでパッケージを復元したり無駄極まりありません。

Peeview でくるらしいので待ちましょう。 キャッシュが来る場合、CircleCI のキャッシュのようにキーによる世代ハンドリングをしたいところです。 これが来ないとかなりアレなので。

おわりに

YAML 定義は、Multi Stage Pipeline が来るまではリリース含めてどうするか、厳しいと言わざるを得ませんでした。 しかし、Multi Stage Pipeline が来て、ジョブの定義をより強力に記述できるようになったことでだいぶんよくなりました。

もし Azure DevOps Pipeline を使うなら、YAML 一択です。

*1:CircleCI の Workflow に相当

*2:CirclecI でいう Command やJobに相当

*3:あくまで入力値だけで一度YAMLにいれたものの編集では開きません