Azure Pipelines 分析入門

Azure DevOps Service を使い始めて数カ月経ち、実際に業務で Pipeline を組むようなシーンが出てきたり、AZ-400 を取得しようとしていたりしています。
ただ、Azure Pipelines を実装したはいいものの遅いなと思うことがあり、これを分析したいと思っていたらそのものずばりの機能があったので、触ってみた感触などを交えながら Azure Pipelines の分析に入門してみたいと思います。

# Azure Pipelines とは

CI/CD を実装する際には必須と言っても過言ではないパイプラインを作成・実行する機能を提供する Azure DevOps Service の一つです。

## 公式情報

[Azure - Azure Pipelines](https://azure.microsoft.com/ja-jp/products/devops/pipelines)
[Azure Pipelines のドキュメント](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/?view=azure-devops)

## パイプラインの定義方法

[GitHub Actions](https://github.co.jp/features/actions) がわかる方はそのイメージでおよそ近しいものになります。
たとえば、次のような YAML ファイルを定義してパイプラインとして設定すると、設定した内容に応じて、コードがマージされたことや PR が発行されたことなどをトリガとして自動的にインテグレーションやデプロイのためのプロセスを実行することができます。
この例では、main ブランチに対する PR(※1)・main ブランチに対するコードのマージ・api/または app/ディレクトリに対する変更のみ、という条件でパイプラインが起動されます。

```yaml
name: Azure Static Web Apps CI/CD

pr:
  branches:
    include:
      - main
trigger:
  branches:
    include:
      - main
  paths:
    include:
      - api/*
      - app/*

jobs:
  - job: build_and_deploy_job
    displayName: Build and Deploy Job
    timeoutInMinutes: 30
    cancelTimeoutInMinutes: 10
    condition: or(eq(variables['Build.Reason'], 'Manual'),or(eq(variables['Build.Reason'], 'PullRequest'),eq(variables['Build.Reason'], 'IndividualCI')))
    pool:
      vmImage: ubuntu-latest
    variables:
      - group: Azure-Static-Web-Apps-xxxxx-xxxx-xxxxxxxxx-variable-group
    steps:
      - checkout: self
        submodules: true
      - task: AzureStaticWebApp@0
        env:
          NEXT_PUBLIC_APPINSIGHTS_INSTRUMENTATIONKEY: $(NEXT_PUBLIC_APPINSIGHTS_INSTRUMENTATIONKEY)
          NEXT_PUBLIC_APPLICATIONINSIGHTS_CONNECTION_STRING: $(NEXT_PUBLIC_APPLICATIONINSIGHTS_CONNECTION_STRING)
        inputs:
          azure_static_web_apps_api_token: $(AZURE_STATIC_WEB_APPS_API_TOKEN_XXXXX_XXXX_XXXXXXXXX)
          ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
          # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
          app_location: "/app" # App source code path
          api_location: "/api" # Api source code path - optional
          output_location: "out" # Built app content directory - optional
          ###### End of Repository/Build Configurations ######
```

このパイプラインは次のような環境で実行されます。

- Microsoft によってホストされるエージェント
- 同時実行数は 1

# Azure Pipelines Analytics

Azure Pipelines ではあるパイプラインの実行状況について分析レポートを見ることができます。
これにより、パイプラインの実行に時間が掛かったり失敗している場合に何が問題なのかを特定することができ、デプロイ時間等の改善を行うことができます。
デプロイ時間を短くできれば、コスト効率の改善や素早く確実なデプロイによる価値提供などに貢献することができそうです。

ここでは、既に作成済みのパイプラインを何度か実行している環境の Analytics 画面の情報等を通じて分析に入門してみます。

## Pipeline 実行履歴

まずは、どのパイプラインを分析したいのか決める必要があります。
下図のように実行履歴が見れるので、ここから確認したいパイプラインを選択します。

![azure-pipelines-history.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118632/0b7495d9-76d0-9eca-203c-69387317f419.png)

## 分析画面

選択したパイプラインについて Analytics タブを選択すると、下図のように分析レポートを確認することができます。

![azure-pipelines-analytics.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3118632/1a0a2e55-3199-fa32-ac6e-555a86e2765c.png)

ここで表示されるグラフがちょっと見づらいなと思いました。
また、ステップごとの実行時間などもマウスをポイントすれば見られるのですが、平均など統計的に操作した数値を見ることはできないので、ぱっと見て大体どれぐらいの時間が掛かっているのかを知るのは少し手間です。
何か別の仕組みなのか、Markeplace で何かを探してくる必要があるかもしれません。

### 分析

ここでは次のようなことが言えます（既に示されているものも含めて）。

- 実行時間の 80 パーセンタイル値は 4 分 25 秒
- 38 の成功したパイプラインがある
- 実行時間の内、98.55% が Azure Static Web App のタスクに費やされている
- 実行時間の内、99.09% を占める step の上位 10 位の中では、Default/AzureStaticWebApp ステップが圧倒的に実行時間が長く、割合としては支配的
- AzureStaticWebApp ステップの内容を解析することでデプロイ時間を改善できる可能性がある

注）3/20 に、1 つだけ実行時間が極端に長いパイプライン履歴があります。
こちらは Azure Static Web App のデプロイがタイムアウトで終了したときのものであることが、実行ログからわかっています。

## 分析結果を踏まえた今後の対応

たとえば今回であれば次のような対応が考えられるかと思います。

- Static Web App のデプロイタスクに最も時間が費やされているので、ここで何が起きているのか調査する
- 短縮できる余地があれば実施してデプロイ時間の短縮化により Free tier を無駄に消費しないようにする

:::note warn
Static Web App のデプロイでは時折「成功しているのに長時間ポーリングで待たされる」ことや「タイムアウトして失敗したように見えるがデプロイ自体は成功している」ことがあるので、今回のケースで実際に改善できるかどうかはわからないと考えています。
:::

# まとめ

Azure DevOps Service を使えば、ソフトウェア開発に必要な管理ツールがパッケージで手に入ります。
しかも従量課金（無料枠あり）なので、お試しで使って必要に応じて課金できます。
特に、継続的インテグレーションや継続的デリバリーを実践される際にはパイプライン機能は必要になりますので、こうしたツールを導入してプラクティスの実践をアシストできると素晴らしいですね。

## 余談

Sam Newman の『マイクロサービスアーキテクチャ』では次のようにも言われており、「確かにそういう現場あるよね...」という気持ちになったのと同時に、今回分析したパイプラインも CI にはなっていないことに気付きました。

> CI を行っていると言っているにもかかわらず実際には全く行っていない多くのチームと、一緒に仕事をしたことがあります。CI ツールの利用と CI のプラクティスを混同しているのです。ツールは、単にこの手法を可能にする道具にすぎません。
> 私は、CI とは何かを本当に理解しているかを調べるために Jez Humble が尋ねた 3 つの質問を、とても気に入っています。
> 
> **1 日に一度はメインラインにチェックインしていますか**
> **変更を検証するテストスイートがありますか**
> **ビルドが壊れたときに、それを修正するのがチームの最優先事項でしょうか**

--- _Sam Newman 『マイクロサービスアーキテクチャ』 p.122, 6.1.1 実際に CI を行っているか_

---

※1...YAML PR トリガーは [GitHub と BtiBucket でのみサポートされています](https://learn.microsoft.com/ja-jp/azure/devops/pipelines/yaml-schema/pr?view=azure-pipelines)。ですので、ここで提示した YAML ファイルのPRトリガーは Azure Repos では機能しません。Azure Repos では PR トリガーの代わりに [Build Validation のブランチポリシーを構成する](https://learn.microsoft.com/ja-jp/azure/devops/repos/git/branch-policies?view=azure-devops&tabs=browser#build-validation)ことで実現できます。