スモークテストとシンセティックトランザクション:デプロイが実際に機能していることを確認する

パイプラインがグリーンになったのを見たばかりでしょう。ユニットテストも統合テストも、E2Eテストもすべてパスしました。デプロイを実行し、プログレスバーが完了し、パイプラインは成功を報告します。しかし、ここに厄介な真実があります。それらのテストはどれも、実際の本番環境では実行されていません。すべて別の場所(CIランナー、ステージングサーバー、ローカルマシン)で実行されました。アプリケーションが実際のインフラにデプロイされた瞬間、すべてが壊れる可能性はまだあります。

これこそが、スモークテストとシンセティックトランザクションが存在する理由です。これらは既存のテストスイートの代替ではありません。これらは別のレイヤーであり、「コードは正しいか?」ではなく、「デプロイは実際に成功したか?」という異なる問いに答えます。

最もシンプルなチェック:スモークテスト

スモークテストは、デプロイ後に行う最も基本的な確認です。それは一つの問いに答えます:アプリケーションは起動して応答しているか?

データセンターで新しいサーバーラックの電源を入れるときを考えてみてください。本格的なワークロードを実行する前に、電源ランプが点灯しているか、ファンが回っているか、管理インターフェースにpingが通るかを確認します。フルベンチマークは実行しません。単に電源が入っていることを確認するだけです。

Webアプリケーションの場合、スモークテストはヘルスチェックエンドポイントへの単一のHTTPリクエストかもしれません。バックエンドサービスの場合、プロセスが実行中で期待されるポートで待機していることを確認することかもしれません。モバイルアプリの場合、実機でアプリがクラッシュせずに起動することを確認することかもしれません。

優れたスモークテストの主な特徴は、速度とシンプルさです。数分ではなく、数秒で完了する必要があります。複雑なビジネスロジックや、一時的に利用できなくなる可能性のある外部システムに依存すべきではありません。スモークテストにデータベース接続、キャッシュサーバー、3つのサードパーティAPIが必要なら、それはもはやスモークテストではなく、まったく別のものです。

以下は、実用的なスモークテストとシンセティックトランザクションをbashで示したものです:

# スモークテスト:クイックヘルスチェック
curl -f -s -o /dev/null http://myapp.com/health || exit 1

echo "Smoke test passed"

# シンセティックトランザクション:ユーザーログインと検索をシミュレート
#!/bin/bash
set -e

BASE="http://myapp.com"

# ステップ1: ログインページを読み込む
curl -s -o /dev/null -w "%{http_code}" "$BASE/login" | grep -q 200 || exit 1

# ステップ2: ログインフォームを送信(シミュレート)
curl -s -c /tmp/cookies.txt -b /tmp/cookies.txt \
  -d "username=testuser&password=testpass" \
  -o /dev/null -w "%{http_code}" "$BASE/login" | grep -q 302 || exit 1

# ステップ3: 商品を検索
curl -s -b /tmp/cookies.txt "$BASE/search?q=laptop" | grep -q "results" || exit 1

echo "Synthetic transaction passed"

スモークテストは、デプロイ直後、新しいバージョンにトラフィックがルーティングされる前に配置してください。スモークテストが失敗した場合、パイプラインは即座に停止する必要があります。より深いチェックに進んではいけません。ユーザートラフィックをルーティングしてはいけません。デプロイは最も基本的なレベルで失敗しており、それが解決されるまで他のことは重要ではありません。

より深く:シンセティックトランザクション

シンセティックトランザクションは、検証をさらに一歩進めます。アプリケーションが生きていることを確認するだけでなく、実際のユーザー行動をシミュレートします。実際のユーザーが行うようにアプリケーションのクリティカルパスをウォークスルーしますが、パイプラインによってトリガーされ自動的に実行されます。

Eコマースアプリケーションを想像してみてください。シンセティックトランザクションは次のことを行うかもしれません:

  1. ホームページを開く
  2. 商品を検索する
  3. 商品をカートに追加する
  4. チェックアウトに進む
  5. 購入フローを完了する

各ステップで、レスポンスが正しいこと、ページが適切に読み込まれること、カートに実際に正しいアイテムが含まれていること、注文確認が表示されることをチェックします。いずれかのステップが失敗した場合、シンセティックトランザクションは失敗します。

シンセティックトランザクションはスモークテストよりもコストがかかります。実行に時間がかかり(数秒ではなく数分になることが多い)、システムのより多くの部分が正しく動作することに依存します。しかし、スモークテストでは捕捉できない問題を発見します。

よくあるシナリオ:ヘルスチェックエンドポイントが200 OKを返すため、スモークテストはパスします。しかし、デプロイ中に設定ファイルが正しくコピーされなかったため、ログインページが500エラーを返します。スモークテストはログインページをチェックしませんでした。シンセティックトランザクションはそれを即座に捕捉します。

パイプラインにおける位置づけ

スモークテストとシンセティックトランザクションは異なる目的を持ち、デプロイパイプラインの異なる段階に配置されるべきです。

スモークテストは最初に、デプロイ完了直後に配置します。これはゲートキーパーです。アプリケーションが実行すらしていなければ、他の何かを実行する意味はありません。パイプラインは迅速に失敗し停止すべきです。

シンセティックトランザクションはスモークテストがパスした後に実行します。これはユーザートラフィックが到着する前の、より深い検証です。シンセティックトランザクションが失敗した場合、ユーザーが問題に遭遇する前にデプロイを停止する時間がまだあります。

実際には、多くのシンセティックトランザクションは必要ありません。最もクリティカルなユーザージャーニーをカバーする2〜5のシナリオで通常は十分です。目標は網羅的なテストではありません(それはデプロイ前に行っています)。目標は、デプロイ自体が何も壊していないことを確認することです。

これらのテストが他のテストでは見逃すもの

デプロイ前のテストは管理された環境で実行されます。テストデータベース、モックサービス、本番とは異なる可能性のある設定ファイルを使用します。ステージング環境が本番を綿密にミラーリングしている場合でも、違いは存在します。

スモークテストとシンセティックトランザクションは実際の本番環境で実行されます。それらはそこにしか現れない問題を捕捉します:

  • ステージングと本番の間の環境設定の違い
  • 本番環境での依存関係の欠落や誤ったバージョン
  • 本番アカウントまたはクラスターにのみ存在する権限の問題
  • 正当なトラフィックをブロックするネットワークポリシー
  • SSL証明書の問題
  • ロードバランサーの設定ミス
  • 実際の条件下でのデータベース接続プールの枯渇

これらは理論上の問題ではありません。あらゆる規模のチームで定期的に発生します。ステージングでは完全に機能する設定値が本番ではタイポがある。ステージングではローテーションされたシークレットが本番ではされていない。新しいサービスのポートをブロックするファイアウォールルール。これらの問題は、実際の環境に対して実行されないため、デプロイ前のテストでは決して捕捉されません。

実践的なチェックリスト

パイプラインにスモークテストとシンセティックトランザクションを実装する際は、以下の点に留意してください:

  • スモークテストは10秒未満に抑える。それ以上かかる場合は、簡略化する。
  • スモークテストはデプロイ直後、トラフィックルーティングの前に配置する。
  • スモークテストが失敗したらパイプラインを失敗させる。先に進まない。
  • シンセティックトランザクションはスモークテストがパスした後、完全なトラフィックカットオーバーの前に実行する。
  • シンセティックトランザクションは2〜5のクリティカルなユーザージャーニーに制限する。
  • 網羅的なテストにシンセティックトランザクションを使用しない。それはデプロイ前のテストの役割です。
  • シンセティックトランザクションの結果を経時的に監視する。断続的な失敗のパターンは、根本的な問題を示している可能性があります。
  • シンセティックトランザクションがステージングのレプリカではなく、実際の本番環境に対して実行されることを確認する。

具体的な要点

デプロイ前のテストはコードが正しいことを検証します。スモークテストとシンセティックトランザクションはデプロイが成功したことを検証します。これらは同じものではなく、一方が他方を置き換えることはできません。グリーンパイプラインは、コードが管理された環境ですべてのチェックにパスしたことを意味します。スモークテストの成功は、アプリケーションが実際に本番環境で実行されていることを意味します。シンセティックトランザクションのパスは、ユーザーが最も重要なタスクを完了できることを意味します。両方をデプロイパイプラインに追加すれば、コードが現実と出会うときにのみ現れる問題を捕捉できるでしょう。