Apache Tomcat

Jakarta EE仕様を実装するオープンソースのJava Webアプリケーションサーバー。純粋なJavaによるHTTP Webサーバー環境。軽量で効率的な実行。

アプリケーションサーバーJavaJakarta EEServletJSPWebサーバーオープンソース

アプリケーションサーバー

Apache Tomcat

概要

Apache Tomcatは、Jakarta EE(旧Java EE)仕様を実装するオープンソースのJava Webアプリケーションサーバーです。純粋なJavaで実装されたHTTP Webサーバー環境として、Servletコンテナ、JSPエンジンの機能を提供します。軽量で効率的な実行が可能で、Java Webアプリケーションサーバーとして広く採用され、エンタープライズ環境での実績も豊富です。

詳細

Apache Tomcatは1999年にリリースされ、Java Webアプリケーション開発において最も重要なサーバーソフトウェアの一つです。現在もJakarta EE移行に対応し、継続的なアップデートで安定性を維持しています。軽量でありながら高性能で、開発環境から本番環境まで幅広く使用されています。

主要な技術的特徴

  • Servletコンテナ: Jakarta Servlet API実装
  • JSPエンジン: JavaServer Pages処理
  • Webサーバー機能: HTTP/HTTPSサーバー
  • クラスタリング: 負荷分散とセッション複製
  • セキュリティ: JNDI、SSL/TLS、認証・認可
  • 管理ツール: Web管理画面とMBean監視

用途

  • Java Webアプリケーション実行
  • RESTful API開発
  • エンタープライズWebサービス
  • マイクロサービス基盤
  • 開発・テスト環境
  • レガシーアプリケーション移行

メリット・デメリット

メリット

  • 軽量性: フル機能のJava EEサーバーより軽量
  • 安定性: 長年の実績と継続的な改善
  • オープンソース: 無償で商用利用可能
  • 豊富なドキュメント: 充実した技術情報
  • 強力なコミュニティ: Apache Software Foundation支援
  • 標準準拠: Jakarta EE仕様完全対応

デメリット

  • 機能制限: フルJava EEサーバーと比較して機能が限定的
  • メモリ使用量: Java VMのメモリオーバーヘッド
  • 起動時間: 大規模アプリケーションでの起動時間
  • 複雑な設定: 本格的な本番環境設定の複雑さ
  • JVM依存: Java仮想マシンのバージョン依存

インストール・基本設定

前提条件

# Java Runtime Environment/JDKの確認
java -version
javac -version

# Java 11以上が推奨(Tomcat 10.1以降)
# Java 8以上が必須(Tomcat 9.0)

Tomcatのインストール

tarball版(推奨)

# Tomcatのダウンロード
cd /opt
sudo wget https://archive.apache.org/dist/tomcat/tomcat-10/v10.1.34/bin/apache-tomcat-10.1.34.tar.gz

# 展開とシンボリックリンク作成
sudo tar xzf apache-tomcat-10.1.34.tar.gz
sudo ln -s apache-tomcat-10.1.34 tomcat

# tomcatユーザーの作成
sudo useradd -r -s /bin/false tomcat
sudo chown -R tomcat:tomcat /opt/tomcat/

パッケージマネージャー

# Ubuntu/Debian
sudo apt update
sudo apt install tomcat9

# CentOS/RHEL
sudo yum install tomcat
# または
sudo dnf install tomcat

基本設定

環境変数設定(setenv.sh)

# bin/setenv.sh
export JAVA_HOME="/usr/lib/jvm/java-11-openjdk"
export CATALINA_HOME="/opt/tomcat"
export CATALINA_BASE="/opt/tomcat"
export CATALINA_OPTS="-Xms512m -Xmx2048m -XX:PermSize=256m -XX:MaxPermSize=512m"
export JAVA_OPTS="-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom"

サーバー設定(server.xml)

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
  <Listener className="org.apache.catalina.core.AprLifecycleListener" />
  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />

  <GlobalNamingResources>
    <Resource name="UserDatabase" auth="Container"
              type="org.apache.catalina.UserDatabase"
              description="User database that can be updated and saved"
              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
              pathname="conf/tomcat-users.xml" />
  </GlobalNamingResources>

  <Service name="Catalina">
    <!-- HTTP Connector -->
    <Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443"
               maxThreads="200"
               minSpareThreads="10" />

    <!-- HTTPS Connector -->
    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="200" SSLEnabled="true">
      <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
                     type="RSA" />
      </SSLHostConfig>
    </Connector>

    <Engine name="Catalina" defaultHost="localhost">
      <Host name="localhost" appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        <Valve className="org.apache.catalina.valves.AccessLogValve"
               directory="logs"
               prefix="localhost_access_log" suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />
      </Host>
    </Engine>
  </Service>
</Server>

アプリケーション配置

WARファイル配置

# アプリケーション配置
sudo cp myapp.war /opt/tomcat/webapps/

# 自動展開確認
ls -la /opt/tomcat/webapps/

コンテキスト設定

<!-- conf/Catalina/localhost/myapp.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="/opt/myapp/myapp.war" 
         reloadable="true"
         crossContext="false">
  
  <!-- データソース設定 -->
  <Resource name="jdbc/myDB" 
            auth="Container"
            type="javax.sql.DataSource"
            driverClassName="com.mysql.cj.jdbc.Driver"
            url="jdbc:mysql://localhost:3306/mydb"
            username="dbuser"
            password="dbpass"
            maxTotal="20"
            maxIdle="10"
            maxWaitMillis="10000"/>
            
  <!-- 環境変数設定 -->
  <Environment name="app.environment" value="production" type="java.lang.String"/>
</Context>

web.xml設定例

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                             https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd"
         version="6.1">

  <display-name>My Web Application</display-name>

  <!-- セッション設定 -->
  <session-config>
    <session-timeout>30</session-timeout>
    <cookie-config>
      <http-only>true</http-only>
      <secure>true</secure>
    </cookie-config>
  </session-config>

  <!-- サーブレット定義 -->
  <servlet>
    <servlet-name>ApiServlet</servlet-name>
    <servlet-class>com.example.ApiServlet</servlet-class>
    <init-param>
      <param-name>config</param-name>
      <param-value>/WEB-INF/api-config.properties</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>ApiServlet</servlet-name>
    <url-pattern>/api/*</url-pattern>
  </servlet-mapping>

  <!-- フィルター設定 -->
  <filter>
    <filter-name>CorsFilter</filter-name>
    <filter-class>com.example.CorsFilter</filter-class>
  </filter>
  
  <filter-mapping>
    <filter-name>CorsFilter</filter-name>
    <url-pattern>/api/*</url-pattern>
  </filter-mapping>

  <!-- エラーページ -->
  <error-page>
    <error-code>404</error-code>
    <location>/error/404.jsp</location>
  </error-page>

  <error-page>
    <error-code>500</error-code>
    <location>/error/500.jsp</location>
  </error-page>
</web-app>

パフォーマンス最適化

JVM最適化

# bin/setenv.sh での JVM 調整
export CATALINA_OPTS="
  -server
  -Xms2g -Xmx4g
  -XX:NewRatio=3
  -XX:+UseG1GC
  -XX:MaxGCPauseMillis=200
  -XX:G1HeapRegionSize=16m
  -XX:+UseStringDeduplication
  -XX:+UnlockExperimentalVMOptions
  -XX:+UseCGroupMemoryLimitForHeap
  -Djava.awt.headless=true
  -Djava.security.egd=file:/dev/./urandom
  -Dfile.encoding=UTF-8
"

コネクター調整

<!-- server.xml でのコネクター調整 -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           maxThreads="400"
           minSpareThreads="50"
           maxConnections="10000"
           acceptCount="100"
           enableLookups="false"
           disableUploadTimeout="true"
           compression="on"
           compressionMinSize="2048"
           compressableMimeType="text/html,text/xml,text/css,text/javascript,application/javascript,application/json" />

APR/Native設定

# APR (Apache Portable Runtime) インストール
# Ubuntu/Debian
sudo apt install libapr1-dev libssl-dev

# CentOS/RHEL
sudo yum install apr-devel openssl-devel

# Tomcat Native ライブラリビルド
cd $CATALINA_HOME/bin
tar -xzf tomcat-native.tar.gz
cd tomcat-native-*/native
./configure --with-apr=/usr/bin/apr-1-config --with-ssl=yes
make && sudo make install

セキュリティ設定

SSL/TLS設定

# キーストア作成
$JAVA_HOME/bin/keytool -genkey -alias tomcat -keyalg RSA -keysize 2048 \
  -validity 365 -keystore conf/keystore.jks \
  -storepass changeit -keypass changeit \
  -dname "CN=localhost, OU=IT, O=MyCompany, L=Tokyo, S=Tokyo, C=JP"
<!-- HTTPS コネクター設定 -->
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="200" SSLEnabled="true">
  <SSLHostConfig protocols="TLSv1.2,TLSv1.3"
                 ciphers="TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,ECDHE-RSA-AES256-GCM-SHA384"
                 honorCipherOrder="true">
    <Certificate certificateKeystoreFile="conf/keystore.jks"
                 certificateKeystorePassword="changeit"
                 type="RSA" />
  </SSLHostConfig>
</Connector>

セキュリティ管理者設定

<!-- conf/tomcat-users.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
  <role rolename="manager-gui"/>
  <role rolename="manager-script"/>
  <role rolename="admin-gui"/>
  <user username="admin" password="{bcrypt}$2a$10$..." roles="manager-gui,admin-gui"/>
  <user username="deployer" password="{bcrypt}$2a$10$..." roles="manager-script"/>
</tomcat-users>

セキュリティバルブ

<!-- Remote Address Valve -->
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
       allow="127\.0\.0\.1|192\.168\..*|10\..*" />

<!-- CSRF Protection -->
<Valve className="org.apache.catalina.filters.CsrfPreventionFilter" />

<!-- Security Headers -->
<filter>
  <filter-name>httpHeaderSecurity</filter-name>
  <filter-class>org.apache.catalina.filters.HttpHeaderSecurityFilter</filter-class>
  <init-param>
    <param-name>hstsEnabled</param-name>
    <param-value>true</param-value>
  </init-param>
</filter>

本番環境運用

Systemd サービス設定

# /etc/systemd/system/tomcat.service
[Unit]
Description=Apache Tomcat Web Application Container
After=network.target

[Service]
Type=forking
User=tomcat
Group=tomcat

Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk
Environment=CATALINA_PID=/opt/tomcat/temp/tomcat.pid
Environment=CATALINA_HOME=/opt/tomcat
Environment=CATALINA_BASE=/opt/tomcat
Environment="CATALINA_OPTS=-Xms512M -Xmx1024M -server -XX:+UseParallelGC"

ExecStart=/opt/tomcat/bin/startup.sh
ExecStop=/opt/tomcat/bin/shutdown.sh

RestartSec=10
Restart=always

[Install]
WantedBy=multi-user.target

Docker設定

FROM openjdk:11-jre-slim

# Tomcat環境変数
ENV CATALINA_HOME /usr/local/tomcat
ENV PATH $CATALINA_HOME/bin:$PATH

# Tomcatインストール
WORKDIR $CATALINA_HOME
RUN set -eux; \
    apt-get update; \
    apt-get install -y --no-install-recommends \
        curl \
    ; \
    rm -rf /var/lib/apt/lists/*; \
    \
    curl -fSL https://archive.apache.org/dist/tomcat/tomcat-10/v10.1.34/bin/apache-tomcat-10.1.34.tar.gz \
        | tar -xzf - --strip-components=1; \
    \
    nativeBuildDir="$(mktemp -d)"; \
    tar -xzf bin/tomcat-native.tar.gz -C "$nativeBuildDir" --strip-components=1; \
    apt-get purge -y --auto-remove curl

# 権限設定
RUN chmod +x bin/*.sh

# ポート公開
EXPOSE 8080 8443

CMD ["catalina.sh", "run"]

監視設定

<!-- JMX設定 -->
<Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleListener"
          rmiRegistryPortPlatform="10001"
          rmiServerPortPlatform="10002" />
# JMX接続オプション
export CATALINA_OPTS="$CATALINA_OPTS 
  -Dcom.sun.management.jmxremote
  -Dcom.sun.management.jmxremote.port=9999
  -Dcom.sun.management.jmxremote.authenticate=false
  -Dcom.sun.management.jmxremote.ssl=false"

管理・メンテナンス

Manager Application

# デプロイ
curl -u admin:password -X PUT \
  http://localhost:8080/manager/text/deploy?path=/myapp \
  --upload-file myapp.war

# アンデプロイ
curl -u admin:password \
  http://localhost:8080/manager/text/undeploy?path=/myapp

# アプリケーション一覧
curl -u admin:password \
  http://localhost:8080/manager/text/list

ログ監視

# アクセスログ
tail -f /opt/tomcat/logs/localhost_access_log.$(date +%Y-%m-%d).txt

# カタリナログ
tail -f /opt/tomcat/logs/catalina.out

# アプリケーションログ
tail -f /opt/tomcat/logs/localhost.$(date +%Y-%m-%d).log

バックアップスクリプト

#!/bin/bash
# backup-tomcat.sh

BACKUP_DIR="/backup/tomcat"
DATE=$(date +%Y%m%d_%H%M%S)
TOMCAT_HOME="/opt/tomcat"

# Tomcat停止
systemctl stop tomcat

# バックアップ作成
mkdir -p $BACKUP_DIR
tar -czf $BACKUP_DIR/tomcat_$DATE.tar.gz \
  $TOMCAT_HOME/conf \
  $TOMCAT_HOME/webapps \
  $TOMCAT_HOME/logs

# Tomcat再起動
systemctl start tomcat

echo "Backup completed: tomcat_$DATE.tar.gz"

トラブルシューティング

メモリ不足対応

# ヒープダンプ取得
jmap -dump:format=b,file=heapdump.hprof <tomcat_pid>

# メモリ使用状況確認
jstat -gc <tomcat_pid> 5s

パフォーマンス分析

# スレッドダンプ取得
jstack <tomcat_pid> > threaddump.txt

# GCログ有効化
export CATALINA_OPTS="$CATALINA_OPTS -Xloggc:gc.log -XX:+PrintGCDetails"

参考ページ