2018年12月11日火曜日

Azure Pipelines でマトリックスを組んでみた

この記事はAzure DevOps Advent Calendar 2018 11日目の記事です。
4日目に投稿した「ブログズミ: Azure Pipelines 始めました」の続きになります。


早速ですが、上のスクリーンショットは 31 個のジョブを実行している様子です。
いやホント10 並列は素晴らしいですね!

では、今回はマトリックスを組んでみた流れを紹介したいと思います。
テンプレートを作る
まずは、パラメータで処理パターンを増やすためのベースとなるテンプレート部分を作ります。
ドキュメントを見た感じですと、ジョブ、もしくはステップをテンプレートにできるようです。
Job and step templates - Azure Pipelines & TFS | Microsoft Docs

テンプレートの記述と利用
テンプレートは azure-pipelines.yml とは 別の yaml ファイルに記述します。
そして、azure-pipelines.yml もしくは別のテンプレートから下記のように参照します。
steps:
  - template: templates/sample.yml  # Template reference
jobs:
  - template: templates/jobs.yml  # Template reference

サンプルがドキュメントに載ってますので、そちらを見ていただくとわかりやすいと思います。
テンプレートは別のリポジトリのファイルを参照することもできるようですが、今回は使わないので省略します。 > Using other repositories

テンプレートにパラメータを渡す
テンプレートにパラメータとして任意の要素を渡し、パラメータに応じて処理内容を変えたいと思います。
Passing parameters
(ドキュメントを見ていると、単純の値や配列だけでなく、ジョブをパラメータとして扱うこともできるようですが、まだ実践してないので今回は省略)

まずは、パラメータのやり方から。

template 側の yaml
parameters:
  name: ''
  options: ''
  vmImage: 'ubuntu 16.04' # デフォルト値

jobs:
  - job: ${{ parameters.name }}
    pool:
      vmImage: ${{ parameters.vmImage }}
parameters にパラメータを定義します。ここでセットした値はデフォルト値になります。
パラメータの値を使用する場合は、${{ parameters.hogehoge }} のようにします。

azure-pipelines.yml 側
jobs:
  - template: .ci/azure_pipelines/template-make-test.yml
    parameters:
      name: default
 
パラメータを渡す場合も、parameters に記述します。
これでパラメータの受け渡しができるようになりました。

パラメータに応じて処理を変える
さて、中核に迫ってまいりました。
パラメータの内容によって、処理を変える方法はいろいろ考えられます。
ドキュメントを見ていると、高度なことができそうな感じがしているのですが・・・
まだ使いこなせてないので、省略。
* Template expression functions
   Expressions
* Insertion
* Conditional insertion
* Iterative insertion

今回はとてもシンプルにパラメータをスクリプトの引数として使いました。
(Azure Pipelines 側の書き方や制約に縛られず、自分の好きな書き方をできるので、まずはこの方法で良いと思います。)

iutest では以下のようにしました。
parameters:
  options: ''
  package_name: 'default'

steps:
- script: make -C test -j4 OUTPUTXML=junit ${{ parameters.options }}
  displayName: 'make'
- script: make -C test -j4 OUTPUTXML=junit ${{ parameters.options }} ${run_option} test
  displayName: 'test'
  env:
    run_option: RUN_OPTION="--iutest_default_package_name=${{ parameters.package_name }}"

make にオプションを渡せるようにしたのと、テスト実行時のオプションを指定するようにしました。

azure-pipelines.ym > job template > step template
さて、ここまででほぼほぼテンプレートを作ることができるようになっていると思いますが、最後にテンプレートを2段構成にしてみました。
テンプレートをテンプレートで使うことも問題なくできるのです!

iutest では、make test とテスト結果を集計するステップテンプレート、
そして、それをある程度の粒度でパラメタライズドしたジョブテンプレートにしました。



azrue-pipelines.yml は以下のように、ジョブテンプレートを利用するだけの非常にシンプルな内容になりました。
jobs:
  - template: .ci/azure_pipelines/template-make-test.yml
    parameters:
      name: default
  - template: .ci/azure_pipelines/template-make-disabled-test.yml
    parameters:
      name: disabled

テンプレート側の yaml は長いので、GitHub を見てくださいmm
iutest/azure-pipelines.yml at master · srz-zumix/iutest
iutest/.ci/azure_pipelines at master · srz-zumix/iutest

マトリックスを書く

これが、ちょっと長いのですが・・・こんな感じになりました。


ステップテンプレートに make のオプションを生成して流しているジョブテンプレートになるのですが、
やっていることは1つのマクロを定義して config を変えて、ビルド・テストをさせています。
そのマクロ部分をマトリックスにしたのですが、いちいち名前をつけないといけないのが面倒・・・
DISABLED_CONFIG 配列に定義できると楽なんですが・・・

たぶん、もっとキレイに書けるんだろうなーという感触はありますが、今後の課題としたいと思いますmm

10並列の効果はどんなもんよ?
iutest の現時点で、1 pipeline で 57 ジョブが実行しています。
各ジョブでやっていることは、ほぼほぼ同等でマクロ定義が1つ異なるだけのビルド・テストです。
1ジョブの実行時間が約5分。

直列に行った場合は、5 x 57 分で約5時間です・・・

が、これが、


なんと!


およそ 35分 !!
10並列のパワー素晴らしい

テスト失敗してますよ?
はい。
今まで config 変更のテストは、ローカルの Jenkins もしくは今はなき SnapCI でやっていたのですが(それかローカル実行)、とにかく時間がかかって辛かった!のでやってませんでした。すみませんmm
今回、Azure Pipelines の力によってメンテナンスできてなかった部分が炙り出された感じです。
本当、ありがとうございます!!って感じです。
(FAIL はちゃんと直します。ごめんなさい)

今後やりたいこと
さて、今回はこれで以上となりますが、
まだまだ Azure Pipelines でやりたいこと・できることは多そうです。
また進展あったらまとめたいと思います。ではでは。

* [ci skip]
* auto cancel
* 簡易テスト後に、マトリックスが走るようにする(dependsOn の挿入?)
* 条件分岐(xml 出力がされないことを期待する場合に、集計をしない)
* yaml に書く量を減らしたい
* 本当のマトリックス( N x M )で爆発させたい

0 件のコメント:

コメントを投稿