踩坑无数!Tomcat部署项目的那些年,我总结出这套保命指南

踩坑无数!Tomcat部署项目的那些年,我总结出这套保命指南

前言

image-20250817215422535image-20250817215422535

应粉丝朋友的要求,写一篇关于tomcat部署的文章。希望能够帮助到大家!!!说起Tomcat部署项目,我想每个搞Java开发和运维的兄弟都有一肚子话要说。记得接触那会儿,看着那个小猫咪的logo还觉得挺可爱,结果第一次部署项目就被它折腾得死去活来。

这些年下来,从Tomcat 6到现在的Tomcat 11,各种版本都碰过,踩的坑能绕地球三圈。今天就跟大家聊聊Tomcat部署项目的那些事儿,希望能帮后来的兄弟们少走点弯路。

Tomcat到底是个啥玩意儿可能有些刚入门的朋友还不太清楚Tomcat是干什么的,我简单说说。

Tomcat其实就是一个Web服务器,更准确地说是一个Servlet容器。什么意思呢?就是专门用来跑Java Web应用的。你写的那些JSP、Servlet,打包成war文件,就是丢给Tomcat来运行的。

它是Apache软件基金会开发的开源项目,完全免费。相比其他的应用服务器比如WebLogic、WebSphere这些商业产品,Tomcat轻量级很多,配置也相对简单。这也是为什么这么多公司选择它的原因。

Tomcat的架构其实挺有意思的,它有几个核心组件:

• Catalina:这是Servlet容器的实现,负责处理Servlet和JSP• Coyote:HTTP连接器,处理HTTP请求• Jasper:JSP引擎,把JSP编译成Servlet说白了,当用户在浏览器里访问你的网站时,请求先到Coyote,然后交给Catalina处理,如果是JSP页面就用Jasper编译。整个流程就是这样。

我记得刚开始学的时候,总是搞不清楚Tomcat和Apache HTTP Server的区别。简单说,Apache HTTP Server主要处理静态内容,而Tomcat专门处理动态的Java内容。当然,Tomcat也能处理静态文件,但性能没有Apache HTTP Server好。所以生产环境经常是Apache + Tomcat的组合,Apache在前面做反向代理。

现在市面上还有其他选择,比如Jetty、Undertow这些,但Tomcat的市场占有率还是最高的。主要是生态成熟,文档齐全,遇到问题容易找到解决方案。

Tomcat目录结构,这些你得搞清楚解压完Tomcat后,看到一堆目录可能会懵,我来给大家介绍一下各个目录的作用。了解这些对后面的配置和部署很重要。

代码语言:javascript复制apache-tomcat-9.0.80/

├── bin/ # 可执行文件目录

├── conf/ # 配置文件目录

├── lib/ # 类库目录

├── logs/ # 日志文件目录

├── temp/ # 临时文件目录

├── webapps/ # Web应用部署目录

└── work/ # 工作目录bin目录这里放的都是可执行文件,最常用的几个:

• startup.sh/startup.bat:启动脚本• shutdown.sh/shutdown.bat:关闭脚本• catalina.sh/catalina.bat:核心启动脚本,startup其实就是调用它• version.sh/version.bat:查看版本信息我经常用到的还有setenv.sh,这个文件默认不存在,需要自己创建。在里面可以设置JVM参数,比startup.sh里设置更规范:

代码语言:javascript复制#!/bin/bash

export JAVA_OPTS="-Xms2048m -Xmx4096m -server"

export CATALINA_OPTS="-Dfile.encoding=UTF-8"conf目录配置文件都在这里,核心的几个文件:

• server.xml:主配置文件,定义端口、连接器等• web.xml:全局web应用配置• context.xml:全局Context配置• tomcat-users.xml:用户权限配置• logging.properties:日志配置还有个Catalina目录,里面是各个虚拟主机的配置。默认有个localhost目录,我们经常在里面放Context配置文件。

webapps目录imgimg

这是应用部署的地方,默认会有几个示例应用:

• ROOT:根应用,访问http://localhost:8080就是它• examples:示例应用,有各种Servlet和JSP例子• docs:文档应用• manager:管理应用,可以通过web界面管理其他应用• host-manager:虚拟主机管理生产环境建议把除了ROOT以外的都删掉,安全考虑。

logs目录日志文件存放位置,主要的几个:

• catalina.out:标准输出日志,最重要的一个• catalina.YYYY-MM-DD.log:Catalina引擎日志• localhost.YYYY-MM-DD.log:localhost虚拟主机日志• manager.YYYY-MM-DD.log:manager应用日志• access_log.YYYY-MM-DD.txt:访问日志(需要配置才有)排查问题时,catalina.out是必看的,应用启动失败的信息基本都在里面。

work目录这是Tomcat的工作目录,主要存放:

• JSP编译后的Servlet类文件• Session序列化文件• 其他临时文件一般不需要手动操作这个目录,但有时候JSP修改后不生效,可以删除对应的编译文件强制重新编译。

lib目录存放Tomcat运行需要的jar包,包括:

• Servlet API• JSP API• Tomcat核心类库如果有全局的第三方jar包,也可以放在这里,但不建议。最好还是放在应用的WEB-INF/lib下。

我之前遇到过一个坑,项目用了某个jar包的新版本,但lib目录里有旧版本,结果类冲突各种奇怪问题。所以lib目录里的东西,没事别乱动。

temp目录临时文件目录,Tomcat运行时可能会在这里创建临时文件。一般也不需要关注,但要确保有写权限。

了解了这些目录结构,部署和配置就心里有数了。特别是webapps、conf、logs这三个,是经常要打交道的。

环境准备这块,真的不能马虎部署之前,环境搭建是第一步。别小看这个步骤,我见过太多因为环境问题导致后面一堆麻烦的案例。

JDK版本选择Tomcat对JDK版本是有要求的,这个兼容性表格我建议大家收藏:

• Tomcat 10.x 需要 Java 11+• Tomcat 9.x 支持 Java 8+• Tomcat 8.x 支持 Java 7+我之前就遇到过一个哭笑不得的情况,项目用的Tomcat 10,结果服务器上装的是Java 8,启动的时候各种报错。当时还以为是配置问题,折腾了半天才发现是版本不匹配。

检查JDK版本很简单:

代码语言:javascript复制java -version

javac -version记住,这两个版本号要一致,不然可能会有奇怪的问题。

java环境安装教程:https://blog.csdn.net/Coin_Collecter/article/details/136825041

Tomcat下载和解压去Apache官网下载Tomcat,建议下载tar.gz格式的,zip有时候在Linux下会有权限问题。

官网地址:https://tomcat.apache.org/index.html

image-20250817214904835image-20250817214904835

代码语言:javascript复制wget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.108/bin/apache-tomcat-9.0.108.tar.gz

tar -xzf apache-tomcat-9.0.108.tar.gz

mv apache-tomcat-9.0.108 /opt/tomcat解压完记得检查一下目录结构,确保bin、conf、webapps这些关键目录都在。

配置systemd服务,一键启停真香手动启停Tomcat太麻烦了,每次都要cd到bin目录执行脚本。更要命的是服务器重启后还得手动启动。配置成systemd服务就方便多了,开机自启、一键重启,运维必备技能。

创建tomcat用户首先创建专门的tomcat用户,安全考虑不要用root跑服务:

代码语言:javascript复制# 创建系统用户

sudo useradd -r -m -U -d /opt/tomcat -s /bin/false tomcat

# 设置目录权限

sudo chown -R tomcat:tomcat /opt/tomcat

sudo chmod +x /opt/tomcat/bin/*.sh这里用-s /bin/false是为了安全,这个用户不能登录shell。

创建systemd服务文件在/etc/systemd/system/目录下创建tomcat.service文件:

代码语言:javascript复制sudo vim /etc/systemd/system/tomcat.service内容如下:

代码语言:javascript复制[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=-Xms2048M -Xmx4096M -server -XX:+UseParallelGC"

Environment="JAVA_OPTS=-Djava.awt.headless=true -Djava.security.egd=file:/dev/./urandom"

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

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

RestartSec=10

Restart=always

[Install]

WantedBy=multi-user.target这里几个关键配置解释一下:

• Type=forking:因为startup.sh会fork出子进程• CATALINA_PID:指定pid文件位置,方便管理• RestartSec=10:服务异常退出后10秒重启• Restart=always:总是重启,除非手动停止环境变量配置JAVA_HOME路径要根据实际情况调整,可以用这个命令查看:

代码语言:javascript复制sudo update-alternatives --config java如果有多个Java版本,选择对应的路径。

重载并启动服务配置完成后重载systemd配置:

代码语言:javascript复制# 重载systemd配置

sudo systemctl daemon-reload

# 启动tomcat服务

sudo systemctl start tomcat

# 查看服务状态

sudo systemctl status tomcat

# 设置开机自启

sudo systemctl enable tomcat如果启动失败,用journalctl查看详细日志:

代码语言:javascript复制sudo journalctl -u tomcat.service -f常用管理命令配置好后,管理Tomcat就方便多了:

代码语言:javascript复制# 启动服务

sudo systemctl start tomcat

# 停止服务

sudo systemctl stop tomcat

# 重启服务

sudo systemctl restart tomcat

# 重新加载配置(不重启进程)

sudo systemctl reload tomcat

# 查看服务状态

sudo systemctl status tomcat

# 查看服务日志

sudo journalctl -u tomcat.service

# 开机自启

sudo systemctl enable tomcat

# 禁用开机自启

sudo systemctl disable tomcat配置过程中的坑我在配置systemd服务时踩过几个坑:

1. JAVA_HOME路径错误:一定要用绝对路径,相对路径可能找不到2. 权限问题:tomcat用户要有执行bin目录下脚本的权限3. PID文件路径:temp目录要有写权限,不然创建不了pid文件4. 环境变量:JVM参数最好在这里设置,不要在catalina.sh里改我把JAVA_HOME设置成了/usr/bin/java,结果一直启动失败。后来才知道要设置到JDK的根目录,不是可执行文件路径。

高级配置如果需要更精细的控制,可以加一些高级配置:

代码语言:javascript复制[Unit]

Description=Apache Tomcat Web Application Container

After=network.target

Wants=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=-Xms2048M -Xmx4096M -server -XX:+UseG1GC"

Environment="JAVA_OPTS=-Djava.awt.headless=true -Dfile.encoding=UTF-8"

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

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

ExecReload=/bin/kill -s HUP $MAINPID

# 超时设置

TimeoutStartSec=300

TimeoutStopSec=30

# 重启策略

RestartSec=10

Restart=on-failure

# 资源限制

LimitNOFILE=65536

LimitNPROC=4096

[Install]

WantedBy=multi-user.target这样配置后,Tomcat就完全融入到systemd管理体系中了。服务器重启自动启动,异常退出自动重启,再也不用担心服务挂掉了。

基础配置调优,这些参数得改默认的Tomcat配置基本上只能跑个Hello World,生产环境肯定不够用。

server.xml核心配置打开conf/server.xml,这个文件是Tomcat的心脏。

代码语言:javascript复制

connectionTimeout="20000"

maxThreads="200"

minSpareThreads="10"

maxSpareThreads="100"

acceptCount="100"

redirectPort="8443" />这里面几个关键参数:

• maxThreads:最大线程数,根据你的服务器配置调整• connectionTimeout:连接超时时间,20秒一般够用• acceptCount:等待队列长度,超过这个数就拒绝连接我一般会把maxThreads调到500左右,但这个要根据实际情况。记得有次为了提高并发,直接调到2000,结果服务器内存爆了,那叫一个酸爽。

JVM参数优化在bin/catalina.sh(Windows是catalina.bat)里加上JVM参数:

代码语言:javascript复制export JAVA_OPTS="-Xms2048m -Xmx4096m -XX:PermSize=256m -XX:MaxPermSize=512m -Djava.awt.headless=true"内存分配这块要注意,Xms是初始内存,Xmx是最大内存。我的经验是Xms设置为Xmx的一半到三分之二比较合适。

项目部署的几种姿势WAR包部署最常见的方式,把war包丢到webapps目录下就行。Tomcat会自动解压部署。

代码语言:javascript复制cp myproject.war /opt/tomcat/webapps/但是有个坑,如果你的war包名字有特殊字符或者中文,可能会有问题。我建议统一用英文小写加下划线的命名方式。

部署完可以看看logs/catalina.out,确认部署成功:

代码语言:javascript复制tail -f /opt/tomcat/logs/catalina.out目录部署有时候为了方便调试,会直接把解压后的项目目录放到webapps下:

代码语言:javascript复制mkdir /opt/tomcat/webapps/myproject

cp -r /path/to/project/* /opt/tomcat/webapps/myproject/这种方式的好处是可以直接修改文件,不用重新打包。但生产环境不建议这么搞。

Context配置部署在conf/Catalina/localhost/下创建xml文件:

代码语言:javascript复制

这种方式比较灵活,项目可以放在任意位置。

那些年踩过的坑端口冲突问题默认8080端口经常被占用,特别是开发环境。检查端口占用:

代码语言:javascript复制netstat -tlnp | grep 8080

lsof -i:8080如果被占用了,要么杀掉占用进程,要么改Tomcat端口。改端口在server.xml里:

代码语言:javascript复制权限问题Linux下经常遇到权限问题,特别是日志写不进去:

代码语言:javascript复制chown -R tomcat:tomcat /opt/tomcat

chmod +x /opt/tomcat/bin/*.sh我建议专门创建一个tomcat用户来运行服务,不要用root。

内存溢出这个问题太常见了,特别是PermGen space错误。Java 8以后用MetaSpace替代了PermGen,但还是要注意:

代码语言:javascript复制export JAVA_OPTS="$JAVA_OPTS -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m"中文乱码这个问题困扰了我很久,主要是编码设置不统一。在server.xml的Connector里加上:

代码语言:javascript复制

URIEncoding="UTF-8"

useBodyEncodingForURI="true" />监控和日志管理日志配置Tomcat的日志配置在conf/logging.properties里。我一般会调整日志级别和输出格式:

代码语言:javascript复制org.apache.catalina.core.ContainerBase.[Catalina].level = INFO

org.apache.catalina.core.ContainerBase.[Catalina].handlers = java.util.logging.ConsoleHandler性能监控可以开启JMX监控:

代码语言:javascript复制export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote"

export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.port=9999"

export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.authenticate=false"

export CATALINA_OPTS="$CATALINA_OPTS -Dcom.sun.management.jmxremote.ssl=false"然后用JConsole或者VisualVM连接监控。

生产环境部署注意事项安全配置生产环境一定要关闭不必要的功能:

1. 删除webapps下的默认应用(ROOT、examples、docs、manager)2. 修改默认端口3. 配置访问控制在server.xml里可以配置访问限制:

代码语言:javascript复制

allow="192\.168\.1\.\d+|127\.0\.0\.1" />集群部署如果需要集群,可以配置session复制:

代码语言:javascript复制

expireSessionsOnShutdown="false"

notifyListenersOnReplication="true"/>

不过说实话,现在更多是用Nginx做负载均衡,session用Redis存储。

自动化部署脚本手动部署容易出错,我写了个简单的部署脚本:

代码语言:javascript复制#!/bin/bash

APP_NAME="myproject"

TOMCAT_HOME="/opt/tomcat"

WAR_PATH="/tmp/${APP_NAME}.war"

# 停止Tomcat

$TOMCAT_HOME/bin/shutdown.sh

# 备份旧版本

if [ -d "$TOMCAT_HOME/webapps/$APP_NAME" ]; then

mv $TOMCAT_HOME/webapps/$APP_NAME $TOMCAT_HOME/webapps/${APP_NAME}_backup_$(date +%Y%m%d_%H%M%S)

fi

# 部署新版本

cp $WAR_PATH $TOMCAT_HOME/webapps/

# 启动Tomcat

$TOMCAT_HOME/bin/startup.sh

# 检查部署状态

sleep 10

curl -I http://localhost:8080/$APP_NAME常见问题排查启动失败看catalina.out日志,一般都能找到原因。常见的有:

• 端口被占用• JDK版本不兼容• 配置文件语法错误• 权限不足应用无法访问检查几个方面:

1. 防火墙是否开放端口2. 应用是否正确部署3. Context路径是否正确代码语言:javascript复制# 检查防火墙

firewall-cmd --list-ports

# 或者

iptables -L

# 检查应用状态

curl -I http://localhost:8080/myproject性能问题用jstack和jmap分析:

代码语言:javascript复制# 查看线程堆栈

jstack > thread_dump.txt

# 查看内存使用

jmap -histo Docker化部署现在很多项目都容器化了,Tomcat也不例外。写个简单的Dockerfile:

代码语言:javascript复制FROM tomcat:9.0-jdk11

# 删除默认应用

RUN rm -rf /usr/local/tomcat/webapps/*

# 复制应用

COPY myproject.war /usr/local/tomcat/webapps/ROOT.war

# 复制配置文件

COPY server.xml /usr/local/tomcat/conf/

EXPOSE 8080

CMD ["catalina.sh", "run"]构建和运行:

代码语言:javascript复制docker build -t myproject:latest .

docker run -d -p 8080:8080 --name myproject myproject:latest容器化的好处是环境一致性,但也要注意日志和数据的持久化。

总结Tomcat部署项目看起来简单,但要做好还是有很多细节需要注意。从环境准备到配置优化,从安全设置到性能监控,每个环节都不能马虎。

我这些年的经验告诉我,部署不是一锤子买卖,需要持续的监控和优化。特别是生产环境,一定要做好备份和回滚准备。

记住几个关键点:

• 环境兼容性检查不能省• 配置参数要根据实际情况调整• 安全配置在生产环境必须做• 监控和日志要跟上• 自动化部署能减少人为错误希望这篇文章能帮到正在和Tomcat较劲的兄弟们。部署这活儿,经验很重要,多踩几个坑就熟练了。

如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步!

公众号:运维躬行录

个人博客:躬行笔记

相关推荐

摩拜单车怎样一元骑(摩拜单车3小时收费多少?)
365bet亚洲唯一官网

摩拜单车怎样一元骑(摩拜单车3小时收费多少?)

📅 10-31 👁️ 2031
874是什麼意思
365bet亚洲唯一官网

874是什麼意思

📅 11-26 👁️ 8633
全球十大恐怖事件真实案例,17岁女孩被凌虐四个礼拜
365sport365中文版

全球十大恐怖事件真实案例,17岁女孩被凌虐四个礼拜

📅 07-31 👁️ 5863
Softbank光太慢了!如何靠改成IPv6来有效提速?
365sport365中文版

Softbank光太慢了!如何靠改成IPv6来有效提速?

📅 11-12 👁️ 213
2025年十款热门打奶器产品榜 精选电动打奶泡器商品推荐
best365网页登录不上去

2025年十款热门打奶器产品榜 精选电动打奶泡器商品推荐

📅 09-30 👁️ 8168
出手即证明!耐克携手中国男篮发布世界杯系列产品
365sport365中文版

出手即证明!耐克携手中国男篮发布世界杯系列产品

📅 08-03 👁️ 7615