更新:$Date:: 2014-12-08 18:16:22 +0900#$, $Rev: 287 $
LinuxサーバへTomcat 7.xをインストールし、自動起動するように設定する。
以下の環境・バージョンでインストールを行う。CentOSを使ったけど、RedHat Linuxでも同じはず。
Linux | CentOS 6.4 (64bit) |
---|---|
Java | JDK 7u60 |
Tomcat | 7.0.54 |
手順は次の通り。
TomcatのWebページWhich version?で書かれている通り、Tomcat 7.0.xを動かすにはJavaのバージョン1.6以上が必要である。そのため、まずSunのページ……ではなくOracleのページからJavaをダウンロードしてインストールする。
JavaにはJRE(Javaランタイム環境)とJDK(Java開発キット)がある。どちらを入れるべきか。結論から先に言うと、TomcatはJREでもJDKでもどちらでも動作するが、JDKを入れることを推奨する。
一般的なサーバ構築の知識としては、余計なセキュリティリスクを減らすためにも、開発機(ビルド機)には開発環境(JDK)を入れ、サービス機にはランタイム(JRE)だけ入れておくのがセオリーである。しかし、Tomcatなどを動かすアプリケーションサーバの場合はちょっと事情が違う。例えばJavaVMのメモリ状態を確認するjstatコマンドや、プロセスIDを確認するjpsコマンドは、どちらもJREには入っておらず、JDKを入れないとインストールされない。JavaVMを動かすアプリサーバ運用においてjstatコマンドが使えないのはイタすぎるので、ここは素直にJDKを入れてしまった方が良い、というのが私の結論である。
なおこれは単なる豆知識だが、昔のTomcatを知っている方だと「TomcatはjspコンパイルのためにJREだけじゃ動かないよ?」と思われるかもしれない。しかし最近のTomcat(5.5より後)は、JSPコンパイルのためのEclipse JDTがTomcat配布物に同梱されている。そのため、現在のTomcatはJREのみでも動作する。
というわけで前置きが長くなったが、ここではサービス機の構築を想定してJava SE Downloadsのページから、2014年6月10日現在でJava 1.7系列最新のJava SE 7u60(Version 7 Update 60)のJDKを入れることにする。
JDKの"Download"をクリックするとダウンロードページに行くので、[Accept License Agreement]をクリックしてから、Linux x64のパッケージをダウンロードする。rpm版とtar.gz版があるため、それぞれのインストール方法を以下に述べる。
単にrpmを入れるだけ……なのだが、若干のコツがあるためそれを述べる。
インストールする際は、yumリポジトリを壊さないようにrpm -Uvhではなくyumコマンドを使うようにする。yumには、
# yum install [filename]
のように、installに引数を付けるとリポジトリを探すのではなくローカルファイルをインストールするような動作ができる。この際、依存関係があればそのパッケージも同時に入れてくれるのですこぶる便利である。これはもっと明示的に、以下のようにlocalinstallで書くこともできる。
# yum localinstall [filename]
また、インストール時に署名が無いと怒られる場合があるのでnogpgcheckオプションも付けておく。前置きが長くなったが、要するにJDKのインストールは以下のように実行すれば良いわけだ。
# yum localinstall --nogpgcheck jdk-7u60-linux-x64.rpm
Javaをrpmで入れたなら、環境変数JAVA_HOMEは "/usr/java/default" と設定する必要がある。このへんの事情はちょっとややこしいため、まずはrpmインストール直後はどういうディレクトリ構造になっているのかをちょっと書いておくと:
# pwd /usr/java # ls -al total 12 drwxr-xr-x. 3 root root 4096 Jun 10 21:54 . drwxr-xr-x. 14 root root 4096 Jun 10 21:54 .. lrwxrwxrwx. 1 root root 16 Jun 10 21:54 default -> /usr/java/latest drwxr-xr-x. 8 root root 4096 Jun 10 21:54 jdk1.7.0_60 lrwxrwxrwx. 1 root root 21 Jun 10 21:54 latest -> /usr/java/jdk1.7.0_60
まず、インストールするとjavaコマンドが実際に入っているディレクトリ、[jdk1.7.0_60]ができる。それと同時に、このコマンドが入っているディレクトリに向いているsymlinkの[latest]と、さらにlatestに向いているシンボリックリンク[default]ができる。
default → latest → jdk1.7.0_60/
[latest]は、今後のバージョンアップでも常に最新版を向くsymlinkとなることが保証されている。一方、[default]は普通JAVA_HOMEに設定するパスである。なお、本来ならばrpmでアップデート時にdefaultリンクをそのままにしてくれれば、例えば以下のようにバージョン固定できるのだが……。
実際には、JDKアップグレード時にdefaultまでlatestを向くように書き換えられてしまう。ここは、defaultリンクは放っておいて欲しいんだがなぁ。
持ってきたtar.gzを適当な場所で展開し、出てきた[jdk1.7.0_60]フォルダを /usr/local にコピーしてシンボリックリンクを作っておく。
# tar xvzf jdk-7u60-linux-x64.tar.gz # mv jdk1.7.0_60 /usr/local # cd /usr/local # ln -s jdk1.7.0_60 java
これで、Javaが/usr/local/javaにインストールできた。環境変数JAVA_HOMEには、"/usr/local/java" を設定する。なお以下のTomcat等の例ではrpm版をデフォルトに書いてあるので、tar.gzで入れた人はJAVA_HOMEのところを適当に読み替えてください。
Tomcatをroot権限で実行していると、何かしらのセキュリティホールがあった際にサーバのroot権限が取られてしまうかもしれない。それはセキュリティ上よろしくないので、実行専用のユーザとして、tomcatというアカウントを作成する。このtomcatユーザは、ログインシェルに/sbin/nologinを指定して通常利用はできないようにしておく。
# useradd -s /sbin/nologin tomcat
Tomcatをroot権限で実行することは、現在においては自殺行為なので絶対にしてはいけない。
Tomcatの公式ページよりパッケージをダウンロードする。ダウンロードページには色々あるのだが、[Core:]の中の[tar.gz]をダウンロードすれば良い。7.0.54ならばapache-tomcat-7.0.54.tar.gzというファイルになる。
ダウンロードしたtar.gzファイルを、/usr/localに展開する。展開後、ディレクトリのオーナーをtomcatユーザにしておき、tomcatという名前でシンボリックリンクを作成しておく。
# tar xvzf apache-tomcat-7.0.54.tar.gz # mv apache-tomcat-7.0.54 /usr/local # cd /usr/local # chown -R tomcat:tomcat apache-tomcat-7.0.54 # ln -s apache-tomcat-7.0.54 tomcat
これで、Tomcatが/usr/local/tomcatにインストールできた。
JavaとTomcatをインストールしたので、環境変数JAVA_HOME(JREの場合はJRE_HOME)とCATALINA_HOMEを設定する。どこで設定するかという方針を決めないといけないが、以下では/etc/profile と setenv.sh の2つの手法について述べる。
なお、この辺の設定方法の詳細は、Tomcat同梱のドキュメント RUNNING.txt を読むのが良い。このテキストは分量もコンパクトで分かりやすく書かれているので、必読である。
サーバ全体の設定ならば、/etc/profileに書くのが妥当である。CentOSならば既にファイルは存在しているので、その最終行の後ろにJAVA_HOMEとCATALINA_HOMEの設定を追加してやれば良い。
JAVA_HOME=/usr/java/default CATALINA_HOME=/usr/local/tomcat export JAVA_HOME CATALINA_HOME
上記で、いきなり export JAVA_HOME=/usr/java/default と書かずに、いったんシェル変数に代入してからexportしているのは、私が古代人だからである。……何が言いたいのかというと、つまり、昔のshではexportでいきなり代入することはできず、このように2段階に分けて書かないとダメだった。現代のLinux(CentOS)では/bin/shは実はbashなので、いきなりexport HOGE=fugaと書いても良いのだが、互換性を考慮してこうして分けて書いている。
なお実際に試してみると分かるが、実はCATALINA_HOMEは設定しなくてもたいていの場合は正常に動く。これはstartup.shが叩かれた際、その中で呼ばれるcatalina.shが環境変数CATALINA_HOMEの値をチェックして、自動設定してくれるからである。
(省略)... # Get standard environment variables PRGDIR=`dirname "$PRG"` # Only set CATALINA_HOME if not already set [ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd` (省略)...
もっとも、これはあくまで救済措置であり、CATALINA_HOMEはきちんと設定しておくのが基本であり推奨である。
CATALINA_HOME以外の環境変数については、サーバ共通の/etc/profileに書かずに、Tomcat用にsetenv.shを用いて設定することができる。特にCATALINA_OPTSやJAVA_OPTSをTomcat用に設定したい場合、このsetenv.shに書くのが妥当である。
Tomcatは起動時、startup.shからcatalina.shが実行される。このcatalina.shは、$CATALINA_HOME/binにsetenv.shというファイルが存在するかどうかを調べ、存在すればその中身を実行する……という動きになっている。なお、デフォルトではこのsetenv.shというファイルは存在しないので、必要ならば自分で作成する必要がある。(ドキュメントを読まないと分からないので、意外にこのsetenv.shのやり方は知られていない。私もメールで教えて頂いて、はじめて知った ^^;)。
例えば、JAVA_HOMEの設定と、ヒープメモリの設定を書きたければ、$CATALINA_HOME/bin/setenv.sh というファイルを作って以下のように記述しておけばよい。
JAVA_HOME=/usr/java/default JAVA_OPTS="-Xms1024M -Xmx1024M"
setenv.shにJava起動時のオプションを記載するならば、JAVA_OPTSもしくはCATALINA_OPTSのどちらかに書くことになる。どっちに書いてもほとんど同じなのだが、CATALINA_OPTSは起動時のみに指定されるのに対し、JAVA_OPTSは起動時と停止時の両方に指定される点が異なる。つまり、起動時のみに指定したいオプションはCATALINA_OPTSに書くべきなのだが、相当特殊なオプションを利用しない限り、正直どっちでもいい。
Tomcat運用でよく使われるJavaオプションは、以下の通りである。
オプション | 設定例 | 意味 |
---|---|---|
-Xms | -Xms1024m | Java VM起動時に確保されるヒープメモリサイズ |
-Xmx | -Xmx1024m | Java VMで確保される最大ヒープメモリサイズ |
-XX:MaxPermSize | -XX:MaxPermSize=256m | Java VMで確保されるPermGen領域の最大サイズ |
-verbose:gc | -verbose:gc | GC(ガベージコレクション)時にデバッグ出力する |
-Djava.awt.headless | -Djava.awt.headless=true | グラフィカルサブシステムを利用する・しないを指定してJava VM起動。 |
-Djava.net.preferIPv4Stack | -Djava.net.preferIPv4Stack=true | Java VMがIPv6を利用する・しない。 |
XmsとXmxは、Java VMが使うヒープメモリサイズである。Java VMについてちょっと詳しく書かれた文書を読むと、New領域とかOld領域とか、さらにはEdenとかSurvivor(S1/S2)とか怪しげな単語が出てくるがそれである。アプリケーションが一般的に使うメモリがここだ。サーバの物理メモリの8分の1くらいから2分の1くらいまでの間が目安(かな)。
なお、XmsとXmxで指定した値が違うと、Java VMは最初にメモリをちょびっとだけ確保し、必要になれば拡張していく。この拡張時にオーバーヘッドが生じる(GCが走るからだろう)ため、これを嫌って、XmsとXmxは同じ値にして最初からどかっとメモリ確保してしまうのが現代の定石である。
-XX:MaxPermSizeは、PermGen領域の最大メモリサイズを指定する。これはPermanent領域を指し、ライブラリのために確保されるメモリ領域である(ヒープメモリとは別)。Tomcatならば、コンテキストに同梱しているlib(jarファイル)のサイズが目安になる。「java.lang.OutOfMemoryError: PermGen space」というエラーが出るとこの値を増やす必要がある。
-verbose:gcは、GC(ガベージコレクション)発生時にCatalina.outにログを出してくれる。特にFull GCはとてもコストの高い処理なので、Tomcatアプリの動作が遅いときには、GCが走っているか? というのを見極めることが重要なポイントとなる。そのためこのログは運用時に常に付けることを好む人も多い。
-Djava.awt.headlessは、headlessモードの指定をする。GUI環境が無い(Xを動かしていないとか)LinuxサーバでAWTの機能を使う際、これを指定しないとエラーになる場合がある。これは現代のサーバサイドJavaでは常にtrueにしておいて良いだろう。
-Djava.net.preferIPv4Stackは、Java VMがIPv6を無視する。Tomcatを使う場合にIPv6を利用するのは地雷を踏みに行く以外の何物でもないので、サーバはIPv4で組んでこのオプションにtrueを指定するのが定石中の定石である。
というわけでまとめると、以下のような例がありがちかな。
setenv.sh: JAVA_HOME=/usr/java/default JAVA_OPTS="-Xms1024m -Xmx1024m -XX:MaxPermSize=256m -verbose:gc -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true"
前述のcatalina.shの中を覗いてみると分かるけど、Tomcatは起動時にクラスパスを強制クリアしている。その代わり(?)に、setclasspath.shというファイルがあればその中身を読み込んでくれる。
(省略)... # Ensure that any user defined CLASSPATH variables are not used on startup, # but allow them to be specified in setenv.sh, in rare case when it is needed. CLASSPATH= (省略)... # Get standard Java environment variables if $os400; then # -r will Only work on the os400 if the files are: # 1. owned by the user # 2. owned by the PRIMARY group of the user # this will not work if the user belongs in secondary groups . "$CATALINA_HOME"/bin/setclasspath.sh else if [ -r "$CATALINA_HOME"/bin/setclasspath.sh ]; then . "$CATALINA_HOME"/bin/setclasspath.sh else echo "Cannot find $CATALINA_HOME/bin/setclasspath.sh" echo "This file is needed to run this program" exit 1 fi fi
このため、自前で設定したいものがある場合、setenv.shと同様にsetclasspath.shで設定してやればよい。
以下の内容で /etc/init.d/tomcat として設置する。設置後、chmod +xして実行権限を付けること。priority(35 65)は、サーバに合わせて適宜変えると良い。
#!/bin/bash # # Startup script for the Tomcat Servlet Container # # chkconfig: 2345 35 65 # description: Tomcat is the servlet container that is used in the official \ # Reference Implementation for the Java Servlet and JavaServer \ # Pages technologies TOMCAT_USER=tomcat CATALINA_HOME=/usr/local/tomcat . /etc/rc.d/init.d/functions prog=tomcat start() { echo -n $"Starting $prog: " daemon --user $TOMCAT_USER $CATALINA_HOME/bin/startup.sh > /dev/null RETVAL=$? if [ $RETVAL -eq 0 ]; then echo_success else echo_failure fi echo [ $RETVAL = 0 ] && touch /var/lock/subsys/$prog return $RETVAL } stop() { echo -n $"Stopping $prog: " daemon --user $TOMCAT_USER $CATALINA_HOME/bin/shutdown.sh > /dev/null RETVAL=$? if [ $RETVAL -eq 0 ]; then echo_success else echo_failure fi echo [ $RETVAL = 0 ] && rm -f /var/lock/subsys/$prog return $RETVAL } # See how we were called. case "$1" in start) start ;; stop) stop ;; restart) stop start ;; status) INSTANCES=`ps --columns 512 -aef|grep java|grep tomcat|grep org.apache.catalina.startup.Bootstrap|wc -l` if [ $INSTANCES -eq 0 ]; then echo $prog is stopped RETVAL=3 else if [ $INSTANCES -eq 1 ]; then echo $prog is running 1 instance... else echo $prog is running $INSTANCES instances... fi RETVAL=0 fi ;; *) echo $"Usage: $prog {start|stop|restart|status|help}" exit 1 esac exit $RETVAL
tomcat起動スクリプトファイルを/etc/init.dに設置したら、chkconfigコマンドで自動起動するように登録しておく。
# /sbin/chkconfig --add tomcat
設置できたら、rootになって実行してみる。
# cd /etc/init.d # ./tomcat start
起動後、http://(サーバのIPアドレス):8080 にアクセスしてみて、Tomcatの起動画面を確認する。上手くいかなければ、/usr/local/tomcat/logs/catalina.out の中身を確認する。
なお、起動スクリプトを使わずに手でstartup.shを実行したい場合、tomcatユーザはログイン不可にしているため、以下のようにsudoコマンドの-uオプションを使ってtomcat権限で実行する。
# cd /usr/local/tomcat/bin # sudo -u tomcat ./startup.sh
参考書としては、オライリーのTomcatハンドブックが良い。
この本はTomcat 6なので正直ちょっと古いのだが、日本語で読めるまともな書籍はこれしか無いのが事実。電子版もあるのでPDFで買うと吉かも。
なお、このTomcatハンドブックは色々と問題があって、一言でいうとTomcat礼賛が激しすぎる。「Apache httpdなんて全然たいしたことないから!!! 代わりにTomcatのWebサーバこんなにすごいから!!!! Tomcatはスゴいんだからroot権限で動かしたってセキュリティ的に問題なんて無いし!!!!」みたいな記述は、ニヤニヤしながら全部無視する必要がある。
Tomcatを使ってセッションレプリケーションのクラスタ構成を組むやり方も書きました:ApacheとTomcatでクラスタリング
Tomcatは、OracleのJavaではなく、OpenJDKで動かすこともできる。エンタープライズな実績的には当然OracleのJavaの方が過去の事例が山ほどあるけど、今後はOpenJDKが主流になっていくかもしれない。
Tomcatをデーモンとして実行するためには、Tomcatに付属しているjsvc toolというのを使う方法もある。しかし、これを使うには自分でビルドする必要があったり、/usr/lib/libcap.so が無いと言われたり色々ややこしかったので、私は使わない方針にしている。
シェルスクリプトの本を書きました。このページがお役に立った方でシェルスクリプトに興味のある方、ぜひ買ってちょ。サーバ監視など、インフラ周りの豆知識的なことも結構載せているので役に立つと思います!(たぶん)
Kindle版もあります。