参考メモ/CentOS7のApache Tomcatパッケージについてメモ

お仕事では、Javaであんまりディストリビューションのパッケージを使わないのですが、実際問題どんな構成になってるか気になってちょっと見てみました。
要するにJavaでデーモンサービスを作る場合、systemdのunitファイルどう作ればいいの？というのを知りたかったわけです。

```
確認環境：64bit CentOS7
$ cat /etc/centos-release
CentOS Linux release 7.2.1511 (Core)
※epelリポジトリ導入済み
```

## CentOS7 での tomcat 関連パッケージ

2016-03-13時点では、tomcatパッケージのバージョンは 7.0.54.

`yum search tomcat` の結果：

| パッケージ名 | 説明(Description) |
|----|----|
| jglobus-ssl-proxies-tomcat.noarch | Globus Java - SSL and proxy certificate support for Tomcat |
| tomcat-admin-webapps.noarch | The host-manager and manager web applications for Apache Tomcat |
| tomcat-docs-webapp.noarch | The docs web application for Apache Tomcat |
| tomcat-javadoc.noarch | Javadoc generated documentation for Apache Tomcat |
| tomcat-jsp-2.2-api.noarch | Apache Tomcat JSP API implementation classes |
| tomcat-jsvc.noarch | Apache jsvc wrapper for Apache Tomcat as separate service |
| tomcat-lib.noarch | Libraries needed to run the Tomcat Web container |
| tomcat-native.x86_64 | Tomcat native library |
| tomcat-servlet-3.0-api.noarch | Apache Tomcat Servlet API implementation classes |
| tomcat-webapps.noarch | The ROOT and examples web applications for Apache Tomcat |
| tomcatjss.noarch | JSSE implementation using JSS for Tomcat |
| tomcat.noarch | Apache Servlet/JSP Engine, RI for Servlet 3.0/JSP 2.2 API |
| tomcat-el-2.2-api.noarch | Expression Language v2.2 API |

大体、Apache Tomcatの公式リリースの分け方と似たり寄ったりな感じです。ライブラリjar系が、 tomcat-lib/jsp-2.2-api/servlet-3.0-api/el-2.2-api に分かれてる感じっぽいです。

## インストールしてみる。

とりあえず "tomcat" パッケージだけに絞ってインストールしてみます。

```
$ sudo yum install tomcat

...

Installing:
 tomcat                           noarch 
Installing for dependencies:
 apache-commons-collections       noarch 
 apache-commons-daemon            x86_64 
 apache-commons-dbcp              noarch 
 apache-commons-logging           noarch 
 apache-commons-pool              noarch 
 avalon-framework                 noarch 
 avalon-logkit                    noarch 
 ecj                              x86_64 
 geronimo-jms                     noarch 
 geronimo-jta                     noarch 
 javamail                         noarch 
 log4j                            noarch 
 tomcat-el-2.2-api                noarch 
 tomcat-jsp-2.2-api               noarch 
 tomcat-lib                       noarch 
 tomcat-servlet-3.0-api           noarch 
 xalan-j2                         noarch 
 xerces-j2                        noarch 
 xml-commons-apis                 noarch 
 xml-commons-resolver             noarch 
...
```

なんか、tomcat本体に入ってそうなライブラリまでも、別の依存パッケージに別れてインストールされました。

他のパッケージも入れてみます。tomcatjss は tomcat-native と conflictsしたので今回は見送ります。

```
$ sudo yum install \
  tomcat-webapps \
  tomcat-admin-webapps \
  tomcat-docs-webapp \
  tomcat-javadoc \
  tomcat-native \
  tomcat-jsvc
```

apache-commons-daemon-jsvc , jakarta-taglibs-standard も依存関係でインストールされました。

## tomcat系パッケージのファイル構成

ユーザとグループについて : tomcat パッケージの preinstall script にて、uid=91(tomcat) と gid=91(tomcat) のユーザ・グループをそれぞれ作成されます。

- `/etc/logrotate.d/tomcat`
  - logrotateファイル, `/var/log/tomcat/catalina.out` をcopytruncateしてました。JavaプロセスはUNIXシグナルの受信とかややこしいので、ログローテートようにシグナル送ったりせずに、単純にコピーして空にするのがいいんですかね。でも最近のtomcatって、デフォルトでもcatalina.outなど諸々のログファイル勝手にローテートしてくれた気もする・・・。
- `/etc/sysconfig/tomcat`
  - systemd の `tomcat.service`, `tomcat@.service` unitファイルから参照される環境変数調整用スクリプトファイル。
  - デフォルトの tomcat サービスとは別にtomcatインスタンスをサービスとして管理したい場合は、これを複製することでそのサービス用に環境変数を調整できる仕組みになってる。
  - 詳しくは `tomcat@.service` unit ファイルのコメント参照。
- `/etc/tomcat/`
  - context.xmlやserver.xmlなどtomcatの設定XMLファイル。 tomcat.conf というファイルもあり、これも環境変数調整用のスクリプトファイル
- `/usr/lib/systemd/system/tomcat.service`
  - デフォルト(パッケージ標準？)のtomcatサービス用のunitファイル(後述)
- `/usr/lib/systemd/system/tomcat@.service`
  - デフォルトとは別にtomcatインスタンスを起動してsystemdで管理したい場合のunitファイルの雛形（後述）
  - 実際はこれを `tocmat@othermytomcat8180.service` のようにコピーして、デフォルトのtomcatとは別にTomcatインスタンスをサービスとして管理する。
- `/usr/lib/tmpfiles.d/tomcat.conf`
  - tomcatのPIDファイルについての、systemd-tmpfiles 設定ファイル
- `/usr/libexec/tomcat/server`
  - `tomcat.service` unitファイルから参照される、開始・終了時に実行するスクリプトファイル
- `/usr/sbin/tomcat`
  - Apache Tomcat 本体でいうところとの bin/catalina.sh かな？unitファイル→`/usr/libexec/tomcat/server` の流れだとこのファイル使われてないっぽい？
- `/usr/share/java/`
  - 依存ライブラリパッケージのjarファイルがここに配置される。
- `/usr/share/java/tomcat/`
  - tomcat-lib パッケージのjarファイルがここに配置される。
- `/usr/share/maven-(fragments|poms)/`
  - tomcatや他javaライブラリパッケージのMaven系ファイル
- `/usr/share/tomcat/(bin|conf|lib|logs|temp|webapps)/`
  - binディレクトリにはbootstrap.jar/catalina-tasks.xml/tomcat-juli.jar のみ。ほかはすべて実体のディレクトリへのsymlinkが置いてあるだけ。
- `/var/cache/tomcat/(temp|work)/`
  - コンパイルされたJSPファイルや一時ファイルなど
- `/var/lib/tomcat/webapps/(ROOT|examples|sample)/`
  - Apache Tomcat 本体に含まれている webapps/ 以下のサンプルWebアプリケーション(tomcat-webapps 提供)
- `/var/lib/tomcat/webapps/docs/`
  - Apache Tomcat ドキュメントのWebアプリケーション(tomcat-docs-webapp 提供)
- `/var/lib/tomcat/webapps/(host-manager|manager)/`
  - Apache Tomcat の管理系Webアプリケーション(tomcat-admin-webapps 提供)
- `/var/log/tomcat/catalina.out`
  - Tomcatログファイル

## tomcatサービスの管理

デフォルトの `tomcat.service` :

```
$ sudo systemctl start    tomcat.service
$ sudo systemctl stop     tomcat.service
$ sudo systemctl restart  tomcat.service
$ sudo systemctl enable   tomcat.service
$ sudo systemctl disable  tomcat.service
$ sudo systemctl status   tomcat.service
```

### /usr/lib/systemd/system/tomcat.service

```
# Systemd unit file for default tomcat
#
# To create clones of this service:
# DO NOTHING, use tomcat@.service instead.

[Unit]
Description=Apache Tomcat Web Application Container
After=syslog.target network.target

[Service]
Type=simple
EnvironmentFile=/etc/tomcat/tomcat.conf
Environment="NAME="
EnvironmentFile=-/etc/sysconfig/tomcat
ExecStart=/usr/libexec/tomcat/server start
ExecStop=/usr/libexec/tomcat/server stop
SuccessExitStatus=143
User=tomcat
Group=tomcat


[Install]
WantedBy=multi-user.target
```

ポイント :

- networkとsyslogが起動した後に起動される。
- `[Service]` セクションのポイント
  - `EnvironmentFile=/etc/tomcat/tomcat.conf` でまずグローバルな環境変数を取り込んだ後、`Environment="NAME="` でNAME環境変数を空にして、`EnvironmentFile=-/etc/sysconfig/tomcat` でさらにデフォルトのtomcatサービス用の環境変数を調整する。
    - `EnvironmentFile=` のファイル名が `-` から始まってるのは、そのファイルが存在しなくてもエラーとしないようなオプショナルな扱いにする、という意味。(see `man 5 systemd.exec`)
  - `ExecStart` と `ExecStop` で `/usr/libexec/tomcat/server` スクリプトを起動している。
  - `SuccessExitStatus=143` というのが面白い。
  - `Type=simple` なのは、`/usr/libexec/tomcat/server` スクリプトとの兼ね合いかな・・・？forkingでなくて良いんだ・・・。

### /usr/lib/systemd/system/tomcat@.service

```
# Systemd unit file for tomcat instances.
#
# To create clones of this service:
# 0. systemctl enable tomcat@name.service
# 1. create catalina.base directory structure in
#    /var/lib/tomcats/name
# 2. profit.

[Unit]
Description=Apache Tomcat Web Application Container
After=syslog.target network.target

[Service]
Type=simple
EnvironmentFile=/etc/tomcat/tomcat.conf
Environment="NAME=%I"
EnvironmentFile=-/etc/sysconfig/tomcat@%I
ExecStart=/usr/libexec/tomcat/server start
ExecStop=/usr/libexec/tomcat/server stop
SuccessExitStatus=143
User=tomcat
Group=tomcat

[Install]
WantedBy=multi-user.target
```

ポイント :

- 環境変数の調整で、`Environment="NAME=%I"` になっている。これはunit名の"@"と".service" suffix の間の文字列が、エスケープされて埋め込まれる。この後 `EnvironmentFile=-/etc/sysconfig/tomcat@%I` が取り込まれる。
  - つまりこれをコピーして `tomcat@foo.service` としてunitを登録すれば、`NAME=foo` となって`EnvironmentFile=-/etc/sysconfig/tomcat@foo` が取り込まれることになる。
  - これにより、デフォルト以外のtomcatインスタンスを管理できるようなカスタマイズが行えるようになっている。マイクロサービスアーキテクチャとかで便利かな？

## 感想

- Red Hat や CentOS がサポートしてるパッケージしか使わない！という事情があるならともかく、依存ライブラリ共々、あまりにも「CentOS専用のJavaエコシステム」化してて、ガチガチ過ぎてちょっと辛そう。
- 特にTomcatから依存ライブラリが共通化されてくくりだされてるために、かえって、他のJavaアプリとのjarバージョン地獄が引き起こされる土壌が整ってるようにしか見えない。
- Tomcatのバージョンも7で、今やもう8が出てて9とか出そうなので、実験とかではあんまり便利な状況じゃ無さそう。
- 逆に本当にディストリビューションがサポートしてるパッケージしか使えないのであれば、開発環境から何から何まで、すべてCentOS専用のJavaエコシステムに乗っからざるを得ない。それはすなわち、特にディレクトリ構成について、あまりにも標準からカスタマイズされ過ぎてて、しかもMavenとか他のライブラリパッケージのバージョンと連動しすぎてて、身動きが取れなくなる可能性があるので正直厳しい。

最近の開発や、実際にMaven/GradleなどのJavaビルドシステムの潮流として、なるべく依存性はOSなどシステムグローバルに持たせず、開発する製品単体に収まるようにして、依存関係の衝突が起きないように・・・という感じだと思うんですが、それと容易に衝突しそうなので、そこが心配です。

結論として、あんまり進んで使いたい構成じゃないかも・・・。という感想でした。