お仕事では、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など諸々のログファイル勝手にローテートしてくれた気もする・・・。
- logrotateファイル,
-
/etc/sysconfig/tomcat
- systemd の
tomcat.service
,tomcat@.service
unitファイルから参照される環境変数調整用スクリプトファイル。 - デフォルトの tomcat サービスとは別にtomcatインスタンスをサービスとして管理したい場合は、これを複製することでそのサービス用に環境変数を調整できる仕組みになってる。
- 詳しくは
tomcat@.service
unit ファイルのコメント参照。
- systemd の
-
/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
の流れだとこのファイル使われてないっぽい?
- Apache Tomcat 本体でいうところとの bin/catalina.sh かな?unitファイル→
-
/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=
のファイル名が-
から始まってるのは、そのファイルが存在しなくてもエラーとしないようなオプショナルな扱いにする、という意味。(seeman 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などシステムグローバルに持たせず、開発する製品単体に収まるようにして、依存関係の衝突が起きないように・・・という感じだと思うんですが、それと容易に衝突しそうなので、そこが心配です。
結論として、あんまり進んで使いたい構成じゃないかも・・・。という感想でした。