/opt/tomcat/
├── tomcat-base/ # 基础安装目录
├── instances/ # 实例目录
│ ├── instance1/ # 实例1
│ ├── instance2/ # 实例2
│ └── instance3/ # 实例3
├── apps/ # 应用部署目录
└── scripts/ # 管理脚本
# 下载Tomcat
cd /opt
wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.85/bin/apache-tomcat-9.0.85.tar.gz
tar -xzf apache-tomcat-9.0.85.tar.gz
mv apache-tomcat-9.0.85 tomcat-base
# 创建必要的目录结构
mkdir -p /opt/tomcat/instances
mkdir -p /opt/tomcat/apps
mkdir -p /opt/tomcat/scripts
mkdir -p /opt/tomcat/logs
创建 /opt/tomcat/scripts/create-instance.sh:
#!/bin/bash
# 创建Tomcat多实例脚本
INSTANCE_NAME=$1
PORT_OFFSET=$2
if [ -z "$INSTANCE_NAME" ] || [ -z "$PORT_OFFSET" ]; then
echo "用法: $0 <实例名称> <端口偏移量>"
echo "例如: $0 myapp 100"
exit 1
fi
INSTANCE_DIR="/opt/tomcat/instances/$INSTANCE_NAME"
BASE_DIR="/opt/tomcat/tomcat-base"
# 创建实例目录
mkdir -p $INSTANCE_DIR
mkdir -p $INSTANCE_DIR/{bin,conf,logs,temp,webapps,work}
# 复制必要的配置文件
cp $BASE_DIR/conf/server.xml $INSTANCE_DIR/conf/
cp $BASE_DIR/conf/web.xml $INSTANCE_DIR/conf/
cp $BASE_DIR/conf/logging.properties $INSTANCE_DIR/conf/
cp $BASE_DIR/conf/tomcat-users.xml $INSTANCE_DIR/conf/
# 创建启动脚本
cat > $INSTANCE_DIR/bin/startup.sh << EOF
#!/bin/bash
export CATALINA_BASE="$INSTANCE_DIR"
export CATALINA_HOME="$BASE_DIR"
export CATALINA_PID="\$CATALINA_BASE/tomcat.pid"
export CATALINA_OPTS="-Xms512m -Xmx1024m -Djava.awt.headless=true"
export JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom"
\$CATALINA_HOME/bin/catalina.sh start
EOF
cat > $INSTANCE_DIR/bin/shutdown.sh << EOF
#!/bin/bash
export CATALINA_BASE="$INSTANCE_DIR"
export CATALINA_HOME="$BASE_DIR"
export CATALINA_PID="\$CATALINA_BASE/tomcat.pid"
\$CATALINA_HOME/bin/catalina.sh stop
EOF
chmod +x $INSTANCE_DIR/bin/*.sh
# 修改server.xml中的端口配置
SHUTDOWN_PORT=$((8005 + PORT_OFFSET))
HTTP_PORT=$((8080 + PORT_OFFSET))
AJP_PORT=$((8009 + PORT_OFFSET))
sed -i "s/8005/$SHUTDOWN_PORT/" $INSTANCE_DIR/conf/server.xml
sed -i "s/8080/$HTTP_PORT/" $INSTANCE_DIR/conf/server.xml
sed -i "s/8009/$AJP_PORT/" $INSTANCE_DIR/conf/server.xml
# 修改日志配置
sed -i "s#\${catalina.base}/logs#/opt/tomcat/logs/${INSTANCE_NAME}#" $INSTANCE_DIR/conf/logging.properties
# 创建日志目录
mkdir -p "/opt/tomcat/logs/${INSTANCE_NAME}"
echo "实例 $INSTANCE_NAME 创建成功!"
echo "HTTP端口: $HTTP_PORT"
echo "Shutdown端口: $SHUTDOWN_PORT"
echo "AJP端口: $AJP_PORT"
# 赋予执行权限
chmod +x /opt/tomcat/scripts/create-instance.sh
# 创建实例
/opt/tomcat/scripts/create-instance.sh webapp1 0 # 端口: 8080, 8005, 8009
/opt/tomcat/scripts/create-instance.sh webapp2 100 # 端口: 8180, 8105, 8109
/opt/tomcat/scripts/create-instance.sh webapp3 200 # 端口: 8280, 8205, 8209
修改每个实例的 tomcat-users.xml:
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users xmlns="http://tomcat.apache.org/xml"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
version="1.0">
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="manager-jmx"/>
<role rolename="manager-status"/>
<role rolename="admin-gui"/>
<user username="admin" password="admin123"
roles="manager-gui,manager-script,manager-jmx,manager-status,admin-gui"/>
</tomcat-users>
创建应用部署目录结构:
# 为每个应用创建目录
mkdir -p /opt/tomcat/apps/{app1,app2,app3}
# 示例:部署一个简单的WAR文件
# 将应用部署到对应的webapps目录
cp /path/to/app1.war /opt/tomcat/instances/webapp1/webapps/
cp /path/to/app2.war /opt/tomcat/instances/webapp2/webapps/ROOT.war # 作为根应用
为每个实例创建systemd服务:
/etc/systemd/system/tomcat-webapp1.service:
[Unit]
Description=Tomcat 9 Instance - webapp1
After=network.target
[Service]
Type=forking
User=tomcat
Group=tomcat
Environment="CATALINA_BASE=/opt/tomcat/instances/webapp1"
Environment="CATALINA_HOME=/opt/tomcat/tomcat-base"
Environment="CATALINA_PID=/opt/tomcat/instances/webapp1/tomcat.pid"
Environment="JAVA_HOME=/usr/lib/jvm/java-11-openjdk"
Environment="JAVA_OPTS=-Xms512m -Xmx1024m -server -XX:+UseParallelGC"
ExecStart=/opt/tomcat/tomcat-base/bin/startup.sh
ExecStop=/opt/tomcat/tomcat-base/bin/shutdown.sh
RestartSec=10
Restart=always
[Install]
WantedBy=multi-user.target
/opt/tomcat/scripts/manage-tomcat.sh:
#!/bin/bash
ACTION=$1
INSTANCE=$2
case "$ACTION" in
start)
systemctl start tomcat-$INSTANCE
;;
stop)
systemctl stop tomcat-$INSTANCE
;;
restart)
systemctl restart tomcat-$INSTANCE
;;
status)
systemctl status tomcat-$INSTANCE
;;
list)
echo "可用的Tomcat实例:"
echo "1. webapp1 (端口: 8080)"
echo "2. webapp2 (端口: 8180)"
echo "3. webapp3 (端口: 8280)"
;;
*)
echo "用法: $0 {start|stop|restart|status|list} [实例名]"
exit 1
esac
配置Nginx实现负载均衡和反向代理:
upstream tomcat_cluster {
least_conn;
server 127.0.0.1:8080 weight=3;
server 127.0.0.1:8180 weight=2;
server 127.0.0.1:8280 weight=1;
keepalive 32;
}
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://tomcat_cluster;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 连接超时设置
proxy_connect_timeout 30s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
# 启用keepalive
proxy_http_version 1.1;
proxy_set_header Connection "";
}
# 静态文件缓存
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
# 健康检查
location /health {
access_log off;
return 200 "healthy\n";
}
}
配置logrotate管理日志:
/etc/logrotate.d/tomcat-instances:
/opt/tomcat/logs/*/*.log {
daily
rotate 30
missingok
compress
delaycompress
notifempty
create 644 tomcat tomcat
sharedscripts
postrotate
/usr/bin/systemctl reload tomcat-*
endscript
}
/opt/tomcat/scripts/monitor-tomcat.sh:
#!/bin/bash
INSTANCES=("webapp1" "webapp2" "webapp3")
PORTS=(8080 8180 8280)
for i in "${!INSTANCES[@]}"; do
INSTANCE=${INSTANCES[$i]}
PORT=${PORTS[$i]}
# 检查进程
PID_FILE="/opt/tomcat/instances/$INSTANCE/tomcat.pid"
if [ -f "$PID_FILE" ]; then
PID=$(cat $PID_FILE)
if ps -p $PID > /dev/null; then
echo "$INSTANCE 运行正常 (PID: $PID)"
# 检查端口监听
if netstat -tlnp 2>/dev/null | grep ":$PORT" | grep -q "$PID"; then
echo " - 端口 $PORT 监听正常"
else
echo " - 警告: 端口 $PORT 未监听"
fi
else
echo "$INSTANCE 进程不存在,尝试重启..."
systemctl restart tomcat-$INSTANCE
fi
else
echo "$INSTANCE 未运行"
fi
# 检查应用状态
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$PORT/health 2>/dev/null || echo "000")
if [ "$RESPONSE" = "200" ]; then
echo " - 应用健康检查通过"
else
echo " - 警告: 应用健康检查失败 (HTTP: $RESPONSE)"
fi
done
<!-- 修改server.xml中的Connector配置 -->
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="200"
minSpareThreads="10"
enableLookups="false"
acceptCount="100"
maxConnections="10000"
connectionTimeout="20000"
disableUploadTimeout="true"
compression="on"
compressionMinSize="2048"
compressableMimeType="text/html,text/xml,text/plain,text/css,text/javascript,application/json"
server="Unknown Server" <!-- 隐藏服务器信息 -->
/>
# 只开放必要的端口
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --add-port=8180/tcp
sudo firewall-cmd --permanent --add-port=8280/tcp
sudo firewall-cmd --reload
/opt/tomcat/scripts/test-deployment.sh:
#!/bin/bash
echo "=== Tomcat多实例部署测试 ==="
echo
# 测试每个实例
echo "1. 测试实例连接:"
curl -s http://localhost:8080 | grep -o "<title>.*</title>"
curl -s http://localhost:8180 | grep -o "<title>.*</title>"
curl -s http://localhost:8280 | grep -o "<title>.*</title>"
echo
echo "2. 测试应用健康状态:"
for port in 8080 8180 8280; do
status=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:$port/ 2>/dev/null)
echo "端口 $port: HTTP $status"
done
echo
echo "3. 检查进程状态:"
ps aux | grep "[j]ava.*catalina.base" | grep -v grep
echo
echo "4. 检查端口监听:"
netstat -tlnp | grep -E ":8080|:8180|:8280"
# 检查端口占用
netstat -tlnp | grep -E "8080|8180|8280"
# 修改端口
# 编辑对应实例的server.xml修改端口号
根据应用需求调整JVM参数:
# 编辑systemd服务文件
JAVA_OPTS="-Xms1g -Xmx2g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"
# 设置正确的文件权限
chown -R tomcat:tomcat /opt/tomcat
chmod -R 755 /opt/tomcat/instances
这个部署方案提供了完整的Tomcat多实例管理框架,可根据实际需求进行调整和扩展。