グリーンパイプラインが健全なデプロイを意味しない理由
デプロイが完了しました。パイプラインはグリーンを示しています。すべてのビルドステップが成功し、すべてのテストがクリーンに通り、デプロイスクリプトもエラーなく完了しました。あなたは満足してラップトップを閉じます。
そこに最初のユーザーレポートが届きます。アプリの読み込みが遅い。一部のリクエストが失敗している。数分後にはデータベース接続プールが枯渇し、アプリは実質的にダウンしています。
何が起きたのでしょうか?パイプラインはすべて問題ないと言っていたのに。
このシナリオは、ほとんどのチームが認めたがる以上に頻繁に発生します。ビルドが成功したということは、コードがコンパイルまたはパッケージ化できたことを証明するだけです。アプリケーションが実際にリクエストを受け付け、データベースに接続し、正しいレスポンスを返せることを証明するものではありません。「デプロイが完了した」と「アプリケーションが動作している」の間にはギャップがあります。そのギャップを埋めるのがヘルスシグナルです。
ヘルスシグナルが実際に教えてくれること
ヘルスシグナルとは、アプリケーションが自身の状態を報告する方法です。最も一般的な形式はヘルスエンドポイントです。パイプライン、ロードバランサー、運用チームがアプリの機能を確認するために呼び出す専用のURLです。/health や /healthz という名前のエンドポイントを見たことがあるでしょう。呼び出されると、正常なアプリケーションはHTTP 200を返します。異常がある場合は500やその他のエラーコードを返します。
しかし、本当の価値はエンドポイント自体ではなく、エンドポイントが実際に何をチェックするかにあります。アプリケーションの実際の状態に関係なく常に200を返すヘルスエンドポイントは、ヘルスチェックがないよりも悪いです。誤った自信を与えます。パイプラインはデプロイが成功したと思い込む一方で、ユーザーはすでにエラーに直面しています。
Readiness vs Liveness:2つの異なる質問
ヘルスチェックには2つの異なる種類があり、それぞれ異なる質問に答えます。
次のフローチャートは、LivenessチェックとReadinessチェックの違いと、それらがデプロイ判断にどのように影響するかを示しています。
Readiness は、アプリケーションがトラフィックを受け入れる準備ができているかどうかをシステムに伝えます。アプリケーションが起動したばかりの場合、データベースへの接続、キャッシュのロード、コネクションのウォームアップに数秒かかることがあります。その間、アプリは「準備ができていない」と報告する必要があります。ロードバランサーやオーケストレーターは、アプリが準備完了を知らせるまでリクエストの送信を保留します。適切なReadinessチェックがないと、ユーザーは初期化が不完全なアプリケーションにアクセスし、エラーやタイムアウトが発生する可能性があります。
Liveness は、アプリケーションがまだ生きていて処理を実行しているかどうかをシステムに伝えます。アプリケーションがデッドロックに陥ったり、メモリを使い果たしたり、作業を処理できない状態になった場合、Livenessチェックがそれを検出します。Kubernetesのようなコンテナ化環境では、Livenessチェックの失敗は通常、自動再起動をトリガーします。
両方のチェックは、デプロイパイプラインにおいて異なる目的を果たします。デプロイを実行するとき、パイプラインは通常、最初にReadinessチェックを呼び出します。新しいバージョンが妥当な時間内に準備完了にならない場合、パイプラインは即座にロールバックを決定できます。これは、中途半端なバージョンをユーザーに提供するよりはるかに優れています。一方、Livenessチェックはデプロイが完了した後に特に役立ちます。アプリケーションを長期間にわたって健全に稼働させ続けます。
以下は、Kubernetesデプロイメント用に両方のプローブを設定する実践的なYAML例です。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
spec:
containers:
- name: app
image: my-app:1.0.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3
livenessProbe:
httpGet:
path: /live
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
failureThreshold: 3
この例では、Readiness Probeは5秒の遅延後、10秒ごとに/readyをチェックします。3回失敗すると、KubernetesはそのPodへのトラフィック送信を停止します。Liveness Probeは/liveをより低い頻度でチェックし、失敗した場合はコンテナを再起動します。
優れたヘルスチェックが実際にチェックするもの
何も検証せずに200を返すだけのヘルスチェックは、飾りに過ぎず、シグナルではありません。意味のあるヘルスチェックは、アプリケーションが機能するために重要なコンポーネントをテストする必要があります。
- データベース接続性:アプリがデータベースに到達し、簡単なクエリを実行できるか?
- 重要な外部API:アプリが依存するサービスは利用可能か?
- 内部リソース:スレッドプールは健全か?メモリ使用量は制限内か?
しかし、トレードオフがあります。すべての依存関係を毎回テストするヘルスチェックは、システムに負担をかける可能性があります。パイプラインやロードバランサーが数秒ごとにエンドポイントを呼び出す場合、重いチェックはパフォーマンスを低下させたり、カスケード障害を引き起こしたりする可能性があります。
一般的なパターンは、Livenessチェックを軽量に保つことです。プロセスが実行中であることを確認するだけです。Readinessチェックはより深くできます。呼び出し頻度が低く、その結果がインスタンスにトラフィックをルーティングするかどうかに直接影響するからです。
プログレッシブデプロイ戦略におけるヘルスシグナル
カナリアリリースやブルーグリーンデプロイのようなデプロイ戦略を使用する場合、ヘルスシグナルはさらに重要になります。新しいバージョンを少数のユーザーにロールアウトする場合を想像してください。パイプラインはその新しいバージョンのヘルスエンドポイントを監視できます。ヘルスチェックがエラーを示し始めたり、応答時間が増加したりした場合、パイプラインは自動的にトラフィックを古いバージョンに戻すことができます。
ヘルスシグナルがなければ、ユーザーレポートに頼ることになります。ユーザーレポートは貴重ですが、遅れて届きます。誰かがバグレポートを提出する頃には、多くのユーザーがすでに影響を受けている可能性があります。数秒ごとに実行されるヘルスチェックは、問題を数分や数時間ではなく、数秒以内にキャッチできます。
ヘルスチェックがない、または弱い場合に起こること
適切なヘルスチェックを省略したチームは、しばしば困難な方法で問題を発見します。デプロイは成功しますが、新しいバージョンは認証情報が変更されたためにデータベースに接続できません。パイプラインは成功を報告します。ユーザーはエラーを目にします。誰かが手動で調査し、問題を認識し、ロールバックをトリガーする必要があります。そのプロセスには時間がかかり、その間アプリケーションは劣化した状態です。
依存関係についても同じことが言えます。アプリケーションが外部APIに依存しており、そのAPIがダウンした場合、適切なヘルスチェックはアプリケーションを異常として報告します。弱いヘルスチェックは正常と報告し、モニタリングダッシュボードが緑色を示している間にユーザーは障害を経験します。
実践的なクイックチェックリスト
アプリケーションにヘルスチェックを設定する場合、確認すべき短いリストを以下に示します。
- ヘルスエンドポイントは実際に意味のあるものをチェックしていますか?それとも単に200を返しているだけですか?
- 異なる深さのReadinessチェックとLivenessチェックを分離して設定していますか?
- パイプラインはReadinessチェックを使用して、デプロイを続行するかロールバックするかを判断していますか?
- ヘルスチェックは、頻繁に呼び出されたときにパフォーマンスを低下させない程度に軽量ですか?
- プログレッシブデプロイ戦略は、問題を早期に検出するためにヘルスシグナルを使用していますか?
デプロイの真のテスト
グリーンパイプラインは、アプリケーションが動作するという証明ではありません。ビルドとデプロイのプロセスがエラーなく実行されたという証明です。真のテストはデプロイ後、トラフィックが新しいバージョンに到達したときに行われます。ヘルスシグナルは、「デプロイが完了した」と「アプリケーションが実際にユーザーに正しくサービスを提供している」の間の橋渡しです。
パイプラインが新しいバージョンが健全でないことを数秒以内に検出し、自動的にロールバックできるようになれば、デプロイがうまくいくことを願う状態から、安全であることを知っている状態に移行できます。それが、紙の上では良さそうに見えるデプロイと、実際に本番環境で機能するデプロイの違いです。