前言
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复制 代码语言: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 # 查看内存使用 jmap -histo 代码语言: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较劲的兄弟们。部署这活儿,经验很重要,多踩几个坑就熟练了。 如果这篇文章对你有帮助,别忘了点赞转发支持一下!想了解更多运维实战经验和技术干货,记得关注微信公众号@运维躬行录,领取学习大礼包!!!我会持续分享更多接地气的运维知识和踩坑经验。让我们一起在运维这条路上互相学习,共同进步! 公众号:运维躬行录 个人博客:躬行笔记