Microsoft による DevOps 開発手法
Microsoft は、One Engineering System を使用して、Git ブランチおよびリリース フローを中心とした堅実な DevOps プロセスですべての Microsoft 製品を構築および展開するよう努めています。 この記事では、実際の実装、小規模なサービスから大規模なプラットフォーム開発ニーズまでシステムがどのように拡張されるか、さまざまな Microsoft チームでシステムを使用することから得られる教訓に焦点を当てます。
標準化された開発プロセスの採用は野心的な取り組みです。 Microsoft 組織ごとに要件は大きく異なり、組織内のさまざまなチームの要件は規模と複雑さに応じて変化します。 これらのさまざまなニーズに対応するために、Microsoft はトランクベースの分岐戦略を使用して、製品を迅速に開発し、定期的に展開し、変更を運用環境に安全に配信できるようにしています。
Microsoft では、One Engineering System の一部としてプラットフォーム エンジニアリングの原則も使用しています。
Microsoft のリリース フロー
すべての組織は、チーム間の一貫性を確保するために、標準のコード リリース プロセスを確立する必要があります。 Microsoft のリリース フローには、開発からリリースまでの DevOps プロセスが組み込まれています。 リリース フローの基本的な手順は、ブランチ、プッシュ、プル リクエスト、マージで構成されます。
[Branch]\(ブランチ)
バグを修正したり機能を実装したりするには、開発者はメインの統合ブランチから新しいブランチを作成します。 Git の軽量ブランチ モデルは、コードのコントリビューションごとに、これらの短期間の topic ブランチを作成します。 開発者は機能フラグを使用して早期にコミットし、長時間実行される機能ブランチを回避します。
Push
開発者が変更を統合してチームの残りのメンバーに配布する準備ができたら、ローカル ブランチをサーバー上のブランチにプッシュし、プル リクエストを開きます。 多くのブランチで作業する数百人の開発者がいるリポジトリでは、混乱とブランチの急増を軽減するためにサーバー ブランチの命名規則を使用しています。 開発者は通常、users/<username>/feature
という名前のブランチを作成します (<username>
はアカウント名です)。
Pull request
プル リクエストは、メイン ブランチへのトピック ブランチのマージを制御し、ブランチ ポリシーが満たされていることを確認します。 プル リクエスト プロセスは、提案された変更を構築し、クイック テスト パスを実行します。 第 1 レベルと第 2 レベルのテスト スイートは、5 分以内に約 60,000 のテストを実行します。 これは完全な Microsoft テスト マトリックスではありませんが、プル リクエストにすぐに自信を与えるには十分です。
次に、チームの他のメンバーがコードをレビューし、変更を承認します。 コード レビューは自動テストが中断したところから再開され、アーキテクチャ上の問題を特定するのに特に役立ちます。 手動でコードをレビューすることで、チームの他のエンジニアが変更内容を確認できるようになり、コードの品質が高い状態に保たれます。
マージする
プル リクエストがすべてのビルド ポリシーを満たし、レビュー担当者がサインオフすると、トピック ブランチがメインの統合ブランチにマージされ、プル リクエストが完了します。
マージ後は、完了までにさらに時間がかかる他の受け入れテストが実行されます。 これらの従来のチェックイン後のテストでは、より徹底的な検証が行われます。 このテスト プロセスにより、プル リクエストのレビュー中の迅速なテストと、リリース前に完全なテストをカバーすることとの間で適切なバランスが得られます。
GitHub Flowとの違い
GitHub Flow は、組織が Git へのスケーラブルなアプローチを実装するための人気のある トランクベース開発 リリース フローです。 ただし、一部の組織は、ニーズが増大するにつれて、GitHub Flow の一部から逸脱する必要があることに気づきました。
たとえば、GitHub Flow で見落とされがちな点は、プル リクエストをメイン ブランチにマージする前に、テストのために本番環境にデプロイする必要があることです。 このプロセスは、すべてのプル リクエストがマージのためにデプロイメント キューで待機することを意味します。
一部のチームでは、数百人の開発者が 1 つのリポジトリで常に作業しており、1 日にメイン ブランチへの 200 件を超えるプル リクエストを完了できます。 各プル リクエストでテストのために世界中の複数の Azure データ センターにデプロイする必要がある場合、開発者はソフトウェアを作成する代わりに、ブランチがマージされるのを待つことに時間を費やすことになります。
代わりに、Microsoft チームはメイン ブランチで開発を継続し、通常は 3 週間のスプリント リズムに合わせて、展開を時限リリースにまとめます。
実装詳細
Microsoft リリース フローの主要な実装の詳細をいくつか示します。
Git リポジトリ戦略
チームが異なれば、Git リポジトリを管理するための戦略も異なります。 一部のチームは、コードの大部分を 1 つの Git リポジトリに保存しています。 コードはコンポーネントに分割され、それぞれが独自のルートレベルのフォルダーにあります。 大規模なコンポーネント、特に古いコンポーネントには、親コンポーネント内に個別のサブフォルダーを持つ複数のサブコンポーネントが含まれる場合があります。
付属リポジトリ
一部のチームは付属リポジトリも管理します。 たとえば、エージェント とタスク、VS Code 拡張機能、オープンソース プロジェクト のビルドとリリースは GitHub で開発されています。 構成の変更は別のリポジトリにチェックインされます。 チームが依存している他のパッケージは他の場所から取得され、NuGet 経由で使用されます。
モノリポジトリまたはマルチリポジトリ
一部のチームは単一のモノリシック リポジトリである モノリポジトリ を選択しますが、他の Microsoft 製品は マルチ リポジトリ アプローチを使用します。 たとえば、Skype には何百もの小さなリポジトリがあり、それらをさまざまな組み合わせでつなぎ合わせて、さまざまなクライアント、サービス、ツールを作成します。 特にマイクロサービスを採用しているチームにとって、マルチリポジトリは適切なアプローチとなる可能性があります。 通常、モノリスとして始まった古い製品は、モノリポジトリのアプローチが Git への最も簡単な移行であると考えており、コード構成はそれを反映しています。
リリース ブランチ
Microsoft のリリース フローでは、メイン ブランチがいつでもビルド可能な状態に保たれています。 開発者は、main
にマージされる短期間のトピック ブランチで作業します。 チームは、スプリントの終了時でもメジャー アップデートの場合でも、出荷の準備が整うと、メイン ブランチから新しいリリース ブランチを開始します。 リリース ブランチはメイン ブランチにマージして戻らないため、重要な変更を厳選する必要がある場合があります。
次の図では、存続期間の短いブランチが青色で、解放ブランチが黒色で示されています。 チェリーピッキングが必要なコミットを含む 1 つのブランチが赤色で表示されます。
ブランチのポリシーと権限
Git ブランチ ポリシーは、リリース ブランチ構造を強制し、メイン ブランチをクリーンに保つのに役立ちます。 たとえば、ブランチ ポリシーにより、メイン ブランチへの直接プッシュを防ぐことができます。
ブランチ階層を整理しておくために、チームはアクセス許可を使用して階層のルート レベルでブランチの作成をブロックします。 次の例では、誰もが users/、features/、teams/ などのフォルダーにブランチを作成できます。 リリース マネージャーのみが releases/ の下にブランチを作成する権限を持ち、一部の自動化ツールには integrations/ フォルダーへの権限があります。
Git リポジトリワークフロー
リポジトリとブランチ構造内で、開発者は日々の作業を行います。 労働環境はチームや個人によって大きく異なります。 コマンド ラインを好む開発者もいれば、Visual Studio を好む開発者もいますし、さまざまなプラットフォームで作業する開発者もいます。 Microsoft リポジトリに導入されている構造とポリシーにより、強固で一貫した基盤が確保されます。
一般的なワークフローには、次の一般的なタスクが含まれます。
新しい機能を構築する
新しい機能を構築することは、ソフトウェア開発者の仕事の中核です。 プロセスの Git 以外の部分には、テレメトリ データの確認、設計と仕様の考案、実際のコードの記述が含まれます。 次に、開発者は main
の最新のコミットと同期してリポジトリの操作を開始します。 メイン ブランチはいつでもビルド可能なため、優れた開始点となることが保証されています。 開発者は新しい機能ブランチをチェックアウトし、コードを変更し、コミットしてサーバーにプッシュし、新しいプル リクエストを開始します。
ブランチポリシーとチェックを使用する
プル リクエストの作成時に、自動システムは新しいコードがビルドされているか、何も壊れていないか、セキュリティ ポリシーやコンプライアンス ポリシーに違反していないかをチェックします。 このプロセスは、他の作業の並行実行を妨げません。
ブランチポリシーとチェックは、プルリクエストを完了させる前に、テストの合格を含むビルドの成功、タッチしたコードのオーナーによるサインオフ、企業ポリシーを確認するためのいくつかの外部チェックを要求できます。
Microsoft Teams との統合
多くのチームはMicrosoft Teamsとの統合を設定し、新しいプルリクエストを開発者のチームメイトに知らせます。 タッチされたコードの所有者は自動的にレビュー担当者として追加されます。 Microsoft チームは、REST クライアントの生成や共有コントロールなど、多くの人が触れるコードに対してオプションのレビュー担当者を使用して、それらの変更について専門家の目を得ることがよくあります。
機能フラグを使用してデプロイする
レビュー担当者、コード所有者、自動化が満足すると、開発者はプル リクエストを完了できます。 マージの競合がある場合、開発者は競合を同期し、修正し、変更を再プッシュする方法についての指示を受け取ります。 自動化は修正されたコードで再度実行されますが、人間が再度サインオフする必要はありません。
ブランチは main
にマージされ、新しいコードは次のスプリントまたはメジャー リリースにデプロイされます。 だからといって、新機能がすぐに登場するわけではありません。 Microsoft は、機能フラグ を使用して、新機能の展開と公開を分離します。
機能を公開する準備が整うまでにもう少し作業が必要な場合でも、製品がビルドしてデプロイされたら、main
に進むのが安全です。 main
に入ると、コードは正式なビルドの一部となり、そこで再度テストされ、ポリシーを満たすことが確認され、デジタル署名されます。
問題を早期に検出するには左にシフトしてください
この Git ワークフローにはいくつかの利点があります。 まず、単一のメインブランチを運営することで、マージ負債が事実上排除されます。 次に、プル リクエスト フローは、パイプラインの初期段階でテスト、コード レビュー、エラー検出を強制するための共通ポイントを提供します。 このシフトレフト戦略は、数時間や数日ではなく数分でエラーを検出できるため、開発者へのフィードバック サイクルを短縮するのに役立ちます。 この戦略では、すべての変更が常にテストされるため、リファクタリングに対する信頼性も得られます。
現在、200 件以上のプル リクエストがある製品では、1 日あたり 300 件以上の継続的インテグレーション ビルドが生成され、24 時間ごとに 500 件以上のテストが実行されることになります。 このレベルのテストは、トランクベースの分岐とリリースのワークフローがなければ不可能です。
スプリントマイルストーンでリリース
各スプリントの終了時に、チームはメイン ブランチからリリース ブランチを作成します。 たとえば、スプリント 129 の終わりに、チームは新しいリリース ブランチ releases/M129
を作成します。 その後、チームは sprint 129 ブランチを実稼働環境に導入します。
リリース ブランチのブランチの後、開発者が変更をマージできるようにメイン ブランチが開いたままになります。 これらの変更は、3 週間後の次のスプリント デプロイメントでデプロイされます。
ホットフィックスをリリースする
場合によっては、変更を迅速に本番環境に反映する必要があります。 Microsoft は通常、スプリントの途中で新機能を追加することはありませんが、ユーザーのブロックを解除するためにバグ修正をすぐに導入したい場合があります。 問題はタイプミスなどの軽微なものである場合もあれば、可用性の問題やライブ サイト インシデントを引き起こすほど大きなものである場合もあります。
これらの問題の修正は、通常のワークフローから始まります。 開発者は main
からブランチを作成し、コードレビューを受けて、プルリクエストを完了してマージします。 プロセスは常に、最初に main
を変更することから始まります。 これにより、リリース ブランチに切り替えることなく、修正を迅速に作成し、ローカルで検証できるようになります。
このプロセスに従うと、変更が main
に入ることが保証されますが、これは重要です。 変更を main
に戻さずにリリース ブランチのバグを修正すると、スプリント 130 リリースが main
から分岐する次のデプロイメント中にバグが再発することになります。 停止中に生じる可能性のある混乱とストレスの間、main
の更新を忘れがちです。 最初に main
に変更を加えるということは、常にメイン ブランチとリリース ブランチの両方に変更が含まれることを意味します。
Git の機能により、このワークフローが可能になります。 変更をすぐに運用環境に反映するには、開発者がプル リクエストを main
にマージしたら、プル リクエスト ページを使用して変更をリリース ブランチに選択できます。 このプロセスでは、リリース ブランチをターゲットとする新しいプル リクエストを作成し、main
にマージしたばかりのコンテンツをバックポートします。
チェリーピック機能を使用すると、プル リクエストが迅速に開かれ、ブランチ ポリシーの追跡可能性と信頼性が提供されます。 リリース ブランチをローカル コンピューターにダウンロードすることなく、サーバー上でチェリーピッキングを行うことができます。 変更を加えたり、マージ競合を修正したり、2 つのブランチ間の違いに起因する小さな変更を行ったりすることはすべてサーバー上で発生する可能性があります。 チームはブラウザベースのテキスト エディタから直接変更を編集することも、Pull Request Merge Conflict Extension を使用してより高度なエクスペリエンスを使用して変更を編集することもできます。
プル リクエストがリリース ブランチをターゲットにすると、チームはコードを再度レビューし、ブランチ ポリシーを評価し、プル リクエストをテストしてマージします。 マージ後、修正は数分以内にサーバーの最初のリングに展開されます。 そこから、チームは展開リングを使用して、より多くのアカウントに修正を段階的に展開します。 変更がより多くのユーザーに展開されるにつれて、チームは成功を監視し、変更によってバグが修正され、不備や速度低下が生じないことを確認します。 この修正は最終的にすべての Azure データ センターに展開されます。
次のスプリントに進む
次の 3 週間で、チームはスプリント 130 への機能の追加を完了し、それらの変更をデプロイする準備を整えます。 新しいリリース ブランチ main
から releases/M130
を作成し、そのブランチをデプロイします。
この時点で、実際には 2 つのブランチが運用環境にあります。 リングベースのデプロイメントを使用して変更を運用環境に安全に反映すると、高速リングはスプリント 130 の変更を取得し、新しい変更が運用環境で検証される間、低速リング サーバーはスプリント 129 に留まります。
デプロイメントの途中で変更をホットフィックスするには、スプリント 129 リリースとスプリント 130 リリースという 2 つの異なるリリースにホットフィックスを適用する必要がある場合があります。 チームはホットフィックスを両方のリリース ブランチに移植して展開します。 130 ブランチは、すでにアップグレードされているリングにホットフィックスを再デプロイします。 129 ブランチは、次のスプリントのバージョンにまだアップグレードされていない外側のリングにホットフィックスを再デプロイします。
すべてのリングがデプロイされると、古いスプリント 129 ブランチは放棄されます。これは、ホットフィックスとしてスプリント 129 ブランチに加えられた変更も main
で行われたためです。 したがって、それらの変更は releases/M130
ブランチにも反映されます。
まとめ
リリース フロー モデルは、Microsoft が DevOps を使用してオンライン サービスを提供する開発を行う方法の中心です。 このモデルは、シンプルなトランクベースの分岐戦略を使用します。 しかし、Microsoft のリリース フローにより、開発者は展開キューに留まり、変更がマージされるのを待たずに作業を続けることができます。
このリリース モデルでは、Microsoft コードベースのサイズやそこで作業する開発者の数に関係なく、Azure データ センター全体に定期的に新機能をデプロイすることもできます。 このモデルでは、ホットフィックスを迅速かつ効率的に運用環境に導入することもできます。