新しいバージョンが実際に正しく動作するか確認する方法

デプロイが完了しました。パイプラインはグリーンです。新しいバージョンが本番環境で稼働しています。チームの誰かがブラウザを開き、トップページを表示して「問題なさそう」と言います。皆がほっと一息ついて、次の作業に移ります。

この感覚はよくわかりますが、非常に危険です。一人が1ページだけを確認するのは、再現可能なプロセスではありません。他の機能が動作するかどうかはわかりません。APIが正しく応答するかもわかりません。そして、ユーザーが良い体験を得られるかどうかは、まったくわかりません。

デプロイの検証を誰かの感覚に頼っているのであれば、実質的にユーザーを最初の障害検出システムとして使っていることになります。ユーザーが問題を報告する頃には、被害はすでに広がっています。

手動チェックの問題点

デプロイ後の手動チェックには、3つの根本的な欠陥があります。

第一に、一貫性がありません。今日チェックする人と明日チェックする人では、見る箇所が異なる可能性があります。ある人はログインページをチェックし、別の人は検索機能をチェックするかもしれません。チェック自体が変わるため、デプロイ間で結果を比較することはできません。

第二に、手動チェックは浅いです。人間が妥当な時間内にチェックできるページやエンドポイントの数は限られています。複数のステップを含む複雑なワークフローは、デプロイのたびに手動でテストされることはほとんどありません。最も頻繁に壊れるのは、まさに誰もチェックしない複数ステップのフローです。

第三に、手動チェックは遅いです。誰かが数ページのチェックを終える頃には、デプロイはすでに何千ものユーザーにサービスを提供しているかもしれません。何かが壊れていれば、それらのユーザーはすでに影響を受けています。

ここで、構造化されたプロセスとしての検証が重要になります。検証とは、新しくデプロイされたバージョンが、サーバー側だけでなくユーザーの視点からも正しく動作するかどうかを確認する行為です。これは「ユーザーは明らかな問題に遭遇することなくこのバージョンを使用できるか?」という1つの問いに答えます。

スモークテストから始める

最もシンプルな検証形式はスモークテストです。この用語は電子工学に由来します。新しい回路基板に初めて電源を入れたとき、煙が出ないか確認します。煙が出なければ、部品が燃えていることはなく、より深いテストに進むことができます。

デプロイの文脈では、スモークテストは新しいバージョンがすぐに壊れていないことを確認するための基本的なチェックを実行します。これらのチェックはシンプルで高速です。ビジネスロジックを検証するわけではありません。最も明白な障害だけをキャッチします。

典型的なスモークテストには以下が含まれます:

以下は、デプロイ後に実行できるスモークテストスクリプトの具体例です:

#!/bin/bash
# smoke-test.sh - デプロイ後に基本的なスモークチェックを実行

BASE_URL="http://localhost:8080"
FAILED=0

check_endpoint() {
  local url="$1"
  local description="$2"
  local status=$(curl -s -o /dev/null -w "%{http_code}" "$url")
  if [ "$status" -eq 200 ]; then
    echo "PASS: $description"
  else
    echo "FAIL: $description (HTTP $status)"
    FAILED=1
  fi
}

check_endpoint "$BASE_URL/" "Homepage returns 200"
check_endpoint "$BASE_URL/login" "Login page renders"
check_endpoint "$BASE_URL/api/health" "Health endpoint responds"
check_endpoint "$BASE_URL/static/css/main.css" "CSS asset loads"

if [ "$FAILED" -eq 1 ]; then
  echo "Smoke tests failed. Rollback recommended."
  exit 1
else
  echo "All smoke tests passed."
fi
  • トップページをロードし、HTTP 200が返ることを確認する
  • ログインページがエラーなくレンダリングされることを確認する
  • 重要なAPIエンドポイントが妥当な時間内に応答することを確認する
  • CSSやJavaScriptファイルなどの静的アセットが正しくロードされることを確認する

重要な要件は一貫性です。デプロイのたびに同じチェックを実行する必要があります。実行する人によってチェックが変わると、デプロイ間で結果を比較する能力が失われます。今日パスしたが先週は失敗したスモークテストは、有用な情報をもたらします。毎回変わるスモークテストは、何も教えてくれません。

スモークテストは1分以内に完了する必要があります。それ以上かかる場合、それはもはやスモークテストではありません。別のものです。高速で浅いままにしておきましょう。

シンセティックトランザクションでさらに深く

スモークテストがパスしたら、より徹底的なチェックであるシンセティックトランザクションに進むことができます。これは、実際のユーザーがアプリケーション内で行う操作を自動的にシミュレートするものです。

シンセティックトランザクションは、単にページがロードされるかどうかをチェックするだけではありません。実際のユーザーフローをトレースします。例えば:

  1. トップページを開く
  2. ログインボタンをクリックする
  3. テスト用のユーザー名とパスワードを入力する
  4. ログインフォームを送信する
  5. 特定の機能に移動する
  6. テストデータでフォームに記入する
  7. フォームを送信する
  8. 次のページに期待される結果が表示されることを確認する

シンセティックトランザクションは、2つの重要な点でスモークテストと異なります。

第一に、より長く、より現実的です。スモークテストはドアが開くかどうかを確認します。シンセティックトランザクションは、中に入って座り、食事を注文し、支払いをし、レシートを持って出られるかどうかを確認します。

第二に、シンセティックトランザクションはデータの正確性を検証し、単なるページの可用性だけではありません。スモークテストはログインページがロードされることを確認します。シンセティックトランザクションは、ログイン後にユーザーが正しいデータを含むダッシュボードを表示できることを確認します。これははるかに強力なシグナルです。

シンセティックトランザクションは、デプロイ完了直後に実行する必要があります。長期的な監視の代わりになるものではありません。迅速な答えを得るためのものです。「このバージョンはユーザーにサービスを提供し続けるのに十分健全か、それともロールバックすべきか?」

デプロイ直後に両方を実行する

スモークテストとシンセティックトランザクションは、2段階の検証パイプラインとして最も効果的に機能します。

ステップ1:スモークテストを実行します。失敗したら停止します。何かが根本的に壊れています。ロールバックするか、すぐに修正します。基本が動作するまで、より深いチェックに進まないでください。

以下の図は、自動化された意思決定フローを示しています:

flowchart TD A[Deployment Complete] --> B[Run Smoke Tests] B -- Fail --> C[Rollback] B -- Pass --> D[Run Synthetic Transactions] D -- Fail --> C D -- Pass --> E[Deployment Healthy] style A fill:#e6f3ff,stroke:#333,stroke-width:2px style B fill:#fff3cd,stroke:#333,stroke-width:2px style D fill:#fff3cd,stroke:#333,stroke-width:2px style C fill:#f8d7da,stroke:#333,stroke-width:2px style E fill:#d4edda,stroke:#333,stroke-width:2px

ステップ2:シンセティックトランザクションを実行します。失敗した場合、より微妙な問題があります。アプリケーションは動作していますが、特定のユーザーフローが壊れています。重大度に応じて、ロールバックするかホットフィックスするかを決定する必要があります。

両方のチェックは、デプロイ後数分以内に完了する必要があります。目標は、ほとんどのユーザーが新しいバージョンに遭遇する前に、そのバージョンが安全かどうかを知ることです。

実用的な検証チェックリスト

以下は、自身のデプロイに適用できるシンプルなチェックリストです:

  • スモークテスト:トップページが200を返す
  • スモークテスト:ログインページがエラーなくレンダリングされる
  • スモークテスト:重要なAPIエンドポイントが2秒以内に応答する
  • スモークテスト:静的アセットが正しくロードされる
  • シンセティックトランザクション:ユーザーがテスト用認証情報でログインできる
  • シンセティックトランザクション:ユーザーが主要なワークフロー(例:注文作成、フォーム送信、レポート表示)を完了できる
  • シンセティックトランザクション:テスト中に作成されたデータが期待される場所に表示される

このチェックリストは網羅的ではありません。アプリケーションの特定のフローに基づいて調整する必要があります。しかし、構造は普遍的です。高速かつ浅く始め、その後深く進みます。

実際の例

ECアプリケーションの新しいバージョンをデプロイしたと想像してください。スモークテストが実行され、トップページがロードされ、検索APIが応答し、商品画像が表示されることを確認します。良好です。

次に、シンセティックトランザクションが実行されます。ユーザーが商品を検索し、カートに追加し、チェックアウトに進み、支払いを完了する流れをシミュレートします。トランザクションは支払いステップで失敗します。テストにより、新しいバージョンが支払い連携を壊したことが明らかになります。

シンセティックトランザクションがなければ、ユーザーが苦情を言い始めるまでこの問題を発見できなかったかもしれません。これがあれば、デプロイから2分以内に問題を把握できます。壊れたフローに遭遇するユーザーがほんの一握りになる前に、ロールバックできます。

これが、構造化された検証と「うまくいくことを願う」ことの違いです。

すべてが同じ方法で検証できるわけではない

スモークテストとシンセティックトランザクションはアプリケーションには有効ですが、データベースやインフラストラクチャには同じようには機能しません。データベースマイグレーションはページをロードすることで検証できません。インフラストラクチャの変更は、ユーザーログインをシミュレートすることで検証できません。

異なるタイプのデプロイには、異なる検証シグナルが必要です。原則は同じです。早期にチェックし、一貫してチェックし、ユーザーの視点からチェックすることです。しかし、具体的なチェックは、何をデプロイしているかによって異なります。

具体的なポイント

デプロイ後に一人がブラウザを開くという方法に頼るのはやめましょう。2段階の検証パイプラインを構築してください。基本的な健全性チェックのためのスモークテストと、現実的なユーザーフローのためのシンセティックトランザクションです。両方をすべてのデプロイ直後に実行します。どちらかのステップが失敗した場合、ユーザーよりも先に問題を把握できます。

ユーザーが、あなたのデプロイが何かを壊したことを最初に発見する側になってはいけません。構造化された検証が、それを防ぐ方法です。