デプロイは本当に完了したと言えるのか
デプロイコマンドを実行した。ターミナルには緑色のクリーンな出力が表示されている。エラーも警告もない。新しいコンテナは起動し、ファイルも所定の場所に配置されている。チームメンバーは帰宅の準備を始めている。
しかし、本当にデプロイは完了したのだろうか?
多くのチームは、デプロイコマンドが終了した瞬間をゴールと見なしている。これは危険な思い込みだ。その時点で分かっているのは、ファイルの移動やサービスの再起動といったプロセスが成功裏に完了したという事実だけである。アプリケーションが実際に正常に動作しているかどうかは、まだ分かっていない。
デプロイと健全性の違い
デプロイには2つの明確なフェーズがある。第一は、新しいバージョンを所定の場所に配置するという技術的な行為である。第二は、新しいバージョンが正しく動作することを検証することである。多くのチームは第一フェーズで止めてしまい、それで終わりにしている。
以下のフローチャートは、上記で説明した2フェーズのプロセスを示している。
デプロイが成功した後に、何が問題になり得るかを考えてみよう。
- 新しいコードに設定ミスがあり、実際のトラフィックが流れて初めて顕在化する
- データベースマイグレーションは成功したが、アプリケーションコードが異なるカラム名を期待している
- 依存関係が更新され、ユニットテストでは捕捉できなかったインテグレーションが壊れた
- 新しいバージョンがより多くのメモリを使用し、数分後にOOMキラーが発動する
これらのいずれも、デプロイログには表示されない。ターミナルには依然として「デプロイ成功」と表示されるだろう。しかし、アプリケーションは壊れている。
エビデンスとして何をカウントするか
デプロイが完了したと言えるのは、新しいバージョンが健全でユーザーにサービスを提供できる状態にあるというエビデンス(証拠)を入手したときだけである。そのエビデンスは、測定可能かつ検証可能でなければならない。「なんとなく大丈夫そう」や「問題なさそうに見える」はエビデンスとしてカウントされない。
エビデンスは複数のソースから得られる。スモークテストは最も基本的なレイヤーである。アプリケーションが起動すること、メインページが読み込まれること、コア機能が応答することを確認する。スモークテストが失敗した場合、何か根本的に問題があることを意味する。
以下は、デプロイ後にエビデンス収集の第一レイヤーを自動化する最小限のスクリプトである。
#!/bin/bash
# post-deploy-verify.sh - デプロイコマンド実行後に実行
set -euo pipefail
URL="https://your-app.example.com"
DB_CONN_STRING="postgresql://user:pass@db-host:5432/app"
# 1. ヘルスチェック
HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" "$URL/health")
if [ "$HTTP_CODE" -ne 200 ]; then
echo "FAIL: ヘルスチェックが $HTTP_CODE を返しました"
exit 1
fi
echo "PASS: ヘルスチェックが200を返しました"
# 2. スモークテスト - メインページが読み込まれるか
if ! curl -s "$URL" | grep -q "<title>App</title>"; then
echo "FAIL: メインページに期待されるタイトルがありません"
exit 1
fi
echo "PASS: メインページが正しく読み込まれました"
# 3. データベース接続テスト
if ! psql "$DB_CONN_STRING" -c "SELECT 1" > /dev/null 2>&1; then
echo "FAIL: データベース接続に失敗しました"
exit 1
fi
echo "PASS: データベース接続に成功しました"
echo "すべてのチェックが合格しました - デプロイのエビデンスを収集しました"
合成トランザクションはさらに深く掘り下げる。ログイン、データ検索、フォーム送信、注文チェックアウトなど、実際のユーザーフローをシミュレートする。合成トランザクションが成功すれば、完全なユーザージャーニーがエンドツーエンドで機能していることが分かる。
そして、このシリーズでこれまでに説明してきたシステムシグナルがある。デプロイ後は、可用性が安定しているか、エラー率が急上昇していないか、レイテンシが悪化していないかを確認する必要がある。これらのシグナルがすべて正常に見えれば、新しいバージョンが問題を引き起こしていないという強力な根拠となる。
カジュアルな検証の罠
本当の危険は、チームが検証を完全にスキップすることではない。カジュアルに行うことである。開発者がダッシュボードを一瞥し、緑色のバーを見て、すべて問題ないと決めつける。しかし、その一瞥では、500エラーの微妙な増加を見逃すかもしれない。一部のユーザーでチェックアウトフローがタイムアウトしていることに気づかないかもしれない。
カジュアルな検証が失敗するのは、人間の注意力と記憶に依存しているからだ。デプロイした開発者は、長い一日の後に疲れているかもしれない。次のミーティングに急いでいるかもしれない。この特定の変更に対して、どのシグナルを確認すべきかを正確に把握していないかもしれない。
解決策は、デプロイする前にエビデンスの基準を定義することである。どのシグナルがデプロイの完了を証明するかを事前に決定する。それを文書化する。明示的にする。
妥当な基準のセットは、次のようになる。
- メインページとログインフローのスモークテストが合格する
- 最も重要な3つのユーザージャーニーの合成トランザクションが合格する
- エラー率が0.1%未満に留まる
- P95レイテンシがデプロイ前のベースラインから5%以上増加しない
- データベース接続プールの使用率が70%未満に留まる
これらの条件がすべて満たされたとき、デプロイは完了する。いずれかの条件が失敗した場合、デプロイコマンドが成功していても、デプロイは完了していない。
誰がデプロイ完了を判断するか
小規模チームでは、デプロイした開発者自身が判断することが多い。基準を確認し、シグナルを検証し、完了と判断する。これはチームが小さく、全員がシステムをよく理解している場合に機能する。
チームが成長するにつれて、判断は自動化に移行すべきである。パイプライン自体が、すべての自動チェックに合格するまでデプロイを完了とマークしてはならない。これにより、人間の判断をループから排除し、一貫性を確保する。すべてのデプロイが、毎回同じ検証を受けることになる。
リスクの高い変更については、依然として人間をループに残しておきたい場合もある。シニアエンジニアやオンコール担当者がエビデンスをレビューし、最終判断を下すことができる。しかし、その場合でも基準は明確であるべきだ。人間は「何となく大丈夫そうか」を推測しているのではない。事前に定義された条件のリストをチェックしているのである。
どれだけのエビデンスが十分かという普遍的なルールはない。内部ツールのマイナーなバグ修正には、顧客向け決済システムの大規模な機能変更よりも少ない検証で済む。重要なのは、チームが変更の種類ごとに基準に合意していることである。
デプロイ完了のための実用的チェックリスト
以下は、チームで適応して使用できるシンプルなチェックリストである。
- デプロイコマンドがエラーなく完了した
- スモークテストに合格した(メインページ、ログイン、コア機能)
- 合成トランザクションに合格した(クリティカルなユーザージャーニー)
- エラー率が許容範囲内である
- レイテンシが許容範囲内である
- リソース使用量(CPU、メモリ、接続数)が安定している
- モニタリングシステムからアラートが発報されていない
- データベースマイグレーションが適用され、検証された
いずれかの項目が失敗した場合、デプロイは完了していない。成功を宣言する前に調査を行う。
これを正しく理解すると何が変わるか
チームが「デプロイは健全性のエビデンスが得られるまで完了しない」という認識で一致すると、デプロイプロセス全体が変わる。デプロイは、ターミナルで終わる技術的なタスクではなくなる。ユーザーが新しいバージョンを安全に使用できる状態で終わる移行プロセスになる。
この変化は行動を変える。チームはより良いスモークテストを書くようになる。なぜなら、それらのテストが「今日の作業を終えて良いか」を決定することを知っているからだ。デプロイ前に明確な基準を定義するようになる。デプロイを早く終わらせようと急ぐのをやめ、新しいバージョンが稼働した後に何が起こるかに注意を払うようになる。
次回、チームでデプロイを実行するときは、コマンドが終了した後に何が起こるかを観察してほしい。全員がリラックスして次の作業に移るか? それとも、まずエビデンスを確認するか? その瞬間が、あなたのチームがデプロイの完了を本当に理解しているかどうかを教えてくれる。