← ← 返回资讯列表

某民航机场除冰雪作业管理系统Tomcat 11安全升级实录

关键词:民航 / 除冰雪作业管理 / Tomcat 11 升级 / CMSServerV6 / 漏洞修复  处理日期:2026-10-26  停机窗口:约20分钟  业务影响:升级后正常

导读

某民航机场除冰雪作业管理系统是保障冬季航班除冰作业调度的业务系统,漏扫发现其 Tomcat 11.0.20 存在已知安全漏洞,需升级至 11.0.27 消除告警。系统部署在 /opt/CMSServerV6/ 目录下,属于第三方套件式部署(自带 JDK、附带 geocode 等多个子组件),升级中先后遇到四个典型问题:直接解压覆盖会毁掉定制配置、shutdown.sh 报 JVM 创建失败、JDK 位置藏在旧 tomcat 目录内部、以及升级后应用访问 404(lib 第三方库漏迁)。本案例完整记录排查与实施过程,供同类套件化部署的中间件升级参考。

一、现场与环境

项目内容
业务系统某民航机场除冰雪作业管理系统
服务器Linux(云服务器)
中间件Apache Tomcat 11.0.20,套件式部署于 /opt/CMSServerV6/tomcat
部署特点套件自带 JDK 17.0.0.1(位于 tomcat 目录内),另有 geocode 子组件独立 java 进程运行
系统默认 java1.8.0_452(与 Tomcat 11 要求的 JDK 17+ 不符)
升级目标Apache Tomcat 11.0.27(当前最新稳定补丁版,覆盖 11.0.21~11.0.27 全部安全修复)

二、四个坑,逐个拆解

坑一:能否直接解压覆盖旧目录?——不能

最初的设想是备份后把新包直接解压覆盖到 /opt/CMSServerV6/tomcat。这个方案有致命缺陷:

tar 解压覆盖同名文件:conf/server.xml、conf/web.xml、lib/ 下的文件会被新版默认版本盖掉,而套件对 server.xml 有定制(端口、Context、连接器参数),覆盖后轻则配置丢失、重则服务起不来

覆盖不删除多余文件:旧版残留的 jar 与新 jar 混在 lib/ 里,可能引发类加载冲突

正确做法是「旧目录整体挪走 + 新包解压到干净位置 + 定向迁移」,路径保持不变,套件的其他脚本无感知

坑二:shutdown.sh 报 could not create the java virtual machine

执行停止脚本时报 JVM 创建失败。原因:shutdown.sh 本身也要启动一个 JVM 向 Tomcat 发停止指令,而当前 shell 的 java 是系统默认的 1.8——Tomcat 11 的启动参数(--add-opens 等)JDK 8 根本不认识,直接拒绝启动。

排查命令与关键发现:

java -version # java version "1.8.0_452" ← 系统默认,不满足 Tomcat 11 要求 ps -ef | grep [c]atalina # 输出显示旧 Tomcat 进程实际使用的是: # /opt/CMSServerV6/tomcat/jdk-17.0.0.1/bin/java # ← 套件自带 JDK 17,且就放在 tomcat 目录内部

结论:机器上不缺 JDK 17,只是 shell 环境变量指向了 1.8。旧进程能跑,靠的是套件自带的 jdk-17.0.0.1。

shutdown 无法使用时的处置(对 Tomcat 安全):

kill <catalina进程PID> sleep 5; ps -ef | grep [c]atalina # 仍在则 kill -9

坑三:JDK 藏在旧 tomcat 目录里,挪目录等于把 JDK 也挪走了

这是本次最隐蔽的问题:套件把 jdk-17.0.0.1 安装在 /opt/CMSServerV6/tomcat/ 内部。按标准流程「mv tomcat tomcat_old」后,新解压的 tomcat 目录里没有这个 JDK——如果 setenv.sh 里 JAVA_HOME 指向旧路径,虽然还能跑,但目录结构混乱;如果指向新目录内路径,则直接找不到 java。

处置:把 JDK 拷回新目录,保持套件原有目录结构:

cp -a /opt/CMSServerV6/tomcat_old/jdk-17.0.0.1 /opt/CMSServerV6/tomcat/

另注意:同目录下还有 geocode 子组件(java -jar gpsPars.jar 独立进程),升级 Tomcat 期间不要误杀,也不受本次升级影响。

坑四:升级后应用访问 404 —— lib 第三方库漏迁(最终真凶)

现象:新版 Tomcat 启动正常、8080 端口在监听、catalina.out 无 SEVERE 报错,webapps/gpsweb 目录也已迁移到位,但访问业务地址返回 404。

排查过程(按此顺序,5 分钟定位):

# 1. 确认应用是否真的在(排除迁移遗漏) ls -la /opt/CMSServerV6/tomcat/webapps/ # → gpsweb、gpsweb_bak20261022_11、host-manager、manager 均在 # 2. 确认端口与进程(排除 Tomcat 没起来) ss -tlnp | grep java # 8080 正常监听 # 3. 查应用部署是否报错(排除 listenerStart 失败) grep -iE "Deploying|Deployment of|SEVERE|Error listenerStart|Exception" \ /opt/CMSServerV6/tomcat/logs/catalina.out | tail -40 # → 仅有 Http11InputBuffer.parseRequestLine 等请求解析堆栈(扫描器/异常请求噪音),无部署失败 # 4. 对比新旧 lib 目录(命中) diff <(ls /opt/CMSServerV6/tomcat_old/lib) <(ls /opt/CMSServerV6/tomcat/lib) # → 旧 lib 比新 lib 多出 2 个 jar(套件自带的定制库),升级时未迁移

根因:CMSServerV6 套件把 2 个自有 jar 放在 Tomcat 的 lib/ 目录下(共享类加载器级别),应用 gpsweb 启动时依赖它们。升级时按「只补第三方 jar」的原则对比了 lib,但这一步在首轮实施中被漏做,导致应用虽被部署,加载类时失败 → 应用未真正可用 → 访问 404。

修复:

# 把旧 lib 中多出的 2 个 jar 补到新 lib cp -a /opt/CMSServerV6/tomcat_old/lib/<缺失jar1>.jar /opt/CMSServerV6/tomcat/lib/ cp -a /opt/CMSServerV6/tomcat_old/lib/<缺失jar2>.jar /opt/CMSServerV6/tomcat/lib/ # 再次 diff 确认只差 Tomcat 自带版本文件(不应再有业务 jar 缺失) diff <(ls /opt/CMSServerV6/tomcat_old/lib) <(ls /opt/CMSServerV6/tomcat/lib) # 重启并验证 export JAVA_HOME=/opt/CMSServerV6/tomcat/jdk-17.0.0.1 /opt/CMSServerV6/tomcat/bin/shutdown.sh; sleep 5 /opt/CMSServerV6/tomcat/bin/startup.sh tail -f /opt/CMSServerV6/tomcat/logs/catalina.out curl -sI http://127.0.0.1:8080/gpsweb | head -3 # 期望 200/302,不再 404

补 jar 后应用正常加载,业务访问恢复,404 消除。

附带问题:启动日志出现 “The APR based Apache Tomcat Native library was not found on the java.library.path”。这是旧 server.xml 中保留了 AprLifecycleListener / Http11AprProtocol 配置,而 Tomcat 11 已移除 APR 支持所致——属警告不影响运行。彻底消除的方法:删除 conf/server.xml 中的 AprLifecycleListener 监听器行,并把 Connector 的 protocol 由 Http11AprProtocol 改为 Http11NioProtocol(或删除 protocol 属性,默认即 NIO)。NIO 是 Tomcat 11 的主力实现,性能无损。

三、实施步骤(实际执行序列)

备份:tar czf 打包整个 /opt/CMSServerV6/tomcat 目录

停服:kill catalina 主进程(shutdown.sh 因 JDK8 环境无法使用),确认进程退出、端口释放

挪目录:mv /opt/CMSServerV6/tomcat /opt/CMSServerV6/tomcat_old

解压新包:tar xzf apache-tomcat-11.0.27.tar.gz -C /opt/CMSServerV6/ 并改名为 tomcat(保持路径不变,套件脚本无感)

拷回套件自带 JDK:cp -a tomcat_old/jdk-17.0.0.1 tomcat/

迁移应用:cp -a tomcat_old/webapps/* tomcat/webapps/

合并配置:diff 新旧 conf/server.xml,将旧文件中的定制项(端口、Connector、Context)合并进新文件,不整文件覆盖

迁移第三方 jar(本次 404 的真凶,务必执行):diff <(ls tomcat_old/lib) <(ls tomcat/lib),把旧 lib 多出的第三方/套件自带 jar 全部补到新 lib(CMSServerV6 有 2 个自有 jar 放在 lib 下,漏迁会导致应用部署成功但类加载失败、访问 404);Tomcat 自带 jar 不覆盖

写 setenv.sh 固定 JDK:export JAVA_HOME=/opt/CMSServerV6/tomcat/jdk-17.0.0.1,避免再受系统默认 java 1.8 干扰

权限对齐:chown/chmod 与旧目录一致,bin/*.sh 加执行权限

启动验证:startup.sh + tail catalina.out,确认 Server version: Apache Tomcat/11.0.27 与 Server startup 无 SEVERE 报错;并用 curl -sI http://127.0.0.1:8080/gpsweb 验证应用返回非 404(仅看进程和端口不够,必须验应用层)

业务验证:除冰雪作业管理系统各功能页面访问正常

work/ 目录未迁移:JSP 编译缓存由新版自动重建(迁移旧缓存反而可能引发类加载异常)

版本确认方式:

JAVA_HOME=/opt/CMSServerV6/tomcat/jdk-17.0.0.1 /opt/CMSServerV6/tomcat/bin/version.sh # Server version: Apache Tomcat/11.0.27 grep "Server version" /opt/CMSServerV6/tomcat/logs/catalina.out | tail -1

四、回退方案(未触发)

全程采用「旧目录保留 + 新目录就位」方式,回退只需两条命令,秒级恢复:

kill <新catalina进程> rm -rf /opt/CMSServerV6/tomcat && mv /opt/CMSServerV6/tomcat_old /opt/CMSServerV6/tomcat /opt/CMSServerV6/tomcat/bin/startup.sh

回退触发条件:应用启动失败且窗口期内无法定位、核心业务功能异常。本次升级一次成功,未触发回退。旧目录 tomcat_old 与备份包建议保留至少一个月。

五、可复用的经验清单

套件化部署(CMSServerV6 这类)升级前必须先摸清三件事:JDK 在哪(可能藏在应用目录内)、conf 定制了什么、还有哪些兄弟组件(geocode)共用环境。ps -ef 看运行中进程的实际 java 路径,比查环境变量可靠。

shutdown.sh 报 could not create the java virtual machine,先查 java -version——十有八九是 shell 默认 JDK 版本过低,不认识新版 Tomcat 的 JVM 参数。此时 kill 进程是安全的替代停止方式。

升级用 setenv.sh 显式固定 JAVA_HOME,不要依赖系统默认 java,彻底隔离系统 JDK 与中间件 JDK。

永远不要解压覆盖旧目录:挪走旧目录、新包解压到干净位置、定向迁移 webapps/conf 定制项/lib 第三方 jar,路径保持不变让上层脚本无感。

conf 逐文件 diff 合并、lib 只补不覆、work 不迁移——中间件升级三条铁律。

同大版本补丁升级(11.0.20→11.0.27)无 API 变更,应用零改动;升级直接选最新补丁版,不要停留在中间版本。

民航等关键业务系统升级:备份先行、低峰窗口、回退方案先写好再动手、旧目录保留观察期。

升级完成后可顺手加固:server.xml Connector 加 server="WebServer" 隐藏版本响应头,避免漏扫指纹识别;8005 SHUTDOWN 端口确认仅监听 127.0.0.1。

升级后验证必须验到应用层:进程在、端口监听、日志无 SEVERE 都不等于业务可用。用 curl -I 打一次业务 URL,返回 404 就说明应用没真正加载起来——本次 404 就是这样被发现的。

应用 404 而 Tomcat 正常时的排查顺序:webapps 有没有应用 → 端口/进程 → catalina.out 的部署与 listenerStart 报错 → diff 新旧 lib → server.xml 的 Context/appBase 配置。第五步之前先做第四步(lib 对比)命中率最高。

套件式部署常把自有 jar 放在 Tomcat 的 lib/(共享类加载器)而非 WEB-INF/lib,这类依赖最容易在升级中漏迁,且失败表现是「部署成功但访问 404」而非启动报错,隐蔽性极强。lib 迁移必须用 diff 双向对比,不能靠肉眼。

Tomcat 11 已移除 APR/Tomcat Native 支持,沿用旧 server.xml 会每次启动打印 APR 警告。删除 AprLifecycleListener、Connector 协议改 NIO 即可消除,性能无损失。

服务说明

项目内容
客户场景机场除冰雪作业管理系统(民航冬季运行保障业务)
服务内容Tomcat 11.0.20 → 11.0.27 安全升级,漏洞修复闭环
风险等级低(补丁级升级 + 完整备份 + 秒级回退方案)
停机窗口约 40 分钟(含 404 排查与 lib 补迁),业务验证通过
技术要点套件自带 JDK 识别与迁移、setenv.sh 固定 JAVA_HOME、conf/lib 定向合并、lib 第三方 jar 漏迁导致应用 404 的定位与修复、APR 警告消除
可提供服务中间件(Tomcat/Nginx/Redis/MySQL)安全升级与漏洞修复、Linux 服务器运维托管、Docker/1Panel 容器环境故障排查、民航及政企信息系统运维支持、应急响应

相关推荐