Tomcatを開けてみると何があるのか
一言でいうと
Tomcatは、ディレクトリ7つの役割さえ知っていれば、ほとんどの運用状況が説明でき、そのうち実際に事故を起こす場所は、bin/setenv.sh・work/・logs/catalina.outの3つです。
なぜ今もTomcatなのか
Spring Bootを使えば、組み込みTomcatが入っているので、java -jarで終わります。ところが、韓国のSI現場に出ると、今もスタンドアロンのTomcatにWARを載せるシステムのほうが、はるかに多いです。理由は技術的な好みではありません。
- 運用組織がWAS単位で管理します。サーバー1台に複数の業務WARを載せ、起動/停止/モニタリングの手順が、WASを基準に標準化されています。
- 標準フレームワーク(電子政府標準フレームワークを含む)とデプロイ手順書が、WARを前提に書かれています。
- WebLogic/JEUSを使っていた組織が、コスト削減でTomcatに移行した場合でも、運用方式はそのままです。
そのため、新人に最初の週に降ってくる仕事が、「Tomcatをちょっと立ち上げてみてください」なのです。そしてその瞬間、systemctl start tomcatが使えないサーバーに出会います。
ディレクトリの地図
/opt/tomcat
├── bin/ 기동·정지 스크립트. catalina.sh, startup.sh, shutdown.sh, setenv.sh
├── conf/ 설정. server.xml, web.xml, context.xml, tomcat-users.xml, logging.properties
├── lib/ 톰캣 자신과 모든 웹앱이 공유하는 JAR (JDBC 드라이버를 여기 두는 관행)
├── logs/ catalina.out, localhost_access_log.*.txt, 각종 *.log
├── webapps/ 배포 대상. WAR 를 두면 자동으로 같은 이름 디렉터리로 전개된다
├── work/ JSP 를 컴파일한 .java/.class 캐시
└── temp/ java.io.tmpdir
このコードブロックの韓国語コメントは、上から順に、起動・停止スクリプト、設定、Tomcat自身とすべてのWebアプリが共有するJAR(JDBCドライバーをここに置く慣行)、ログ、デプロイ対象(WARを置くと自動的に同じ名前のディレクトリに展開される)、JSPをコンパイルした.java/.classのキャッシュ、java.io.tmpdirという意味です。
現場で実際に問題になる点だけを押さえましょう。
bin/setenv.sh: Tomcatがデフォルトで提供しないファイルですが、あればcatalina.shが自動的に読み込みます。JVMオプション(CATALINA_OPTS)をここに入れます。catalina.shを直接直すと、Tomcatのバージョンを上げるときに消えます。必ずsetenv.shに入れてください。work/: デプロイ後に画面が昔のままなら、十中八九ここのキャッシュです。デプロイ手順書に「workディレクトリの削除」が入る理由です。logs/catalina.out: ローテーションされません。放置すると数十GBになります。ディスクフルによる障害の原因の1位が、このファイルです。lib/vsWEB-INF/lib/: 同じライブラリが、両方に異なるバージョンで存在すると、クラスローダー地獄が開きます。NoSuchMethodErrorが出たら、ここから見ます。
server.xmlの階層
server.xmlはマトリョーシカです。外から内へ読むと理解が早いです。
<Server port="8005" shutdown="SHUTDOWN"> <!-- JVM 하나 -->
<Service name="Catalina"> <!-- 커넥터들 + 엔진 하나 -->
<Connector port="8080" protocol="HTTP/1.1" ... /> <!-- 바깥과 만나는 문 -->
<Engine name="Catalina" defaultHost="localhost"> <!-- 요청 처리 엔진 -->
<Host name="localhost" appBase="webapps" <!-- 가상 호스트 -->
unpackWARs="true" autoDeploy="true">
<Valve className="...AccessLogValve" pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
このコードブロックの韓国語コメントは、順に、JVM1つ、コネクターたちとエンジン1つ、外部との接点となる入り口、リクエストを処理するエンジン、仮想ホストという意味です。
- Serverの
port="8005"というポートは、サービスポートではなく、終了コマンドの受信ポートです。shutdown.shはここにTCPで接続して、SHUTDOWNという文字列を送ります。つまり、このポートが開いていて文字列がデフォルトなら、誰でもTelnetでWASを停止できます。セキュリティ点検で必ず指摘される項目で、対応は2つです。shutdownの文字列を長く変えるか、port="-1"で完全に無効化します。-1にするとshutdown.shが使えなくなるので、killで止める必要があることを、手順書に書いておきます。 - Connectorは、後のモジュールでまとめて扱います。ここでは1つだけ覚えておきましょう。コネクターは複数置くことができ、それぞれが異なるポート/プロトコル/スレッドプールを持ちます。
- Hostの
appBase属性がwebappsで、autoDeploy="true"なので、WARをコピーすると展開されます。運用ではautoDeploy="false"にしておき、デプロイスクリプトが明示的に展開するようにする組織も多いです。誤ってファイルが入る事故を防ぐためです。 - AccessLogValveの
pattern属性に、%D(処理時間ms)を入れていないシステムが、今でも多いです。応答時間がアクセスログにないと、「遅い」という報告を受けたときに、根拠が何もありません。これはサービスイン前に必ず入れてください。
context.xml: Webアプリ単位の設定
conf/context.xmlは全体設定、conf/Catalina/localhost/<앱이름>.xml(プレースホルダーはアプリ名です)はアプリごとの設定です。後者を使うと、webappsの外にあるディレクトリをサービスできます(docBase)。デプロイアーティファクトを/app/deploy/orderに置き、Tomcatには手を触れない運用方式が、ここから生まれます。
DBコネクションプール(<Resource>)も、普通はここにあります。そのため、「DBの接続情報はどこにありますか」の答えは、たいていcontext.xmlか、アプリケーションのプロパティファイルの2つのどちらかです。
起動と停止: systemdがないとき
# 기동 (백그라운드, catalina.out 으로 로그)
/opt/tomcat/bin/catalina.sh start
# 포그라운드 (컨테이너에서 쓰는 방식. 로그가 터미널로)
/opt/tomcat/bin/catalina.sh run
# 정지 (8005 포트로 SHUTDOWN 전송, 종료 대기)
/opt/tomcat/bin/catalina.sh stop 30 -force
このコードブロックの韓国語コメントは、順に、起動(バックグラウンドで、ログはcatalina.outへ)、フォアグラウンド(コンテナで使う方式。ログはターミナルへ)、停止(ポート8005にSHUTDOWNを送信し、終了を待つ)という意味です。
stopの後ろの30 -forceは、「30秒待って、死ななければkill」です。運用スクリプトには、これを入れるのがよいです。セッションを処理中のスレッドがあると、Tomcatはおとなしく終了しない場合があります。
起動できたかどうかを確認する最も確実な方法は、プロセスではなくログとポートです。
grep 'Server startup in' /opt/tomcat/logs/catalina.out | tail -1
ss -ltn | grep 8080
「プロセスは立ち上がっているのに、ポートが開いていない状態」が実際に存在します。ポートの競合や初期化の失敗で、コネクターだけが死んだ場合です。プロセスだけを見て「立ち上がりました」と報告すると、5分後にまた電話を受けます。
現場での姿
SI現場でTomcatを触る最初の週に経験することは、たいてい次の3つのどれかです。
- 「JVMオプションを入れたのに、効きません」:
catalina.shを直接直したか、setenv.shを作って再起動しなかったのです。反映されたかどうかは、ファイルではなくプロセスに聞く必要があります。/proc/<pid>/cmdlineで、実際の実行引数を見ます。 - 「デプロイしたのに、画面がそのままです」:
work/に残ったJSPのコンパイルキャッシュです。デプロイ手順書に「workディレクトリの削除」が入る理由がこれで、この1行が抜けた手順書で何時間も費やすことが、実際に起きます。 - 「ディスクがいっぱいです」:
catalina.outには、ローテーションがありません。Tomcatではなくlogrotate側で切り出す必要があり、放置すると数十GBになります。
3つとも、Tomcatを知らないから生じる問題ではなく、どのファイルが何をするかを知らないから生じる問題です。だから、ディレクトリの地図が先なのです。