更新:$Date:: 2014-12-08 18:16:22 +0900#$, $Rev: 287 $

概要

LinuxサーバへTomcat 7.xをインストールし、自動起動するように設定する。

環境

以下の環境・バージョンでインストールを行う。CentOSを使ったけど、RedHat Linuxでも同じはず。

LinuxCentOS 6.4 (64bit)
JavaJDK 7u60
Tomcat7.0.54

手順は次の通り。

  1. Java (JDK 1.7)のインストール
  2. Tomcat管理ユーザの作成
  3. Tomcatのインストール
  4. 環境変数の設定 (JAVA_HOMEなど)
  5. 自動起動スクリプト /etc/init.d/tomcat の設置
  6. 起動確認

Java (JDK 1.7)のインストール

TomcatのWebページWhich version?で書かれている通り、Tomcat 7.0.xを動かすにはJavaのバージョン1.6以上が必要である。そのため、まずSunのページ……ではなくOracleのページからJavaをダウンロードしてインストールする。

JREかJDKか

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版があるため、それぞれのインストール方法を以下に述べる。

JDKのインストール(rpm版)

単にrpmを入れるだけ……なのだが、若干のコツがあるためそれを述べる。

yum localinstallを使う

インストールする際は、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リンクは放っておいて欲しいんだがなぁ。

JDKのインストール(tar.gz版)

持ってきた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管理ユーザの作成

Tomcatをroot権限で実行していると、何かしらのセキュリティホールがあった際にサーバのroot権限が取られてしまうかもしれない。それはセキュリティ上よろしくないので、実行専用のユーザとして、tomcatというアカウントを作成する。このtomcatユーザは、ログインシェルに/sbin/nologinを指定して通常利用はできないようにしておく。

# useradd -s /sbin/nologin tomcat

Tomcatをroot権限で実行することは、現在においては自殺行為なので絶対にしてはいけない。


Tomcatのインストール

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_HOMEなど)

JavaとTomcatをインストールしたので、環境変数JAVA_HOME(JREの場合はJRE_HOME)とCATALINA_HOMEを設定する。どこで設定するかという方針を決めないといけないが、以下では/etc/profile と setenv.sh の2つの手法について述べる。

なお、この辺の設定方法の詳細は、Tomcat同梱のドキュメント RUNNING.txt を読むのが良い。このテキストは分量もコンパクトで分かりやすく書かれているので、必読である。

/etc/profile

サーバ全体の設定ならば、/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はきちんと設定しておくのが基本であり推奨である。

setenv.sh

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"

JAVA_OPTSとCATALINA_OPTS

setenv.shにJava起動時のオプションを記載するならば、JAVA_OPTSもしくはCATALINA_OPTSのどちらかに書くことになる。どっちに書いてもほとんど同じなのだが、CATALINA_OPTSは起動時のみに指定されるのに対し、JAVA_OPTSは起動時と停止時の両方に指定される点が異なる。つまり、起動時のみに指定したいオプションはCATALINA_OPTSに書くべきなのだが、相当特殊なオプションを利用しない限り、正直どっちでもいい。

Tomcat運用でよく使われるJavaオプションは、以下の通りである。

オプション設定例意味
-Xms-Xms1024mJava VM起動時に確保されるヒープメモリサイズ
-Xmx-Xmx1024mJava VMで確保される最大ヒープメモリサイズ
-XX:MaxPermSize-XX:MaxPermSize=256mJava VMで確保されるPermGen領域の最大サイズ
-verbose:gc-verbose:gcGC(ガベージコレクション)時にデバッグ出力する
-Djava.awt.headless-Djava.awt.headless=trueグラフィカルサブシステムを利用する・しないを指定してJava VM起動。
-Djava.net.preferIPv4Stack-Djava.net.preferIPv4Stack=trueJava 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"

classpath.sh

前述の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 の設置

以下の内容で /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権限で動かしたってセキュリティ的に問題なんて無いし!!!!」みたいな記述は、ニヤニヤしながら全部無視する必要がある。

最後に宣伝

シェルスクリプトの本を書きました。このページがお役に立った方でシェルスクリプトに興味のある方、ぜひ買ってちょ。サーバ監視など、インフラ周りの豆知識的なことも結構載せているので役に立つと思います!(たぶん)

Kindle版もあります。


プログラミングメモ

▲HOME

▲ABOUT ME