TT Lab
はじめる
学ぶ 学習パス コース

Tomcat & nginxの運用

WARデプロイの実際と並行デプロイ(Parallel Deployment)

TT Labで続きを見る

一言でいうと

WARをただコピーするデプロイには、展開中の404という穴があり、Tomcatはすでにその穴を埋める手段(##버전の並行デプロイ。韓国語の語は「バージョン」を意味します)を持っているのに、大半の現場がそれを知りません。

なぜこれが問題なのか

停止デプロイは安全ですが、その間サービスが止まります。無停止にしようとWARだけを上書きすると、展開が終わるまで、そのパスは404で、この時間はクラスが多いほど長くなり、30秒を超えることもあります。短いからと見過ごせない理由は、その30秒がサービスイン初日の午前9時にかかるからです。

しかも、失敗が静かです。コピーの途中でTomcatが展開を始めて、半分のWARを展開しようとして失敗すると、ログには残りますが、デプロイスクリプトの終了コードは0です。デプロイした人は、成功したと信じて帰宅します。

WARはどのようにデプロイされるのか

webapps/order.warをコピーすると、Tomcatがwebapps/order/に展開して、/orderパスでサービスします。これがautoDeploy="true"の動作です。便利ですが、運用には落とし穴があります。

並行デプロイ: Tomcatがもともと持っている無停止の手段

Tomcatには、あまり知られていない機能があります。ファイル名に##버전を付けると、同じコンテキストパスに複数のバージョンを同時に載せられます(プレースホルダーはバージョンです)。

webapps/order##001.war   ← 기존 버전
webapps/order##002.war   ← 새 버전

この状態で、Tomcatは次のように動作します。

つまり、セッションを切らずに新しいバージョンに移れます。L4の前段でサーバーを外したり入れたりする従来の無停止デプロイができない単一WAS環境で、これはかなり使えるカードです。

バージョン文字列は文字列の比較で並べられるので、##1、##2、##10のように書くと、##10が##2より前に来ます。##001のように0を埋めるか、##2026-08-19_1430のようなタイムスタンプを使います。

それでも停止デプロイをする場合

並行デプロイは万能ではありません。次の場合は使えません。

そのため、実務の判断は次のとおりです。 画面・ロジックだけが変わるなら並行デプロイ、スキーマ・バッチ・グローバルな状態が絡むなら停止デプロイ。

WARと実行可能JARは何が違うのか

最近の新規開発はSpring Bootのfat jarで行い、既存のシステムはWARです。同じ組織の中に両方が共存するのはよくある状況なので、違いを整理しておくとよいです。

項目 WAR+外部Tomcat 実行可能JAR(組み込みTomcat)
デプロイ単位 WARファイル JARファイル
Tomcatのバージョン サーバー管理者が管理(複数のアプリが共有) アプリが保持(アプリごとに異なりうる)
ポート server.xml 実行引数 / プロパティ
複数アプリの配置 1つのWASに複数のコンテキスト プロセスを複数立ち上げる
ロールバック 以前のWARに置き換え 以前のJARにプロセスを置き換え
無停止 並行デプロイまたはL4 プロセスの置き換え+LB
運用標準 WASを基準とした手順書 プロセス/コンテナを基準とした手順書

運用組織の標準手順書が、どちら側を前提に書かれているかが、実際の選択を左右します。技術的にはJARが楽でも、WAS単位で監視・起動・バックアップの手順が標準化されている組織では、JAR1つのために手順を新しく作る必要があります。そのコストが、技術的な利点より大きいことがあります。

デプロイスクリプトが備えるべき最低限

現場で使えるデプロイスクリプトは、これくらいのことをします。

  1. 引数の検証: WARファイルが実際に存在し、0バイトでないか
  2. バックアップ: 現在デプロイされているものに、タイムスタンプを付けて保管
  3. アトミックな配置: 一時的な名前でコピーしてからmv
  4. 展開の待機: 最大N秒間、コンテキストが応答するまでポーリング
  5. 検証: ヘルスチェックURLが200で、バージョン文字列が期待値か
  6. 失敗したら即中止: 5つ目が失敗したら、デプロイ成功として報告しない

4つ目の「展開の待機」が特に重要です。cpの直後にcurlすると、まだ404です。それを失敗と判定してロールバックするスクリプトも見ましたが、逆に、待機なしで「デプロイ完了」を出力して終わるスクリプトは、はるかに多く見ました。後者は、失敗したデプロイを成功と報告します。はるかに悪いです。

現場での姿

そのため、デプロイスクリプトが備えるべき最低限が決まっています。別の名前でコピーしてから、mvでアトミックに名前を変更し、展開が終わるまで待ってから、実際の応答が200であることを確認してから終了コードを出します。コピー直後にすぐ確認すると、まだ展開中なので失敗しますが、これを「デプロイ失敗」と誤解して元に戻すことも、よくあります。