アプリケーションのデプロイとテストの戦略

Last reviewed 2023-07-20 UTC

このドキュメントでは、一般的に使用されるアプリケーションのデプロイとテストのパターンの概要について説明します。各パターンがどのように機能するか、各パターンの利点、各パターンを実装する際の考慮事項について解説しています。

実行中のアプリケーションを新しいバージョンにアップグレードするとします。シームレスなロールアウトを実現するために、通常は以下の項目を検討します。

  • (ダウンタイムがある場合)アプリケーションのダウンタイムを最小限に抑える方法。
  • ユーザーへの影響を最小限に抑えながらインシデントを管理、解決する方法。
  • 失敗したデプロイを確実かつ効果的に処理する方法。
  • ヒューマン エラーや処理エラーを最小限に抑えて、予測可能かつ繰り返し可能なデプロイを実現する方法。

どのデプロイ パターンを選択するかは、ビジネス目標に大きく依存します。たとえば、ダウンタイムなしで変更をロールアウトする必要がある場合もあれば、機能を一般提供する前に何かしらの環境や一部のユーザーに変更をロールアウトする必要がある場合もあります。このドキュメントで説明する各方法では、デプロイを成功したとみなすために達成する必要がある特定の目標について説明します。

このドキュメントは、さまざまなアプリケーション、システム、フレームワークのリリースおよびデプロイ戦略の定義と実装に取り組むシステム管理者と DevOps エンジニアを対象としています。

デプロイ戦略

サービスをデプロイしても、直ちにユーザーに公開されるとは限りません。また、サービスがリリースされた後でないと、ユーザーがアプリケーションの変更点を確認できないこともあります。ですが、サービスがインプレースでリリースされる場合、デプロイとリリースは同時に行われます。この場合、新しいバージョンをデプロイすると、そのバージョンは本番環境トラフィックの受け入れを開始します。また、複数のサービス バージョンを同時にプロビジョニングするデプロイ戦略もあります。このデプロイ パターンを使用すると、受信リクエストを受信するバージョンの制御と管理が可能になります。デプロイ、リリース、および関連するコンセプトの詳細については、Kubernetes と継続的ソフトウェア デリバリーの課題をご覧ください。

このセクションで説明するデプロイ パターンを使用すれば、新しいソフトウェアのリリースを柔軟に自動化できます。どの方法が最適かは、何を目的とするかによって異なります。

デプロイの再作成パターン

デプロイの再作成では、新しいアプリケーション バージョンをスケールアップする前に、既存のアプリケーション バージョンを完全にスケールダウンします。

次の図は、アプリケーションに対するデプロイの再作成アプローチがどのように機能するかを示しています。

デプロイの再作成のフロー。

バージョン 1 は現在のアプリケーション バージョンを表し、バージョン 2 は新しいアプリケーション バージョンを表します。現在のアプリケーション バージョンを更新する際、最初に既存のバージョン 1 のレプリカをゼロにスケールダウンしてから、新しいバージョンのレプリカを同時にデプロイします。

主な利点

再作成アプローチの利点は、そのシンプルさです。複数のアプリケーション バージョンを同時に管理する必要がないため、データとアプリケーションの下位互換性の問題を回避できます。

考慮事項

再作成アプローチでは、更新プロセス中にダウンタイムが発生します。メンテナンスの時間枠や停止に対応できるアプリケーションであれば、ダウンタイムは問題になりません。ですが、サービスレベル契約(SLA)と可用性の要件が厳しいミッション クリティカルなアプリケーションの場合は、別のデプロイ戦略も検討してください。

ローリング アップデートによるデプロイ パターン

ローリング アップデートによるデプロイでは、次の図に示すように、すべてのアプリケーション インスタンスを同時に更新するのではなく、実行中のアプリケーション インスタンスのサブセットを更新します。

ローリング アップデートによるデプロイのフロー。

このデプロイ方法では、同時に更新するインスタンスの数をウィンドウ サイズと呼びます。上の図のローリング アップデートでは、ウィンドウ サイズは 1 です。一度につき 1 つのアプリケーション インスタンスが更新されます。クラスタが大きい場合は、ウィンドウ サイズを大きくします。

ローリング アップデートでは、アプリケーションを柔軟に更新できます。

  • 古いバージョンをスケールダウンする前に、新しいバージョンのアプリケーション インスタンスをスケールアップできます(サージ アップグレードと呼ばれるプロセス)。
  • 新しいインスタンスを同時にスケールアップする際に使用不可となるアプリケーション インスタンスの最大数を指定できます。

主な利点

  • ダウンタイムなし。ウィンドウ サイズに基づいて、デプロイ ターゲットを段階的に(1 つずつ、2 つずつなど)更新します。アプリケーションの新しいバージョンがトラフィックを受け入れる準備ができてから、更新されたデプロイ ターゲットにトラフィックを転送します。
  • デプロイリスクの軽減。アップデートを徐々にロールアウトするため、新しいバージョンに含まれる不安定さはごく一部のユーザーのみにしか影響しません。

考慮事項

  • ロールバックが遅い。新しいリリースが不安定な場合、新しいレプリカを終了して古いバージョンを再デプロイできます。ただし、ロールアウトと同様に、ロールバックは徐々に行われます。
  • 下位互換性。新しいコードと古いコードが並べて表示されるため、ユーザーがランダムにどちらかのバージョンへとルーティングされる可能性があります。そのため、新しいデプロイに下位互換性があることを確認してください。つまり、新しいアプリケーション バージョンで、古いバージョンに保存されているデータの読み取りや処理ができることを確認してください。このデータには、ディスク、データベース、またはユーザーのブラウザ セッションの一部として保存されたデータが含まれます。
  • スティッキー セッション。アプリケーションでセッションの永続性が必要な場合は、ロードバランサで固定コネクション ドレインをサポートすることをおすすめします。また、可能な場合はセッション共有を呼び出して(セッション レプリケーションやデータストアを使用したセッション管理を通じて)、セッションを基盤となるリソースから分離できるようにすることをおすすめします。

Blue/Green デプロイ パターン

Blue/Green デプロイ(Red/Black デプロイとも呼ばれます)では、次の図に示すように、2 つの同一のアプリケーションのデプロイを行います。

Blue/Green デプロイのフロー。

この図では、青色が現在のアプリケーションのバージョンを表し、緑色が新しいアプリケーションのバージョンを表します。一度に公開できるバージョンは 1 つのみです。トラフィックは青色のデプロイにルーティングされます。その間に、緑色のデプロイが作成されてテストされます。テストが完了したら、トラフィックを新しいバージョンに転送します。

デプロイが成功したら、青色のデプロイをロールバック先として保持するか、または終了させます。また、これらのインスタンスに新しいバージョンのアプリケーションをデプロイすることもできます。この場合、現在の(青色の)環境が次のリリースのステージング領域として機能します。

主な利点

  • ダウンタイムなし。Blue/Green デプロイでは、ダウンタイムなしで迅速にカットオーバーできます。
  • 即時ロールバック。ロードバランサを調整してトラフィックを青色の環境にルーティングし直すことで、デプロイ プロセス中にいつでもロールバックできます。ダウンタイムの影響は、問題を検出してからトラフィックを青色の環境に切り替える際にかかる時間に限定されます。
  • 環境の分離。Blue/Green デプロイでは、緑色の環境を同時に起動しても、青色の環境をサポートするリソースが影響を受けないことが保証されています。この分離により、デプロイリスクが軽減されます。

考慮事項

  • コストと運用上のオーバーヘッド。Blue/Green デプロイ パターンを使用する場合、重複する環境を同じインフラストラクチャ上で維持する必要があります。そのため、運用上のオーバーヘッドとコストが増加する可能性があります。
  • 下位互換性。青色のデプロイと緑色のデプロイで、データポイントとデータストアを共有できます。アプリケーションの両方のバージョンで、データストアのスキーマとレコードの形式を使用できることを確認することをおすすめします。この下位互換性は、ロールバックが必要となった際に 2 つのバージョンをシームレスに切り替えるときに必要となります。
  • カットオーバー。現在のバージョンを廃止する場合は、既存のトランザクションとセッションで適当なコネクション ドレインを有効にすることを推奨します。この手順により、現在のデプロイで処理されたリクエストを正常に完了、または終了できます。

テスト戦略

このセクションで説明するテストパターンは通常、同時実行と負荷の現実的なレベルでの妥当な期間におけるサービスの信頼性と安定性を検証するために使用されます。

カナリアテスト パターン

カナリアテストでは、次の図に示すように、変更の一部をロールアウトして、そのパフォーマンスをベースライン デプロイと比較することで評価します。

カナリアテストの構成。

このテストパターンでは、新しいバージョンのアプリケーションを本番環境バージョンと一緒にデプロイします。次に、トラフィックの一部を分割して本番環境バージョンからカナリア バージョンに転送し、カナリアのパフォーマンスを評価します。

カナリアの構成時、評価用の主要な指標を選択します。実際の本番環境ではなく、それに相当するベースラインとカナリアを比較することを推奨します。

分析に影響する可能性のある因子(キャッシュ、長時間接続、ハッシュ オブジェクトなど)を減らすために、アプリケーションのベースライン バージョンで次の手順を行うことをおすすめします。

  • アプリケーションのベースライン バージョンと本番環境バージョンが同じであることを確認します。
  • カナリアのデプロイと同時に、ベースライン バージョンをデプロイします。
  • ベースライン デプロイ(アプリケーション インスタンスの数や自動スケーリング ポリシーなど)がカナリア デプロイと一致していることを確認します。
  • ベースライン バージョンを使用して、カナリアと同じトラフィックを配信します。

カナリアテストでは、さまざまなパーティショニング戦略で部分的なロールアウトを行うことができます。たとえば、アプリケーションのユーザーが地理的に分散している場合に、新しいバージョンの特定のリージョンや特定のロケーションへのロールアウトから始めることができます。詳細については、Spinnaker を使用した GKE のカナリア分析の自動化をご覧ください。

主なメリット

  • 本番環境トラフィックでテスト可能。ステージング環境でシミュレートされたトラフィックを使用してアプリケーションをテストするのではなく、本番環境トラフィックでカナリアテストを実行できます。カナリア ロールアウトでは、新しいアプリケーションをリリースする際の増分と、リリースの次のステップをトリガーするタイミングを決定する必要があります。カナリアテストでは、モニタリング機能が問題を明確に検出できるようにする必要があるため、十分な量のトラフィックが必要になります。
  • 高速ロールバック。ユーザー トラフィックを古いバージョンのアプリケーションにリダイレクトすることで、すぐにロールバックできます。
  • ダウンタイムなし。カナリア リリースでは、本番環境トラフィックをダウンタイムなしでさまざまなバージョンのアプリケーションに転送できます。

考慮事項

  • ロールアウトが遅い。リリースの各段階で、適当な期間のモニタリングが必要となります。そのため、全体としてのリリースが遅れる場合があります。カナリアテストに数時間かかる場合もあります。
  • オブザーバビリティ。カナリアテストを実装するためには、インフラストラクチャとアプリケーション スタックを効果的に観察、モニタリングする機能が必要です。堅牢なモニタリング機能を実装する場合、かなりの労力が必要となることがあります。
  • 下位互換性とスティッキー セッション。ローリング アップデートと同様に、カナリアがデプロイされている間に複数のアプリケーション バージョンが環境内で実行されるため、カナリアテストは下位互換性とセッションの永続性にリスクをもたらす可能性があります。

A/B テストパターン

A/B テストでは、バリアント実装を使用して仮説をテストします。A/B テストは、データから得られた結果に基づいて(予測だけでなく)ビジネス上の意思決定を行う際に使用されます。

A/B テストを実行すると、次の図に示すように、ルーティング ルールに基づいてユーザーのサブセットが新しい機能に転送されます。

A/B テストの構成。

多くの場合、ルーティング ルールにはブラウザのバージョン、ユーザー エージェント、位置情報、オペレーティング システムなどといった因子が含まれます。2 つのバージョンを測定して比較した後、より良い結果が得られたバージョンで本番環境を更新します。

主な利点

A/B テストは、アプリケーション機能の効果を測定するのに最適です。前述したデプロイ パターンのユースケースでは、新しいソフトウェアを安全にリリースし、予測可能な形でロールバックすることに重点を置いています。A/B テストでは、新機能のターゲット ユーザーを管理して、ユーザーの行動における統計的に有意な差異をモニタリングします。

考慮事項

  • 複雑な設定。A/B テストでは、あるバージョンが他のバージョンよりも優れているということの裏付けとなる、