手把手教你:Spring Boot WAR 包部署到 Docker 中的 Tomcat 容器(2026企业级实战版)
适用场景公司要求统一用外部 Tomcat 集群、旧系统依赖 Tomcat、需要多应用共享 Tomcat核心解决Spring Boot 改 WAR 包踩坑、Dockerfile 编写、端口映射、时区问题、日志挂载、镜像优化新手看完就能一步步跟着做老手看完能避90%的坑开篇为什么要把 Spring Boot 打成 WAR 包部署到 Docker TomcatSpring Boot 默认打可执行 JAR 包内置 Tomcat简单方便但很多企业场景必须用外部 Tomcat公司统一用 Tomcat 集群管理所有应用有旧系统依赖 Tomcat 的特定配置/组件需要多应用共享同一个 Tomcat 实例节省资源。但部署到 Docker 又容易踩坑找不到主类、WAR 包放错位置端口映射不对、访问 404日志时间差 8 小时、看不到日志镜像太大、构建慢。本文从0 到 1 完整实战一次性解决所有问题一、前置准备必须先搞定工具版本要求作用JDK17Spring Boot 3.x/ 8Spring Boot 2.x编译运行项目Maven3.9打包项目Docker20.10构建运行容器简单 Spring Boot 项目-用于演示部署Docker 快速安装新手看这里Windows/Mac直接下载 Docker Desktop一键安装Linux执行以下命令安装 Docker CEcurl-fsSLhttps://get.docker.com|bash-sdocker--mirrorAliyun systemctl startdockersystemctlenabledocker二、核心步骤1Spring Boot 项目改造为 WAR 包90%的人在这里踩坑2.1 修改 pom.xml?xml version1.0 encodingUTF-8?projectxmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersionparentgroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-parent/artifactIdversion3.3.0/version!-- 必须和你的Spring Boot版本一致 --relativePath//parent!-- 1. 核心修改packaging改为war --packagingwar/packaginggroupIdcom.example/groupIdartifactIddemo/artifactIdversion1.0.0/versionnamedemo/namedescriptionDemo project for Spring Boot/descriptionpropertiesjava.version17/java.version!-- 2. 指定WAR包名字可选方便Dockerfile引用 --project.build.finalNamedemo/project.build.finalName/propertiesdependenciesdependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId!-- 3. 核心修改排除内置Tomcat --exclusionsexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactId/exclusion/exclusions/dependency!-- 4. 添加Tomcat依赖scopeprovided打包时不包含 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactIdscopeprovided/scope/dependency!-- 测试依赖可选 --dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope/dependency/dependenciesbuildplugins!-- 5. Spring Boot官方插件打包WAR包 --plugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdversion3.3.0/version!-- 必须和Spring Boot版本一致 --/plugin!-- 6. Maven WAR插件可选配置WAR包细节 --plugingroupIdorg.apache.maven.plugins/groupIdartifactIdmaven-war-plugin/artifactIdversion3.4.0/versionconfiguration!-- 允许没有web.xmlSpring Boot项目不需要 --failOnMissingWebXmlfalse/failOnMissingWebXml/configuration/plugin/plugins/build/project2.2 修改启动类关键启动类必须继承SpringBootServletInitializer重写configure方法告诉外部 Tomcat 启动类在哪里packagecom.example.demo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;importorg.springframework.boot.builder.SpringApplicationBuilder;importorg.springframework.boot.web.servlet.support.SpringBootServletInitializer;SpringBootApplicationpublicclassDemoApplicationextendsSpringBootServletInitializer{// 1. 继承SpringBootServletInitializerpublicstaticvoidmain(String[]args){SpringApplication.run(DemoApplication.class,args);}// 2. 重写configure方法指定启动类OverrideprotectedSpringApplicationBuilderconfigure(SpringApplicationBuilderapplication){returnapplication.sources(DemoApplication.class);}}2.3 写个测试接口验证部署用packagecom.example.demo.controller;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;RestControllerpublicclassTestController{GetMapping(/)publicStringtest(){return✅ Spring Boot WAR 包部署到 Docker Tomcat 成功;}GetMapping(/hello)publicStringhello(){returnHello Docker Tomcat!;}}2.4 本地打包测试先确保WAR包能正常运行# 1. 跳过测试打包mvn clean package-DskipTests# 2. 打包成功后target目录下会有demo.war三、核心步骤2编写 Dockerfile部署的灵魂在项目根目录下创建Dockerfile注意没有后缀名这是构建 Docker 镜像的核心3.1 基础版 Dockerfile新手直接用# 1. 基础镜像官方Tomcat JDK17Spring Boot3.x用 # Spring Boot2.x用 tomcat:9-jdk8-temurin FROM tomcat:17-jdk17-temurin # 2. 维护者信息可选 LABEL maintaineryourname youremail.com # 3. 核心修改设置时区解决日志时间差8小时的问题 ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone # 4. 核心修改删除Tomcat默认的webapps文件避免冲突 RUN rm -rf /usr/local/tomcat/webapps/* # 5. 核心修改复制WAR包到Tomcat的webapps目录 # 注意demo.war要和pom.xml里的project.build.finalName一致 # 改成ROOT.war可以直接访问根路径不用加项目名 COPY target/demo.war /usr/local/tomcat/webapps/ROOT.war # 6. 暴露端口Tomcat默认8080 EXPOSE 8080 # 7. 启动Tomcat CMD [catalina.sh, run]3.2 进阶版 Dockerfile多阶段构建镜像缩小70%基础版镜像包含了 Maven 构建的中间文件很大多阶段构建只保留最终的 WAR 包和 Tomcat镜像更小# 第一阶段构建WAR包临时镜像不会保留 FROM maven:3.9.6-eclipse-temurin-17 AS builder WORKDIR /app # 先复制pom.xml利用Docker缓存避免每次都下载依赖 COPY pom.xml . RUN mvn dependency:go-offline -B # 再复制源码构建WAR包 COPY src ./src RUN mvn clean package -DskipTests # 第二阶段运行Tomcat最终镜像 FROM tomcat:17-jdk17-temurin LABEL maintaineryourname youremail.com ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone RUN rm -rf /usr/local/tomcat/webapps/* # 从第一阶段的builder镜像复制WAR包 COPY --frombuilder /app/target/demo.war /usr/local/tomcat/webapps/ROOT.war EXPOSE 8080 CMD [catalina.sh, run]四、核心步骤3构建镜像 运行容器4.1 构建 Docker 镜像在项目根目录下执行注意最后有个.表示 Dockerfile 在当前目录# 构建镜像命名为demo-tomcat标签为1.0dockerbuild-tdemo-tomcat:1.0.4.2 查看构建好的镜像dockerimages# 输出示例# REPOSITORY TAG IMAGE ID CREATED SIZE# demo-tomcat 1.0 abc123def456 10 seconds ago 320MB多阶段构建# demo-tomcat 1.0 xyz789ghi012 1 minute ago 850MB基础版4.3 运行 Docker 容器# 基础运行命令dockerrun-d-p8080:8080--namedemo-tomcat-container demo-tomcat:1.0参数详解参数作用-d后台运行容器-p 8080:8080端口映射宿主机端口:容器端口把容器的8080映射到宿主机的8080--name demo-tomcat-container给容器起个名字方便后续操作demo-tomcat:1.0使用的镜像名和标签五、核心步骤4验证部署 查看日志5.1 验证容器是否运行dockerps# 输出示例# CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES# abc123def456 demo-tomcat:1.0 catalina.sh run 10 seconds ago Up 8 seconds 0.0.0.0:8080-8080/tcp demo-tomcat-container5.2 浏览器访问验证打开浏览器访问根路径http://localhost:8080因为我们把WAR包改成了ROOT.war测试接口http://localhost:8080/hello如果看到✅ Spring Boot WAR 包部署到 Docker Tomcat 成功说明部署成功5.3 查看 Tomcat 日志排查问题必备# 查看实时日志-f 表示实时跟踪dockerlogs-fdemo-tomcat-container# 查看最后100行日志dockerlogs--tail100demo-tomcat-container六、90%的人都会踩的坑避坑指南必看坑1访问 404 Not Found原因WAR包没有复制到/usr/local/tomcat/webapps/WAR包名字不是ROOT.war访问路径需要加项目名比如http://localhost:8080/demo内置Tomcat没有排除导致冲突。解决检查Dockerfile的COPY命令把WAR包改成ROOT.war确保pom.xml里排除了内置Tomcat。坑2找不到主类 / 启动失败原因启动类没有继承SpringBootServletInitializer没有重写configure方法JDK版本不匹配Spring Boot3.x用JDK172.x用JDK8。解决检查启动类的代码确保Dockerfile的基础镜像JDK版本和项目一致。坑3日志时间差 8 小时原因Docker容器默认时区是UTC比中国时区Asia/Shanghai慢8小时。解决Dockerfile里必须加时区设置ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone坑4宿主机 8080 端口被占用原因宿主机上已经有程序占用了8080端口比如本地Tomcat、Nginx。解决查看端口占用Windowsnetstat -ano | findstr 8080Linux/Maclsof -i:8080换个宿主机端口比如映射到8081dockerrun-d-p8081:8080--namedemo-tomcat-container demo-tomcat:1.0# 访问http://localhost:8081坑5Dockerfile 构建失败原因Dockerfile不在项目根目录WAR包名字不对和pom.xml里的project.build.finalName不一致没有先执行mvn clean package基础版Dockerfile。解决确保Dockerfile在项目根目录检查WAR包名字基础版Dockerfile必须先打包多阶段构建不需要。七、进阶优化企业级必备7.1 挂载日志目录方便查看日志不用进容器把容器的Tomcat日志目录挂载到宿主机方便查看和备份dockerrun-d-p8080:8080\-v/home/demo/logs:/usr/local/tomcat/logs\--namedemo-tomcat-container\demo-tomcat:1.0/home/demo/logs宿主机日志目录自己创建/usr/local/tomcat/logs容器Tomcat日志目录7.2 挂载配置文件修改配置不用重新构建镜像把application.yml挂载到宿主机修改配置后重启容器即可# 1. 先在宿主机创建配置目录mkdir-p/home/demo/config# 2. 把application.yml放到这个目录# 3. 运行容器时挂载dockerrun-d-p8080:8080\-v/home/demo/config:/usr/local/tomcat/webapps/ROOT/WEB-INF/classes\--namedemo-tomcat-container\demo-tomcat:1.07.3 限制容器资源避免占用太多宿主机资源dockerrun-d-p8080:8080\--memory512m\--cpus1\--namedemo-tomcat-container\demo-tomcat:1.0--memory512m限制容器最多使用512MB内存--cpus1限制容器最多使用1个CPU核心7.4 健康检查自动重启不健康的容器首先在pom.xml里加spring-boot-starter-actuator依赖dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-actuator/artifactId/dependency然后在Dockerfile里加健康检查HEALTHCHECK --interval30s --timeout3s --start-period60s --retries3 \ CMD curl -f http://localhost:8080/actuator/health || exit 1运行容器时加--restartalways自动重启dockerrun-d-p8080:8080\--restartalways\--namedemo-tomcat-container\demo-tomcat:1.0八、总结部署流程回顾前置准备安装JDK、Maven、Docker项目改造修改pom.xml为war、排除内置Tomcat、启动类继承SpringBootServletInitializer编写Dockerfile选基础镜像、设时区、删默认webapps、复制WAR包、暴露端口、启动Tomcat构建运行mvn打包、docker build、docker run验证优化浏览器访问、查看日志、挂载目录、限制资源。