ゼロダウンタイムデプロイとは?無停止を壊す発生源と設定順序・計測方法を実装者目線で解説
ブルーグリーンに切り替えたのに、リリースのたびに数十件の502が記録される。ゼロダウンタイムデプロイの現場で最も多い相談がこれです。原因は方式の選び方ではなく、ロードバランサーの登録解除、プロセスの終了処理、ヘルスチェックの判定、データベースのスキーマ変更という下位4層のどこかにあります。この記事では、無停止が成立する条件を層ごとに分解し、待ち時間の入れ子をどの順序で決めるか、到達度をどう計測するか、そして無停止を追わない判断が正しくなる条件までを扱います。
まとめ:ゼロダウンタイムデプロイを名乗れる条件と、設定を決める順序
ゼロダウンタイムデプロイは、デプロイ方式を選ぶだけでは成立しません。ブルーグリーンやローリングに変えても、下位4層のどれかが噛み合わなければ切り替えの瞬間に5xxが出ます。順序としては、まず「どこで接続が切れるか」を層ごとに特定し、次に待ち時間の大小関係を決め、最後に方式を選ぶ。この逆順で進めた現場が、方式だけ導入して停止が残る状態に陥ります。
設定の決定順序は一本道です。AWSのApplication Load Balancerであれば登録解除の遅延(既定300秒)を外枠とし、その内側にプロセスの猶予期間、さらに内側にpreStopの待機を収める入れ子にします。この大小関係が崩れると、ロードバランサーがまだ振り分けている最中にサーバー側が先に接続を切り、クライアントには500系が返る。
判断の結論を先に置きます。夜間バッチ中心の社内システムや、利用時間が業務時間内に閉じるシステムでは、無停止への投資は過剰になりやすい。短い計画停止を告知して受け入れた方が、総保有コストは低く収まります。
ゼロダウンタイムデプロイの定義と、実測すると残る秒未満の中断時間
言葉の指す範囲が人によってずれたまま議論が進むと、合格判定ができません。まず定義と、現実に残る中断の幅を押さえます。
ゼロダウンタイムが指す停止の範囲と、計画停止・障害停止との線引き
ゼロダウンタイムデプロイとは、稼働中のシステムを止めずに新しいバージョンへ入れ替えるデプロイの総称です。対象になるのは「リリース作業に起因する停止」だけで、障害による停止や、データセンター側のメンテナンスによる停止は含みません。ここを混ぜると、可用性の議論とリリース手順の議論が同じ表に載ってしまいます。
実務では、メンテナンス画面を出す従来型のリリース(計画停止)との対比で語られます。従来型は「30分止めます」と告知して作業する方式で、失敗しても切り戻す時間が確保されている。ゼロダウンタイムはその告知を不要にする代わりに、新旧のバージョンが同時に動く時間帯を受け入れる設計へ変わります。
実測では数十ミリ秒から数秒残る中断と、SLOで許容する幅の基準
「ゼロ」は看板であって、実測値ではありません。ロードバランサーがターゲットを登録解除する処理、コネクションプールの再確立、DNSのキャッシュ更新には、いずれも有限の時間がかかります。実装が噛み合った状態でも、切り替え時点で数十ミリ秒から数秒のレイテンシ悪化は残る。
そこで合格ラインは「停止0秒」ではなく、SLOに対する誤差予算の消費量で置きます。可用性99.9%を月次で置いた場合、月あたりの許容停止は約43分です。1回のリリースで許容する劣化を、この43分の何%まで使ってよいかという形で決めると、設定の投資判断が数値で比較できるようになります。
デプロイ方式の選定だけでは無停止に届かない構造上の理由と誤解
方式は「どの単位で入れ替えるか」を決めるだけで、「入れ替える瞬間に接続をどう扱うか」までは決めません。ローリングアップデートの仕組みとKubernetes・ECSの設定値を正しく入れても、アプリケーションがSIGTERMを無視すれば処理中の要求は捨てられます。方式は必要条件であって十分条件ではない、というのがここでの結論です。
もうひとつの誤解が「ブルーグリーンなら瞬間切り替えだから安全」という理解です。ブルーグリーンデプロイメントの仕組みと切り替え手順は待機系を丸ごと用意する方式ですが、切り替え後も旧系に張られたままの長寿命コネクションは残ります。切り替えの粒度が大きいほど、下位層の設計不備は一度に表面化する。
デプロイ方式を切り替えても消えないダウンタイム発生源の切り分け
停止の発生源は4つに分けると切り分けが早くなります。上から順に、経路・プロセス・判定・状態です。
ロードバランサーの登録解除待ちと、接続を切ると500系が返る条件
AWSのApplication Load Balancerでは、ターゲットの登録解除を始めると状態がdrainingになり、既定で300秒待ってから登録解除が完了します。この待ち時間の目的は、処理中の要求を完了させることにあります。
問題になるのはこの逆です。AWSの公式ドキュメントは、登録解除中のターゲットが遅延の満了前に接続を終了した場合、クライアントは500系のエラー応答を受け取ると明記しています。つまりサーバー側が先に落ちれば、ロードバランサーがどれだけ丁寧に待っても停止は発生する。順序の設計がすべてを決める層です。
プロセスがSIGTERMを無視し処理中の要求を捨てる失敗の型
コンテナやプロセスの停止は、まずSIGTERMを送り、猶予時間を過ぎたらSIGKILLで強制終了する二段構えになっています。KubernetesのterminationGracePeriodSecondsは既定30秒です。この猶予の内側で何をどの順序で終わらせるかは、グレースフルシャットダウンの実装手順と猶予時間の設計で詳しく扱っています。
失敗の型は3つに集約されます。ひとつ目は、フレームワークがシグナルを受け取らず即座に終了するケース。ふたつ目は、シグナルは受けるが処理中の要求を待たずにリスナーだけ閉じるケース。3つ目は、シェル経由で起動したためPID 1がアプリケーションではなくシェルになり、シグナルが子プロセスへ届かないケースです。3つ目はdocker run sh -cのような起動コマンドで起きやすく、ログ上は正常終了に見えるため発見が遅れます。
ヘルスチェックが起動途中の応答を成功と誤って判定する境界条件
新しいバージョンが「起動した」ことと「要求を捌ける」ことは別の状態です。TCPの接続確認だけをヘルスチェックにしていると、ポートが開いた瞬間に正常と判定され、データベースの接続プールが温まる前に本番トラフィックが流れ込みます。結果として、切り替え直後だけタイムアウトが集中する。
判定の境界は、依存先の疎通を含めるかどうかで分かれます。準備完了の判定には自プロセスが処理可能かどうかだけを見せ、依存先の障害まで含めると連鎖的に全台が異常判定される事故につながります。ヘルスチェック用の経路は認証を外し、内部の重い集計処理を呼ばない軽量なものに限定してください。
キープアライブ接続とDNSのTTLが切り替えを遅らせる時間の幅
HTTPのキープアライブが有効な場合、クライアントは既存の接続を再利用し続けます。ロードバランサーの振り分け先を変えても、確立済みの接続は切り替わらない。WebSocketはさらに極端で、AWSの公式ドキュメントも、接続がアップグレードされた後はCookieによる振り分けが使われず、その接続は選ばれたターゲットに固定されると説明しています。
DNSで切り替える構成では、TTLに加えてクライアント側のキャッシュが効きます。JVMのように独自のDNSキャッシュを持つ実行環境では、TTLを60秒に下げても切り替わらないことがある。DNS切り替えを無停止の手段として選ぶ場合、この不確実性を前提に、旧系を長めに残す設計にします。
接続の引き剥がしとプロセス終了を無停止で通す設定値の決定順序
各層の待ち時間は、個別に決めると必ず矛盾します。外側から内側へ、大小関係を固定して決める手順を示します。
登録解除の遅延300秒と各種タイムアウトを決める順序と数値の根拠
最初に決めるのは、最も長い要求の処理時間です。アクセスログのレイテンシ分布から99.9パーセンタイルを取り、そこに安全率を掛けた値が「引き剥がしに必要な最小時間」になります。この値より短い設定を入れると、必ず一定割合の要求が切られる。
- 要求処理時間の99.9パーセンタイルを実測する
- 登録解除の遅延をその値以上に設定する(既定は300秒)
- プロセスの猶予期間を登録解除の遅延より短く置く
- preStopの待機をヘルスチェックの検出間隔以上に取る
既定の300秒をそのまま使うと、ローリング更新の1台あたりに5分かかり、20台構成では1時間を超えます。処理時間の実測が10秒に収まるなら、deregistration_delay.timeout_secondsを30秒程度まで下げた方が、リリース全体の所要時間と切り戻しの速さが釣り合います。
preStopの待機時間と猶予30秒を接続の滞留より長く取る計算
Kubernetesでは、Podの削除がAPIサーバーに記録されると、エンドポイントからの除外とコンテナへのシグナル送信が並行して進みます。この2つに順序保証はありません。除外がロードバランサーへ伝わる前にプロセスが終了すれば、まだ振り分けられている宛先が消えることになります。
回避策は、preStopに待機を入れて意図的に終了を遅らせることです。待機時間は、エンドポイントの変更が経路へ伝播しきる時間、つまりヘルスチェックの間隔と失敗回数の積に合わせます。間隔10秒・2回で異常判定なら、20秒以上の待機を置く。そのうえでterminationGracePeriodSecondsは「preStopの待機+処理中の要求の完了時間」を超える値へ引き上げます。既定の30秒のままだと、20秒待機した時点で残り10秒しかなく、長い要求はSIGKILLで切られます。
起動側の準備完了判定とスロースタートで初動の失敗を防ぐ設定値
引き剥がし側を整えても、投入側が粗ければ切り替え直後にエラーが出ます。AWSのスロースタートは既定で無効で、ターゲットは最初のヘルスチェックに通った時点から全量の振り分けを受けます。JITコンパイルやキャッシュの暖機が要る実行環境では、この瞬間にタイムアウトが集中する。
対策は2つです。スロースタートの継続時間を30秒から120秒程度で設定し、振り分け量を線形に増やす。あわせて準備完了の判定に、接続プールの確立とキャッシュの初回読み込みを含めます。なお、スロースタートは振り分けアルゴリズムがラウンドロビンのときにのみ使える点に注意してください。
主要な待ち時間の既定値と、無停止の成立のために見直す優先順位
既定値のまま運用されがちな設定を、見直す優先度とともに並べます。上の2つを直すだけで、リリース時の5xxは大きく減ります。
| 設定 | 既定値 | 優先度と論点 |
|---|---|---|
| ALBの登録解除の遅延 | 300秒 | 高:外枠を決める起点 |
| preStopの待機 | 未設定 | 高:伝播待ちの唯一の手段 |
| プロセスの猶予期間 | 30秒 | 高:待機分を足して延長 |
| スロースタート | 無効 | 中:暖機が要る場合のみ |
| スティッキーの有効期限 | 7日固定 | 中:旧系の滞留が伸びる |
スキーマ変更とセッション状態が無停止を壊す境界と回避の実務手順
経路とプロセスを整えても、状態を持つ層が残ります。ここが無停止の実質的な上限を決めます。
拡張と縮約に分けた二段階移行で新旧同時稼働を成立させる実務手順
新旧のバージョンが同じデータベースを見る以上、スキーマは両方から読み書きできる形でなければなりません。列の追加は安全ですが、改名は旧バージョンを即座に壊します。そこで変更を「拡張」と「縮約」の2段階に割ります。
- 拡張:新しい列を追加し、両方の列へ書き込む
- 移行:既存データを新しい列へ埋める
- 切替:読み取りを新しい列へ寄せる
- 縮約:旧バージョンの停止を確認してから古い列を削除する
移行処理そのものもデプロイから切り離します。一括更新をアプリケーションの起動時に走らせると、起動時間が伸びてヘルスチェックの判定を跨ぐ。バッチとして分離し、途中で止めても再実行できる形にしておくと安全です。この再実行可能性の設計は冪等性の考え方と実装パターンと同じ論点になります。
切り戻しを前提に列削除とNOT NULL追加を後回しにする判断
切り戻しの可否は、スキーマ変更の種類で決まります。列の削除と制約の追加は、旧バージョンから見ると片道です。新バージョンをリリースした直後に問題が見つかっても、スキーマを先に進めてしまっていると、コードだけ戻しても動きません。
実務の判断基準は単純です。切り戻し猶予期間(多くの現場では1リリース分、つまり1〜2週間)が過ぎるまで、破壊的な変更を打たない。NOT NULL制約は、まず既定値付きで追加して全行を埋め、旧バージョンが消えた次のリリースで制約を付ける。この順序を守れば、切り戻しはコードのロールバックだけで完結します。
セッションとWebSocketが切り替えで途切れる条件と外部化
プロセスのメモリにセッションを持つ構成では、入れ替えた台に紐づくセッションが消えます。ログイン状態が飛ぶ、入力途中のフォームが失われるといった形で、5xxとしては観測されない停止になる。監視の数値上は無停止に見えるのに、問い合わせだけが増える典型です。
外部化が基本手段になります。セッションをRedisなどの外部ストアへ移し、プロセスを使い捨て可能にする。WebSocketや長時間のストリーミングは外部化しても切れるため、クライアント側に再接続と再送の実装を持たせます。再接続時にサーバーのバージョンが変わる前提で、プロトコルの後方互換を1世代分は残しておいてください。
デプロイの無停止到達度を数値で確かめる計測手順と合格ラインの決め方
設定を入れた後、無停止が成立したかどうかを主観で判断している現場が少なくありません。計測なしの無停止は自称です。
デプロイ実行中だけを切り出して5xxと接続失敗を数える計測の設計
まず、デプロイの開始時刻と完了時刻をイベントとして記録し、その区間だけを切り出せるようにします。日次の可用性に混ぜると、リリース起因の停止は他のノイズに埋もれてしまう。デプロイIDをタグに持たせ、区間ごとの5xx件数と接続失敗数を集計する形にしてください。
数える対象は2種類あります。ロードバランサーが返した5xx(サーバー側の応答)と、接続そのものが確立できなかった件数(ターゲット到達失敗)です。後者はアプリケーションのログに残らないため、ロードバランサー側のメトリクスでしか捕まえられません。切り替え順序の不備は、ほぼこの後者に出ます。
1秒間隔の合成監視で欠測を捉え、平均値に埋もれさせない計測方法
実トラフィックが少ない時間帯にリリースすると、停止していても要求が来ず、エラー件数が0のまま通過します。これを防ぐのが合成監視です。デプロイ実行中だけ1秒間隔で軽量なリクエストを打ち続け、成功率と応答時間を記録する。
集計は平均値ではなく、失敗が連続した最大秒数で見ます。5分間の平均成功率が99.8%でも、その内訳が「連続12秒の全断」なら、それは無停止ではありません。連続失敗秒数を主指標に置くと、設定の入れ子が崩れている箇所が一目で分かるようになります。
合格ラインをSLOの誤差予算から逆算して数値で決める計算の手順
合格ラインは組織のSLOから逆算します。可用性99.9%・月次で運用し、リリース頻度が月20回なら、43分の誤差予算のうちリリースに割く配分を先に決める。仮に20%を割り当てるなら、1回あたりの許容は約26秒です。
この26秒を、連続失敗秒数の上限として合否判定に使います。超えたリリースは設定の見直し対象とし、超えなければ追加投資はしない。この線を引かないと、無停止の追求が無限に続き、費用対効果の判断ができなくなります。誤差予算を使い切った月はリリースを絞る、という運用ルールとも自然につながる指標です。
ゼロダウンタイムを追わない判断が正しくなる条件と投資の止めどころ
無停止は目的ではなく手段です。ここでは、投資しない判断が合理的になる条件を条件付きで言い切ります。
夜間バッチ中心の社内システムで無停止投資が過剰になる具体条件
次の3つが同時に成り立つなら、ゼロダウンタイムデプロイは採用しません。利用者が社内に限られ利用時間帯が業務時間内に閉じている、リリース頻度が月1回以下、システムが状態を強く持ちスキーマ変更が頻繁に発生する。この条件では、二段階移行の運用負荷と待機系のインフラ費用が、避けられる停止の価値を上回ります。
止めどころも明示しておきます。連続失敗秒数が合格ラインを下回った時点で、それ以上の作り込みは止める。サービスメッシュの導入や、リクエスト単位の再試行機構をここで足すのは、ほとんどの受託開発案件で過剰です。
短時間の計画停止を告知して受け入れる方が安いと判断できる境目
境目は「停止1分あたりの機会損失」と「無停止の維持コスト」の比較で決まります。待機系を常時2系統持つ構成では、インフラ費用がおよそ2倍になり、加えてスキーマ変更のたびに二段階移行の設計工数が乗ります。この維持コストを月額に均し、停止1分あたりの損失で割ると、何分の停止まで許容してよいかが出る。
ECサイトのように停止が直接売上に響く場合は、この計算が無停止側に傾きます。一方、社内の申請ワークフローのように「翌営業日までに処理できればよい」システムでは、深夜の10分停止を告知する方が明確に安い。判断を感覚に委ねず、この2つの数値で決めてください。
無停止を外部の運用体制と組み合わせて維持する場合の実務相談範囲
設定を入れた時点では成立していても、依存ライブラリの更新やインフラの構成変更で入れ子は簡単に崩れます。維持には、リリースごとの計測と、閾値を割ったときの調査を回し続ける体制が必要です。ここが続かない現場では、半年後に元の状態へ戻ります。
自社に運用の担い手を置ききれない場合は、計測の仕組みづくりと閾値監視を外部と分担する形が現実的です。一創では保守運用・内製化支援として、デプロイ計測の設計から段階的な内製移管までを請け負っています。設定の入れ子を一度整えたうえで、監視と判断基準を運用チームへ引き渡す進め方をおすすめします。
よくある質問
ゼロダウンタイムデプロイの検討で繰り返し寄せられる質問を、判断に直結する形で整理します。
ゼロダウンタイムデプロイとブルーグリーンデプロイは同じものですか?
別のものです。ゼロダウンタイムデプロイは「止めずに入れ替える」という目的を指す総称で、ブルーグリーンはその実現方式のひとつになります。ローリングアップデートやカナリアリリースも同じ目的のための方式です。方式を採用しただけでは目的は達成されず、接続の引き剥がし、プロセスの終了処理、ヘルスチェック、スキーマ変更の各層を整えて初めて成立します。
ダウンタイムは本当に完全にゼロになりますか?
実測値としてはゼロになりません。切り替え時点で数十ミリ秒から数秒のレイテンシ悪化は残り、長寿命の接続を持つクライアントは再接続を経験します。実務では「連続して失敗した最大秒数」を指標に置き、SLOの誤差予算から逆算した上限(可用性99.9%・月20回のリリースなら1回あたり数十秒程度)に収まっていれば合格と判断する運用が現実的です。
ロードバランサーの登録解除の遅延は何秒にすべきですか?
要求処理時間の99.9パーセンタイルを実測し、その値以上に設定してください。AWSのApplication Load Balancerの既定は300秒ですが、処理が10秒以内に収まるシステムでこの値を使うと、1台あたり5分の引き剥がし待ちが発生し、台数分だけリリース時間が伸びます。実測が10秒なら30秒程度が妥当な落としどころです。逆に長時間のファイル処理を持つ経路は、既定より延ばす判断もあり得ます。
データベースのスキーマ変更も無停止でできますか?
変更の種類によります。列の追加や、既定値付きの制約追加は無停止で通せます。列の削除、改名、NOT NULL制約の追加は、旧バージョンを壊すため二段階に分けてください。拡張(追加と二重書き)と縮約(旧要素の削除)の間に、旧バージョンが完全に消えるまでの待機を挟むのが基本です。長時間ロックを伴う移行は、デプロイから切り離してバッチで実行します。
小規模なチームでもゼロダウンタイムデプロイは必要ですか?
チーム規模ではなく、停止1分あたりの機会損失で判断します。利用者が社内に閉じ、リリース頻度が月1回以下で、状態を強く持つシステムであれば、無停止の維持コストが停止の価値を上回るため見送る判断が妥当です。逆に、外部の顧客が随時利用するサービスなら、規模が小さくても引き剥がしと終了処理の整備だけは先に入れておく価値があります。
関連記事
- カナリアリリースとは?段階リリースの仕組み・他方式との違い:本記事の下位層を整えたうえで、段階的に比率を移す方式を選ぶ際の判断材料になります。
- AWS CodeDeployとは?In-Place・Blue/Greenデプロイと料金:AWS上で切り替えを自動化する場合の具体的な設定と費用を扱っています。
- インプレースアップグレードとは:無停止を選ばない場合の、既存環境をそのまま更新する手法との比較に使えます。
- DevOpsとは:リリース頻度と計測を回す体制側の考え方をまとめています。