段階的リリースが思っている以上に重要な理由

チームが新機能の開発に2週間を費やしたとしよう。コードレビューも済み、ステージング環境でのテストもパスした。すべて順調に見える。パイプラインを実行し、新しいバージョンが全サーバーにデプロイされ、すべてのユーザーが即座に新機能を利用できるようになる。

5分後、エラーレートが上昇し始める。10分後、ユーザーからメインページにアクセスできないとの報告が入る。慌ててロールバックを実行し、全員が旧バージョンに戻される。しかし、被害はすでに発生している。一部のユーザーは一時的にデータを失い、他のユーザーはエラーに遭遇し、アプリケーションへの信頼は損なわれる。

問題はコードの質ではなかった。問題は、どのようにリリースしたかにある。すべての変更が同時に全ユーザーに届く場合、新しいバージョンが本番環境で実際に動作するかどうかを確認する猶予がない。全員が影響を受ける前に、影響を確認する機会がないのだ。

これがビッグバンリリースと呼ばれるものだ。すべての変更が一度に、全ユーザーに対して、観測のための待機時間なしにリリースされる。回避が難しいリスクを伴う。

ステージング環境だけでは不十分な理由

ステージング環境が本番環境と完全に一致することは決してない。設定の違い、トラフィックパターン、実際のユーザーデータによって、本番環境でしか現れないギャップが生じる。テストは堅牢かもしれないが、それらは合成データとシミュレートされた動作に対して実行される。実際のユーザーは予期しない行動をとる。

また、ユーザーごとに利用パターンが異なる。あるグループには問題なく動作する機能でも、別のグループでは壊れる可能性がある。ヘビーユーザーはカジュアルユーザーが決してトリガーしないエッジケースに遭遇する。モバイルユーザーはデスクトップユーザーとは異なるネットワーク環境を持つ。単一のリリースはすべてのユーザーを同じように扱うが、ユーザーは同じではない。

ビッグバンリリースで問題が発生した場合、爆発範囲は広大だ。すべてのユーザーが影響を受け、すべてのセッションが影響を受ける。即座に修正しなければならないというプレッシャーは大きく、それが性急な判断とさらなるミスを招く。

代替案:プログレッシブデリバリー

新しいバージョンを全員に一度に送信する代わりに、段階的に送信する。まずはユーザーのごく一部から始める。様子を見る。問題がなければ、範囲を広げる。問題が発生した場合、影響を受けるのは少数のグループだけだ。

プログレッシブデリバリーは単一の手法ではない。以下のプラクティスの組み合わせである。

次のフローチャートは、段階的リリースの仕組みを、各ステップでの自動チェックとともに示している。

flowchart TD A[開始: 1%のユーザー] --> B[メトリクス監視] B --> C{すべて正常?} C -->|Yes| D[5%に増加] D --> E[メトリクス監視] E --> F{すべて正常?} F -->|Yes| G[10%に増加] G --> H[メトリクス監視] H --> I{すべて正常?} I -->|Yes| J[25%に増加] J --> K[メトリクス監視] K --> L{すべて正常?} L -->|Yes| M[50%に増加] M --> N[メトリクス監視] N --> O{すべて正常?} O -->|Yes| P[100%ロールアウト] C -->|No| Q[一時停止またはロールバック] F -->|No| Q I -->|No| Q L -->|No| Q O -->|No| Q
  • 新しいバージョンに流すトラフィックの割合を制御する
  • どのユーザーが最初に変更を確認するかを決定する
  • 特定のグループに対して機能をオン/オフする
  • メトリクスをリアルタイムで監視する
  • 収集したデータに基づいて自動的に判断する

目標はシンプルだ。露出を制限することでリスクを減らす。悪いリリースが5%のユーザーにしか影響を与えない場合、問題は管理可能だ。分析し、修正するかロールバックするかを判断し、慌てずに行動する時間がある。

段階的リリース中に制御できること

プログレッシブデリバリーは、リリース中に操作できるいくつかのレバーを提供する。それぞれを理解することで、状況に合った戦略を設計できる。

トラフィックシフトは、新しいバージョンに到達するユーザートラフィックの量を制御する。1%のトラフィックから始め、5%、20%、50%、そして最終的に100%へと移行する。各ステップで、露出を増やす前にデータを得る。

ユーザーターゲティングは、誰が最初に新しいバージョンを入手するかを選択できるようにする。内部ユーザー、ベータテスター、特定の地域のユーザーを早期導入者にできる。これにより、より広範なリリースの前に、管理されたグループからのフィードバックを得られる。

フィーチャーフラグは、デプロイとリリースを分離する。新しい機能をオフにした状態でコードをデプロイし、その後段階的に有効にできる。問題が発生した場合、デプロイ全体をロールバックすることなく、フラグをオフに切り替える。

環境ゲーティングは、本番環境に直接ジャンプしないことを意味する。まずカナリア環境にリリースし、次に本番環境の小さなサブセット、そしてより広範な本番環境へとリリースする。各環境が確信を深める。

プログレッシブデリバリーで重要なメトリクス

段階的にリリースしても、適切なシグナルを監視していなければ意味がない。監視なしでは、盲目的に進むことになる。

エラーレートは最も明白なメトリクスだ。5xxエラーやクライアントサイドの例外の急増は、何かがおかしいことを意味する。ただし、全体的なレートだけを見てはいけない。新しいバージョンと古いバージョンのエラーレートを比較する。0.5%のエラーレートは問題なさそうに見えるかもしれないが、古いバージョンが0.05%で動作していることがわかれば話は別だ。

応答時間は、エラーが発生する前に悪化することが多い。新しいバージョンが遅い場合、ユーザーはすぐに不満を言わないかもしれないが、気づく。平均だけでなく、p95およびp99レイテンシを追跡する。

ビジネスメトリクスは、機能が実際に機能しているかどうかを示す。コンバージョン率、サインアップ、購入、エンゲージメントメトリクスは、変更が価値を提供しているかどうかを示す。技術的に完璧なリリースでも、ビジネスメトリクスを損なうのであれば、依然として悪いリリースだ。

ユーザー報告の問題は遅いが価値がある。サポートチケット、ソーシャルメディアでの言及、内部レポートを監視する。自動監視が見逃す問題をユーザーが気づくことがある。

自律的に判断するパイプラインの構築

最も効果的なプログレッシブデリバリーパイプラインは、すべての判断を人間に委ねない。メトリクスに基づいてGo/No-Goチェックを自動化する。

実際の動作は次のとおりだ。

以下は、このプロセスを自動化するKubernetesコントローラーであるArgo Rolloutsを使用した具体例である。

apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
  name: my-service
spec:
  replicas: 10
  strategy:
    canary:
      steps:
        - setWeight: 5
        - pause: {duration: 10m}
        - analysis:
            templates:
            - templateName: success-rate
            args:
            - name: service-name
              value: my-service
        - setWeight: 20
        - pause: {duration: 10m}
        - analysis:
            templates:
            - templateName: success-rate
        - setWeight: 50
        - pause: {duration: 10m}
        - analysis:
            templates:
            - templateName: success-rate
        - setWeight: 100

この設定は、トラフィックを5%から100%へ段階的にシフトし、各ステップの後に一時停止して自動分析チェックを実行する。成功率がしきい値を下回った場合、ロールアウトは自動的に一時停止またはロールバックされる。

  1. パイプラインが新しいバージョンをサーバーまたはユーザーの小さなサブセットにデプロイする
  2. 監視システムが定義された期間(たとえば10分間)メトリクスを収集する
  3. 自動チェックがメトリクスをしきい値と比較する
  4. メトリクスが正常であれば、パイプラインはロールアウトの割合を増やす
  5. メトリクスがしきい値を超えた場合、パイプラインは自動的に一時停止またはロールバックする

これにより、問題を検出してから対処するまでの人間の遅延が排除される。就寝中や会議中でも、パイプラインはユーザーを保護し続ける。

しきい値は慎重に設定する必要がある。厳しすぎると、リリースをブロックする誤検出が発生する。緩すぎると、実際の問題を見逃す。控えめなしきい値から始め、経験に基づいて調整する。

次の段階的リリースのための実践的チェックリスト

プログレッシブデリバリーを実装する前に、このチェックリストを確認しよう。

  • アプリケーションの特定のバージョンにトラフィックをルーティングできるか?
  • エラーレート、レイテンシ、ビジネスメトリクスのリアルタイム監視はあるか?
  • 各メトリクスに対して明確なしきい値を定義しているか?
  • 部分的なリリースを、旧バージョンのユーザーに影響を与えずにロールバックできるか?
  • 特定のユーザーグループ(内部、ベータ、地域ベース)をターゲットにする方法はあるか?
  • パイプラインは自動的に一時停止またはロールバックできるか?
  • プログレッシブデリバリープロセスを非本番環境でテストしたか?

まとめ

ビッグバンリリースは、すべてのデプロイをギャンブルに変える。ステージングテストですべてをキャッチできたこと、本番環境がテスト環境とまったく同じように動作すること、すべてのユーザーが同じエクスペリエンスを得られること、これらに賭けている。これらの賭けは、チームが認める以上に頻繁に失敗する。

プログレッシブデリバリーはその方程式を変える。1回のリリースにすべてを賭ける代わりに、小さな賭けをして結果を確認し、さらに賭ける。問題が発生した場合、被害は封じ込められる。チームは冷静さを保ち、ユーザーは満足し、リリースプロセスは恐れるものではなく信頼できるものになる。

小さく始めよう。1つのサービスまたは1つの機能を選ぶ。トラフィックシフトと監視を設定する。次のリリースを段階的プロセスで実行する。得られる確信は、なぜ他の方法でリリースしていたのか疑問に思うほどになるだろう。