アプリケーション、データベース、インフラストラクチャにおける健全なデプロイとは

デプロイが完了したとき、それが実際に機能しているかどうかをどうやって確認しますか?パイプラインのステータスや緑色のチェックマーク、Slackの「デプロイ成功」メッセージではありません。本当の質問は、デプロイしたものが本来の動作をしているかどうかです。

答えは、何をデプロイしたかによって異なります。アプリケーション、データベースの変更、インフラストラクチャの更新は、それぞれ異なる種類の検証を必要とします。3つすべてに同じヘルスチェックを使用するのは、車のエンジンがかかるか、オイルがきれいか、タイヤの空気圧が十分かを同じテストで確認するようなものです。どれも重要ですが、確認方法は異なります。

アプリケーションのデプロイを検証する

最も基本的な質問から始めましょう。アプリケーションプロセスが実行されていて、接続を受け付けていますか?これは、サーバーの電源が入っているかどうかを確認するのと同じです。単純なヘルスエンドポイントにアクセスして、200レスポンスを確認します。それが得られれば、アプリケーションは生きています。

次のフローチャートは、デプロイの種類ごとに異なる検証パスを示し、最後に健全またはロールバックの判断に至ります。

flowchart TD subgraph App[アプリケーション] A1[ヘルスチェック] --> A2[スモークテスト] A2 --> A3[シンセティックトランザクション] A3 --> A4{すべて合格?} A4 -->|Yes| A5[健全] A4 -->|No| A6[ロールバック] end subgraph DB[データベース] D1[マイグレーションチェック] --> D2[データ整合性チェック] D2 --> D3[クエリパフォーマンスチェック] D3 --> D4{すべて合格?} D4 -->|Yes| D5[健全] D4 -->|No| D6[ロールバック] end subgraph Infra[インフラストラクチャ] I1[設定検証] --> I2[接続性テスト] I2 --> I3[リソース制限チェック] I3 --> I4{すべて合格?} I4 -->|Yes| I5[健全] I4 -->|No| I6[ロールバック] end

しかし、生きていることと動作していることは同じではありません。接続を受け付けるアプリケーションでも、リクエストを処理しようとするとすぐに失敗する可能性があります。設定ファイルを読み取れないかもしれません。データベースに接続できないかもしれません。キャッシュ接続が壊れているかもしれません。これらの問題は、単純なヘルスチェックでは現れません。

そのため、アプリケーションの検証はより深く行う必要があります。複数のエンドポイントを順番に呼び出すスモークテストを実行します。実際のユーザーが行う操作(ログイン、検索、フォーム送信、ログアウト)を模倣したシンセティックトランザクションをシミュレートします。このシンセティックフローが成功すれば、アプリケーションが単に実行されているだけでなく、実際に機能しているという強力な証拠が得られます。

ここで重要なのは、ユーザーにとって最も重要な部分をテストすることです。アプリケーションのコア機能が日付による検索であれば、検証には日付範囲を使用した検索クエリを含める必要があります。ユーザーがファイルをアップロードする場合は、アップロードフローを含める必要があります。すべてのデプロイですべてをテストする必要はありませんが、クリティカルパスはテストする必要があります。

以下は、デプロイ後に実行できるヘルスチェックとシンセティックトランザクションスクリプトの実用的な例です。

# ヘルスチェック: アプリケーションが生きていることを確認
if curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/health | grep -q "200"; then
  echo "Health check passed"
else
  echo "Health check failed"
  exit 1
fi

# スモークテスト: コアユーザーフローをシミュレート(ログイン、検索、送信)
#!/bin/bash
set -euo pipefail

BASE_URL="http://localhost:8080"

# ステップ1: ログイン
LOGIN_RESPONSE=$(curl -s -X POST "$BASE_URL/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"testuser","password":"testpass"}')
TOKEN=$(echo "$LOGIN_RESPONSE" | jq -r '.token')

# ステップ2: 検索
SEARCH_RESPONSE=$(curl -s "$BASE_URL/search?q=test&date_from=2024-01-01" \
  -H "Authorization: Bearer $TOKEN")
if ! echo "$SEARCH_RESPONSE" | jq -e '.results | length > 0' > /dev/null; then
  echo "Search returned no results"
  exit 1
fi

# ステップ3: フォーム送信
SUBMIT_RESPONSE=$(curl -s -X POST "$BASE_URL/submit" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"title":"test","content":"test content"}')
if ! echo "$SUBMIT_RESPONSE" | jq -e '.id' > /dev/null; then
  echo "Form submission failed"
  exit 1
fi

echo "Smoke test passed"

データベースの変更を検証する

データベースはHTTPを話しません。データベースのエンドポイントにpingを送信して200レスポンスを得ることはできません。データベースの検証は、スキーマ変更、インデックス変更、ストアドプロシージャ、参照データの更新に関するものです。問題は、マイグレーションがエラーなく実行されたか、そして以前動作していたものを壊していないかです。

まず、ステージング環境でマイグレーションスクリプトを実行します。出力でエラーを確認します。マイグレーションが成功したら、アプリケーションの通常のアクセスパターンを表すテストクエリを実行します。インデックスを変更した場合は、そのインデックスに依存するクエリが許容可能な速度で実行されるかどうかを確認します。ストアドプロシージャを変更した場合は、テストデータで実行し、結果を検証します。

データベースの検証では、ロールバックが可能であることも確認する必要があります。元に戻せないマイグレーションスクリプトは負債です。ステージング環境でロールバックをテストします。データの損失や破損なしに、以前の状態をクリーンに復元できることを確認します。自信を持ってロールバックできなければ、変更を完全に検証したとは言えません。

よくある間違いは、データベースの検証を1回限りのチェックとして扱うことです。データベースの変更は、本番環境の負荷下でのみ現れる微妙な影響を与える可能性があります。新しいインデックスはあるクエリを高速化する一方で、別のクエリを遅くするかもしれません。スキーマ変更はテストデータでは問題なく動作しても、実際のデータ量ではロックの問題を引き起こす可能性があります。そのため、データベースの検証には、機能チェックとパフォーマンスチェックの両方を含める必要があります。たとえパフォーマンスチェックが単純なベースライン比較であってもです。

インフラストラクチャの変更を検証する

インフラストラクチャには、サーバー、ロードバランサー、ファイアウォール、DNSレコード、TLS証明書、ネットワークルーティングが含まれます。インフラストラクチャを変更するときは、他のすべてが依存する環境を変更しています。ファイアウォールの設定ミスは、データベース接続を静かに壊す可能性があります。ロードバランサールールの誤りは、トラフィックを間違ったサーバーに送信する可能性があります。期限切れのTLS証明書は、アプリケーションをHTTPS経由で到達不能にする可能性があります。

インフラストラクチャの検証は、接続性と設定に関するものです。ファイアウォールルールを変更した後は、アプリケーションがデータベースに到達できることを確認します。ロードバランサーを更新した後は、トラフィックが正しいバックエンドサーバーに到達することを確認します。TLS証明書を更新した後は、HTTPS接続がセキュリティ警告なしに機能することを確認します。

これらのチェックは、多くの場合、インフラストラクチャ自体の外部から実行する必要があります。ネットワーク内部から外部接続性をテストすることはできません。外部からの接続をシミュレートするスクリプトやツールを使用します。エンドポイントにpingを送信します。証明書の有効期限を確認します。DNS解決が正しいIPアドレスを返すことを確認します。

インフラストラクチャの変更は、連鎖的な影響を及ぼす傾向があります。1つのDNSレコードを変更すると、複数のサービスに影響を与える可能性があります。1つのファイアウォールルールを更新すると、以前許可されていたトラフィックがブロックされる可能性があります。そのため、インフラストラクチャの検証には接続性マップを含める必要があります。つまり、機能する必要があるすべての接続のリストと、それぞれに対するテストです。

共通の原則

検証方法は異なりますが、原則は同じです。すべてのデプロイは、デプロイされたオブジェクトが正しく機能しているという証拠を残さなければなりません。証拠は、成功したマイグレーションを示すログエントリ、アプリケーションがリクエストを処理できることを示すHTTPレスポンス、サーバーに到達可能であることを示すping結果などです。証拠がなければ、デプロイが成功したかどうかはわかりません。パイプラインが完了したことだけがわかります。

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

これを最終的なリストではなく、出発点として使用してください。特定のシステムに合わせて調整してください。

  • アプリケーション: ヘルスエンドポイントが200を返す、コアユーザーフローのシンセティックトランザクションが成功する、重要な外部依存関係(データベース、キャッシュ、API)に到達可能である。
  • データベース: マイグレーションスクリプトがエラーなく実行される、テストクエリが正しい結果を返す、クエリパフォーマンスが許容範囲内である、ロールバックスクリプトがステージングで動作する。
  • インフラストラクチャ: 依存するすべてのコンポーネント間の接続性が確認される、TLS証明書が有効で期限切れが近くない、DNS解決が正しいレコードを返す、ファイアウォールルールが必要なトラフィックを許可する。

デプロイは実際にいつ完了するのか?

デプロイは、変更がその環境で正しく動作することを確認したときに完了します。パイプラインが緑色になったときではありません。チケットがクローズされたときではありません。チームリーダーが「よさそうだ」と言ったときでもありません。デプロイは、アプリケーション、データベース、またはインフラストラクチャが本来の動作をしているという証拠があるときに完了します。

その証拠こそが、「デプロイが行われた」ことと「デプロイが成功した」ことを区別するものです。