Apache Tomcat
Jakarta EE仕様を実装するオープンソースのJava Webアプリケーションサーバー。純粋なJavaによるHTTP Webサーバー環境。軽量で効率的な実行。
アプリケーションサーバー
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 "%r" %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"