パイプラインを設計する
このユニットでは、Tailspin Web チームが Space Game Web サイトのリリース パイプラインを定義するところを見ていきます。
リリース パイプラインを計画するときは、通常、そのパイプラインの "ステージ" (主要な区分) を特定することから始めます。 通常、各ステージは環境にマップされます。 たとえば、前のモジュールでは、Andy と Mara の基本的なパイプラインには、Azure App Service インスタンスにマップされた "デプロイ" ステージがありました。
このモジュールでは、変更をあるステージから次のステージに "昇格" させます。 各ステージ内で、Space Game Web サイトをそのステージに関連付けられている環境に "デプロイ" します。
必要なステージを定義したら、変更をあるステージから次のステージにどのように昇格させるかを検討します。 各ステージでは、ビルドを次のステージに移行する前に満たす必要がある成功条件を定義できます。 Azure Pipelines には、パイプライン内で変更を移行する方法とタイミングを制御するためのいくつかの方法が用意されています。 全体として、これらのアプローチは "リリース管理" に使用されます。
このセクションでは、次の作業を行います。
- "ビルド"、"開発"、"テスト"、"ステージング" などの一般的なパイプラインのステージの違いについて学習します。
- 成果物がパイプラインの次のステージに移動されるときに、手動、スケジュール、継続的配置の各トリガーを使用する方法を理解します。
- "リリースの承認" で、承認者がリリースを承諾するか拒否するまでパイプラインが一時停止されるしくみを確認します。
会議
Tailspin Web チームの全員が集まっています。 Azure Pipelines でのリリース パイプラインの作成に関するモジュールでは、チームは現在のスプリントのタスクを計画しました。 各タスクは、Space Game Web サイトのリリース パイプラインの作成に関連しています。
チームがスプリントに対して次の 5 つのタスクを決定したことを思い出してください。
- マルチステージ パイプラインの作成。
- データベースへの Web アプリの接続。
- 品質テストの自動化。
- パフォーマンス テストの自動化。
- リリース周期の改善。
チームは、1 番目のタスク ("マルチステージ パイプラインの作成") について話し合うために会議を開きます。 チームがパイプラインを定義したら、基本的な概念実証からリリース パイプライン (追加のステージ、品質チェック、承認を含む) に移行できます。
Amita と Tim は Andy と Mara がリリース パイプラインのデモを行っているのを再び見ています。 成果物がビルドされて、App Service にインストールされることを確認しました。
必要なパイプライン ステージ
リリース パイプラインを実装する場合は、まず必要なステージを特定することが重要です。 選択するステージは要件によって異なります。 チームがステージを決定する話し合いに加わってみましょう。
Tim: はい、自動化されたパイプラインの概念を理解できました。 Azure に簡単にデプロイできるところが気に入っています。 しかし、このデモからどこに進むのですか? リリースに実際に使用できるものが必要です。
Amita: そのとおりです。 他のステージを追加する必要があります。 たとえば、現在、テスト ステージの場所はありません。
Tim: さらに、新しい機能を経営陣に見せることができるステージが必要です。 経営陣の承認を得ずに運用環境に何かを送ることはできません。
Andy: もちろんです。 リリース パイプラインの機能について理解できましたが、このパイプラインに必要なことを実行させるにはどうすればよいでしょうか?
Mara: 次の手順を計画するための要件を書き出してみましょう。 既にあるものから始めます。
Mara はホワイトボードに移動して、既存のパイプラインをスケッチします。
Mara: "ビルド" ステージでは、ソース コードをビルドして、パッケージを生成します。 この場合、そのパッケージは .zip ファイルです。 "デプロイ" ステージでは、App Service インスタンスに .zipファイル (Space Game Web サイト) がインストールされます。 リリース パイプラインに欠けているものは何ですか?
開発ステージを追加する
Andy: バイアスがかかっているかもしれませんが、"開発" ステージが必要だと思います。 このステージは、成果物を構築した後の最初のステージである必要があります。 開発者は、ローカルの開発環境からサービス全体を常に実行することはできません。 たとえば、eコマース システムには、Web サイト、製品データベース、支払いシステムが必要になる場合があります。 アプリに必要なすべてのものを含むステージが必要です。
この場合、Space Game Web サイトのランキング機能によって、外部ソースからハイスコアが読み取られます。 現在は、ファイルから架空のスコアを読み取っています。 "開発" ステージを設定すると、Web アプリを実際のデータベースと統合できる環境を持つことができます。 そのデータベースにも架空のスコアが保持されるかもしれませんが、最終的なアプリに 1 歩近づきます。
Mara: それはいいですね。 実際のデータベースにはまだ統合されません。 でも、"開発" ステージでは、データベースを追加できる環境にデプロイできます。
Mara はホワイトボードのスケッチを更新します。 "デプロイ" を "開発" に置き換えて、"開発" ステージを示します。
Andy: 興味深いことが示されましたね。 私たちは、変更を GitHub にプッシュするたびに、アプリをビルドします。 これは、ビルドの完了後に各ビルドが "開発" ステージに昇格されるということでしょうか?
Mara: 継続的にビルドすることで、ビルドとテストの正常性に関する重要なフィードバックを得ることができます。 でも、コードをセントラル ブランチ (メインまたはその他のリリース ブランチ) にマージする場合にのみ、"開発" ステージに昇格させたいですね。 この要件が示されるように、スケッチを更新します。
Mara: この昇格は簡単に実現できると思います。 リリース ブランチで変更が行われた場合にのみ "開発" ステージに昇格させる "条件" を定義できます。
条件とは
Azure Pipelines では、パイプラインの状態に基づいてタスクまたはジョブを実行するために条件を使用します。 以前のモジュールで条件を使用しました。
指定できる条件には次のようなものがあることを思い出してください。
- 前の依存タスクがすべて成功したときだけ。
- 実行が取り消された場合を除き、前の依存関係が失敗した場合でも。
- 実行が取り消された場合も含め、前の依存関係が失敗した場合でも。
- 前の依存関係が失敗したときだけ。
- 何らかのカスタム条件。
基本的な例を次に示します。
steps:
- script: echo Hello!
condition: always()
always()
条件により、このタスクは、前のタスクが失敗した場合でも無条件に "Hello!" を出力します。
条件を指定しない場合は、この条件が使用されます。
condition: succeeded()
組み込み関数 succeeded()
では、前のタスクが成功したかどうかをチェックします。 前のタスクが失敗した場合、このタスクと、同じ条件を使用するその後のタスクはスキップされます。
ここでは、次のことを指定する条件を作成します。
- 前のタスクが成功した。
- 現在の Git ブランチの名前は "release" である。
この条件を作成するには、組み込みの and()
関数を使用します。 この関数は、その条件のそれぞれが真かどうかをチェックします。 いずれかの条件が真でない場合は、条件全体が失敗します。
現在のブランチの名前を取得するには、組み込み変数 Build.SourceBranchName
を使用します。 条件内で変数にアクセスする方法はいくつかあります。 ここでは variables[]
構文を使用します。
変数の値をテストするために、組み込みの eq()
関数を使用できます。 この関数は、その引数が等しいかどうかチェックします。
これを念頭に置いて、現在のブランチ名が "release" である場合にのみ "開発" ステージが実行されるように、この条件を適用します。
condition: |
and
(
succeeded(),
eq(variables['Build.SourceBranchName'], 'release')
)
and()
関数の最初の条件は、前のタスクが成功したかどうかチェックします。 2 番目の条件では、現在のブランチ名が "release" であるかどうかをチェックします。
YAML では、パイプ (|
) 構文を使用して、複数行にまたがる文字列を定義します。 条件は 1 行で定義できますが、読みやすくするために、このように記述しています。
Note
このモジュールでは、例として release ブランチを使用しています。 条件を組み合わせることによって、必要な動作を定義できます。 たとえば、"メイン" ブランチに対する pull request によってビルドがトリガーされた場合にのみステージを実行する条件を作成できます。
次のユニットでは、"Dev" ステージを設定するときに、より完全な例を使います。
Azure Pipelines での条件の詳細については、式のドキュメントを参照してください。
Mara: 条件を使用すると、どの変更をどのステージに昇格されるかを制御できます。 ビルドを検証して、それが正常であることを確認するために、変更のビルド成果物を生成できます。 準備ができたら、これらの変更をリリース ブランチにマージし、そのビルドを "開発" ステージに昇格させることができます。
テスト ステージを追加する
Mara: 今のところ、"ビルド" と "開発" のステージがあります。 次のステージは何でしょう?
Amita: 次に "テスト" ステージを追加できますか? 私が最新の変更をテストするのに適切な場所のように思います。
Mara は、ホワイトボード上のスケッチに "テスト" ステージを追加します。
Amita: 1 つ心配なのは、私がアプリをテストする必要がある頻度です。 Mara や Andy によって変更が行われるたびに、電子メールで私に通知されます。 1 日に何度も変更が行われるので、いつ取り掛かればいいのかわかりません。 1 日に 1 回ビルドが送られてくるといいと思うんですが、たとえば、私が出勤したときに。 そのようにすることはできますか?
Andy: もちろん。 勤務時間外に "テスト" にデプロイしないのはなぜですか? 毎日午前 3 時にビルドを送ることにしたらどうでしょう。
Mara: そうですね。 必要に応じて、いつでも手動でこのプロセスをトリガーすることもできます。 たとえば、重要なバグ修正をすぐに確認してもらう必要がある場合に、トリガーすることができます。
Mara は自分のスケッチを更新して、ビルドが "開発" ステージから "テスト" ステージに毎朝午前 3 時に移動されることを示します。
トリガーとは
Amita: あるステージから別のステージに移行する方法がわかってすっきりしました。 でも、ステージを実行するタイミングはどのように制御するのでしょうか?
Mara: Azure Pipelines では、トリガーを使用できます。 "トリガー" には、ステージを実行するタイミングを定義します。 Azure Pipelines には、いくつかの種類のトリガーが用意されています。 次の中から選択できます。
- 継続的インテグレーション (CI) トリガー
- プル要求 (PR) トリガー
- スケジュールされたトリガー
- ビルド完了トリガー
CI および PR トリガーでは、プロセス全体に参加するブランチを制御できます。 たとえば、いずれかのブランチで変更が行われたときに、プロジェクトをビルドするとします。 スケジュールされたトリガーでは、特定の時刻にデプロイが開始されます。 ビルド完了トリガーでは、別のビルド (依存コンポーネントのビルドなど) が正常に終了したときにビルドが実行されます。 スケジュールされたトリガーがいいようですね。
スケジュールされたトリガーとは
"スケジュールされたトリガー" では、cron 構文を使用して、定義されたスケジュールでビルドが実行されます。
Unix および Linux システムでは、cron は、設定された時間間隔または特定の時刻にジョブが実行されるようにスケジュールするための一般的な方法です。 Azure Pipelines のスケジュールされたトリガーでは、cron 構文を使用して、ステージを実行するタイミングを定義します。
cron 式には、特定の時刻パラメーターに対応するフィールドが含まれています。 そのフィールドを次に示します。
mm HH DD MM DW
\ \ \ \ \__ Days of week
\ \ \ \____ Months
\ \ \______ Days
\ \________ Hours
\__________ Minutes
たとえば、次の cron 式では、"毎日午前 3 時" が指定されています: 0 3 * * *
cron 式には、値のリストまたは値の範囲を指定するための特殊文字を含めることができます。 この例では、アスタリスク (*) は、日、月、曜日の各フィールドのすべての値と一致します。
言い換えると、この cron 式は次のように解釈できます。
- 0 分、
- 3 時、
- 任意の日、
- 任意の月、
- 任意の曜日に、
- ジョブの実行
月曜日から金曜日の午前 3 時を指定するには、この式を使用します: 0 3 * * 1-5
Note
cron スケジュールのタイム ゾーンは協定世界時 (UTC) であるため、この例では午前 3 時は UTC の午前 3 時を意味します。 実際には、自分とチームが予期している時間にパイプラインが実行されるように、cron のスケジュールの時刻を UTC を基準にして調整することができます。
Azure Pipelines でスケジュールされたトリガーを設定するには、YAML ファイルに schedules
セクションが必要となります。 次に例を示します。
schedules:
- cron: '0 3 * * *'
displayName: 'Deploy every day at 3 A.M.'
branches:
include:
- release
always: false
この schedules
セクションで:
cron
には cron 式が指定されています。branches
ではrelease
ブランチからのみデプロイするように指定されています。always
では、デプロイを無条件に実行するか (true
)、最後の実行以降にrelease
ブランチが変更された場合にのみ実行するか (false
) を指定します。 ここでは、最後の実行以降にrelease
ブランチが変更された場合にのみデプロイする必要があるため、false
を指定します。
Azure Pipelines でスケジュールされたトリガーが実行されると、パイプライン全体が実行されます。 また、パイプラインは他の条件でも実行されます (GitHub に変更をプッシュするときなど)。 スケジュールされたトリガーに応じる場合にのみステージを実行するには、ビルドの理由がスケジュールされた実行であるかどうかをチェックする条件を使用できます。
次に例を示します。
- stage: 'Test'
displayName: 'Deploy to the Test environment'
condition: and(succeeded(), eq(variables['Build.Reason'], 'Schedule'))
このステージ (Test
) は、前のステージが成功し、組み込みのパイプライン変数 Build.Reason
が Schedule
である場合にのみ実行されます。
より完全な例については、このモジュールで後ほど説明します。
Amita: これはいいですね。 リリースを手動で選択してインストールする必要もありません。 準備は整っています。
Andy: 後でさらに自動化したい場合はそれも可能であることを忘れないでください。 何かが石に刻まれているわけではありません。 私たちが改善を行い、学んでいくにつれて、パイプラインが進化します。
ステージング ステージを追加する
Tim: 今度は私の番です。 さらにストレス テストを実行するためのステージが必要です。 また、承認を得るために経営陣にデモを見せることができるステージも必要です。 今のところ、これら 2 つのニーズを、"ステージング" とでも呼ぶことができる 1 つのステージにまとめることができます。
Andy: Tim、そのとおりです。 "ステージング" 環境 (運用前環境) を持つことは重要です。 多くの場合、このステージング環境は、機能またはバグ修正がユーザーに届けられる前の最後の場所です。
Mara は、ホワイトボード上の自分のスケッチに "ステージング" を追加します。
Amita: 変更を "開発" ステージから "テスト" ステージに昇格させる場合は、スケジュールされたトリガーを使用します。 でも、変更を "テスト" から "ステージング" に昇格させるにはどうすればよいでしょうか? その昇格もスケジュールに基づいて行われる必要がありますか?
Mara: それに対処する最善の方法は、"リリースの承認" だと思います。 リリースの承認により、変更をあるステージから次のステージに手動で昇格させることができます。
Amita: それはまさに私が必要としていたもののようです。 リリースの承認により、ビルドを経営陣に見せる前に、私が最新の変更をテストする時間ができます。 準備ができたら、ビルドを昇格させることができます。
Mara は、自分のスケッチを更新して、Amita によって承認された場合にのみ、ビルドが "テスト" から "ステージング" に移行することを示します。
Tim: 経営陣によるサインオフの後に、リリースの承認を使用して "ステージング" から "運用環境" に昇格させることも想像できます。 それにどの程度の時間がかかるかは予想できません。 サインオフされた後に、リリースを承認して、運用環境に手動で昇格させることができます。 しかし、リリースの承認はどのように機能するのでしょうか?
リリースの承認とは
"リリースの承認" は、承認者がリリースを承諾するか拒否するまでパイプラインを一時停止する方法です。 リリースのワークフローを定義するには、承認、条件、トリガーを組み合わせることができます。
Azure Pipelines でのリリース パイプラインの作成に関するモジュールで、デプロイ環境を表す環境をパイプライン構成で定義したことを思い出してください。 既存のパイプラインの例を次に示します。
- stage: 'Deploy'
displayName: 'Deploy the web application'
dependsOn: Build
jobs:
- deployment: Deploy
pool:
vmImage: 'ubuntu-20.04'
environment: dev
variables:
- group: Release
環境には、リリースの特定の条件を含めることができます。 条件では、その環境にデプロイできるパイプラインと、リリースをあるステージから次のステージに昇格させるために必要な手動の承認を指定できます。
このモジュールの後の方では、ステージング環境を定義し、"テスト" ステージから "ステージング" に "Space Game" Web アプリを昇格させるための承認者として自分自身を割り当てます。
最低限の自動化または必要に応じた自動化
Azure Pipelines では、いくつかのステージを自動化し、自動化の準備ができていないステージは手動で制御するというような柔軟性が提供されます。
Tim: 変更をあるステージから次のステージに昇格させる条件を定義する方法が気に入りました。 しかし、パイプラインでは手動条件をいくつか定義しました。 DevOps ではすべてが自動化されると思っていました。
Mara: 良い指摘ですね。 DevOps は、反復的でエラーが発生しやすいタスクを自動化するためのものです。 場合によっては、人による介入が必要です。 たとえば、新しい機能をリリースする前に、経営陣の承認を得ます。 自動化されたデプロイの経験をさらに積むと、手動の手順をさらに自動化してプロセスを迅速にすることができます。 たとえば、"テスト" ステージで追加の品質チェックを自動化して、Amita がビルドごとに承認しなくて済むようにすることができます。
Tim: それはすばらしいですね。 ここではこの計画を実行してみて、後でシステムを迅速にする方法を確認しましょう。
Amita: 私たちの計画についてですが、次のステップをまとめませんか?
計画
Tailspin チームは次のステップに進もうとしていますが、彼らの計画を確認してみましょう。
Mara: ビルドするリリース パイプラインはこれです。
Mara がホワイトボードを指差します。
Mara: まとめると、私たちの手順では次のことを行います。
- 変更を GitHub にプッシュするたびに、ビルド成果物を生成します。 この手順は、"ビルド" ステージで行われます。
- ビルド成果物を "開発" ステージに昇格させます。 この手順は、ビルド ステージが成功し、変更がリリース ブランチに移行されたときに自動的に実行されます。
- ビルド成果物を毎朝午前 3 時に "テスト" ステージに昇格させます。スケジュールされたトリガーを使用して、ビルド成果物を自動的に昇格させます。
- Amita がビルドをテストして承認した後に、ビルド成果物を "ステージング" に昇格させます。 リリースの承認を使用して、ビルド成果物を昇格させます。
経営陣がビルドを承認した後、ビルド成果物を運用環境にデプロイできます。
Amita: これは大変な作業になりますか? やることがたくさんあるように思います。
Mara:それほど悪くないと思います。 すべてのステージは、他のすべてのステージと分離されています。 ステージは別々になっています。 各ステージには、独自の一連のタスクがあります。 たとえば、"テスト" ステージで行われることは、"テスト" ステージ内にとどまります。
また、パイプラインのすべてのデプロイ ステージには独自の環境があります。 たとえば、アプリを "開発" または "テスト" にデプロイすると、その環境は App Service インスタンスです。
最後に、一度に 1 つのリリースのみをテストします。 パイプラインの途中でリリースが変更されることはありません。 "開発" ステージでは "ステージング" ステージと同じリリースが使用されており、すべてのリリースに独自のバージョン番号があります。 リリースがいずれかのステージで中断した場合は、それを修正して新しいバージョン番号でもう一度ビルドします。 その新しいリリースは、パイプラインの最初から処理されます。
品質に関するいくつかの提言
このチームが、ビルドからステージングまでアプリの処理を行うパイプラインを設計するのをずっと見てきました。 このパイプラインの要点は、彼らの仕事を容易にすることだけではありません。 顧客に提供するソフトウェアの品質を保証することです。
リリース プロセスの品質を測定するにはどうすればよいですか。 リリース プロセスの品質を直接測定することはできません。 測定できるのは、プロセスが良好に機能しているかどうかです。 プロセスを常に変更している場合は、何か問題があることを示している可能性があります。 パイプラインの特定の時点で継続的に失敗するリリースも、リリース プロセスに問題があることを示している可能性があります。
リリースは常に特定の日または時間に失敗しますか。 特定の環境にデプロイした後に常に失敗しますか。 リリース プロセスの特性に依存関係があるか、または関連しているかどうかを確認するには、これらのパターンおよびその他のパターンを見つけます。
リリース プロセスの品質を把握する良い方法は、リリースの品質を視覚化することです。 たとえば、すべてのリリースの状態を表示するダッシュボード ウィジェットを追加します。
リリース自体の品質を測定する場合は、パイプライン内ですべての種類のチェックを実行できます。 たとえば、パイプラインの実行中にさまざまな種類のテスト (ロード テストや UI テストなど) を実行できます。
品質ゲートを使用することも、リリースの品質をチェックするための優れた方法です。 さまざまな品質ゲートがあります。 たとえば、作業項目ゲートでは、要件プロセスの品質を確認できます。 セキュリティとコンプライアンスのチェックをさらに追加することもできます。 たとえば、複数人による確認に準拠しているか、適切な追跡可能性があるかどうかです。
このラーニング パスを進めていくと、これらの手法の多くが実践されているのがわかります。
最後に、高品質のリリース プロセスを設計するときは、どのような種類のドキュメントやリリース ノートをユーザーに提供する必要があるかを考えてください。 ドキュメントを最新の状態に保つのが難しい場合があります。 Azure DevOps Release Note Generator などのツールを使用することをお勧めします。 このジェネレーターは、HTTP によってトリガーされる関数を含む関数アプリです。 Azure Blob Storage を使用することで、Azure DevOps に新しいリリースが作成されるたびに、マークダウン ファイルが作成されます。