多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Spring Boot微服务容器化部署实战指南

Spring Boot微服务容器化部署实战指南 1. 从零开始构建Spring Boot微服务并容器化部署作为一名长期奋战在一线的Java开发者我亲历了微服务架构从概念到落地的全过程。今天要分享的是一个看似简单但极具代表性的实战案例将一个Spring Boot微服务打包成Docker镜像并运行。这个案例涵盖了从项目初始化到容器化部署的完整链路特别适合刚接触Docker的Java开发者作为入门实践。这个demo虽然简单但麻雀虽小五脏俱全。我们将使用Spring Boot 2.6.13构建一个RESTful服务通过Dockerfile定义Java 8运行环境最终实现服务在容器中的一键部署。过程中我会重点讲解几个关键决策点为什么选择这个Spring Boot版本Dockerfile中每个指令的实际作用是什么如何避免常见的打包陷阱2. 项目初始化与基础配置2.1 创建Maven模块在IDEA中新建一个名为docker_boot的Maven模块这是我们的微服务载体。选择Maven而非Gradle是因为在企业环境中Maven仍然是Java项目的主流构建工具兼容性更好。模块命名采用小写加下划线的风格这是Docker镜像命名的推荐做法可以避免后续的转换麻烦。经验之谈项目名称避免使用大写字母和特殊字符否则在后续Docker构建时可能需要进行额外处理。我曾见过因为项目名含空格导致构建失败的案例。2.2 POM文件配置解析POM文件是Maven项目的核心我们的配置有几个关键点值得注意properties java.version1.8/java.version spring-boot.version2.6.13/spring-boot.version /properties选择Java 8是因为目前仍有大量生产环境运行在JDK 8上兼容性最好。Spring Boot 2.6.13是一个长期支持(LTS)版本比最新的3.x系列对传统项目更友好。如果你的项目需要Jakarta EE 9支持可以考虑Spring Boot 3.xJDK 17的组合。依赖方面只引入了最基本的dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency这个starter包含了嵌入式Tomcat和Spring MVC足够我们的REST服务使用。值得注意的是build配置中的spring-boot-maven-pluginconfiguration mainClasscom.atguigu.docker.DockerBootApplication/mainClass skiptrue/skip /configuration这里的skiptrue需要特别注意它可能导致生成的jar包缺少主清单属性(no main manifest attribute)。这个配置通常用于跳过repackage阶段在聚合模块中使用。我们保留它是为了演示可能遇到的问题实际生产环境应该移除或设为false。2.3 最小化应用配置在application.yml中我们只配置了服务端口server.port: 6001选择6001端口是为了避免与常见服务端口冲突。实际项目中建议使用8000-9000范围内不太常用的端口号。如果使用随机端口可以配置为server.port: 0Spring Boot会自动分配可用端口这在容器编排环境中特别有用。3. 核心业务逻辑实现3.1 启动类设计启动类保持最简形式SpringBootApplication public class DockerBootApplication { public static void main(String[] args) { SpringApplication.run(DockerBootApplication.class, args); } }这个类应该放在根包下确保ComponentScan能扫描到所有组件。在实际项目中我习惯在这里添加一些初始化逻辑比如环境检查、 banner打印等。3.2 控制器开发OrderController展示了两个典型的REST端点RestController public class OrderController { Value(${server.port}) private String port; RequestMapping(/order/docker) public String helloDocker() { return hello docker \t port \t UUID.randomUUID().toString(); } }这个设计有几个特点使用Value注入端口号方便验证服务确实运行在配置的端口上返回信息中包含UUID每次请求都会不同方便测试负载均衡使用RequestMapping而非GetMapping保持兼容性在实际项目中建议为API添加版本前缀如/api/v1/order使用专门的DTO而非直接返回String添加Swagger等API文档支持4. Docker化部署全流程4.1 准备可执行JAR在IDEA中执行Maven打包命令mvn clean package成功后会生成target/docker_boot-0.0.1-SNAPSHOT.jar。如果遇到no main manifest attribute错误检查spring-boot-maven-plugin的skip配置或者直接运行mvn clean package spring-boot:repackage避坑指南建议在本地先运行java -jar测试生成的jar包能否正常启动再继续Docker化步骤。我遇到过因为依赖冲突导致容器内运行失败的情况。4.2 Dockerfile深度解析Dockerfile是容器化的核心我们的配置如下FROM java:8 MAINTAINER zzyy VOLUME /tmp ADD docker_boot-0.0.1-SNAPSHOT.jar zzyy_docker.jar RUN bash -c touch /zzyy_docker.jar ENTRYPOINT [java,-jar,/zzyy_docker.jar] EXPOSE 6001逐行解释FROM java:8- 基于官方Java 8镜像比openjdk镜像更小。如果需要更小的镜像可以考虑openjdk:8-jre-alpineVOLUME /tmp- 挂载临时目录Spring Boot默认使用/tmp作为工作目录ADD- 复制jar包并重命名使用简单名称便于后续操作RUN touch- 确保jar包存在并更新timestampENTRYPOINT- 使用exec形式启动应用确保能接收SIGTERM信号EXPOSE- 声明端口实际映射需要在run时指定优化建议添加时区配置-Duser.timezoneGMT08限制内存使用-Xmx512m -Xms256m添加健康检查指令HEALTHCHECK4.3 构建与运行实战将jar包和Dockerfile放在同一目录下如/mydocker执行构建docker build -t zzyy_docker:1.6 .这里有几个最佳实践使用明确的版本标签而非latest构建前清理旧的构建缓存docker system prune -f国内用户可以使用--pull选项确保基础镜像最新运行容器docker run -d -p 6001:6001 --name myboot zzyy_docker:1.6关键参数-d后台运行-p端口映射主机端口:容器端口--name指定容器名称便于管理5. 测试与问题排查5.1 服务验证方法使用curl测试curl http://localhost:6001/order/docker或者浏览器访问http://localhost:6001/order/index预期看到类似输出hello docker 6001 c9e5b0a3-2e4a-4f3d-bdc1-7a9b3a1d4f7e5.2 常见问题解决方案端口冲突如果6001已被占用可以改为其他端口如-p 6002:6001容器立即退出检查日志docker logs myboot常见原因JAR包未正确打包端口绑定失败启动参数错误性能调优在Docker run时添加JVM参数-e JAVA_OPTS-Xmx512m -Xms256m -XX:UseG1GC时区问题在Dockerfile中添加ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone构建缓存问题如果修改了代码但构建时未生效可以禁用缓存docker build --no-cache -t zzyy_docker:1.7 .6. 进阶优化方向6.1 多阶段构建使用多阶段构建可以显著减小镜像大小FROM maven:3.8.6-jdk-8 AS builder WORKDIR /app COPY . . RUN mvn clean package FROM openjdk:8-jre-alpine COPY --frombuilder /app/target/docker_boot-0.0.1-SNAPSHOT.jar /app.jar ENTRYPOINT [java,-jar,/app.jar]这种构建方式第一阶段使用完整JDK编译代码第二阶段只包含运行时环境最终镜像大小可减少50%以上6.2 使用Jib插件Google的Jib插件可以直接构建Docker镜像无需Dockerfileplugin groupIdcom.google.cloud.tools/groupId artifactIdjib-maven-plugin/artifactId version3.3.1/version configuration to imagemy-docker-image/image /to /configuration /plugin执行mvn compile jib:build优点不需要本地Docker环境构建速度更快可重复性更好6.3 集成到CI/CD流程典型的Jenkins pipeline配置示例pipeline { agent any stages { stage(Build) { steps { sh mvn clean package } } stage(Docker Build) { steps { script { docker.build(zzyy_docker:${env.BUILD_ID}) } } } stage(Deploy) { steps { sh docker-compose up -d } } } }关键点使用构建ID作为镜像标签结合Docker Compose管理多容器添加自动化测试阶段7. 生产环境注意事项日志管理配置日志卷持久化-v /path/on/host:/logs资源限制设置内存和CPU限制--memory1g --cpus2健康检查添加健康检查端点GetMapping(/actuator/health) public Health health() { return Health.up().build(); }监控集成暴露Prometheus指标dependency groupIdio.micrometer/groupId artifactIdmicrometer-registry-prometheus/artifactId /dependency安全加固使用非root用户运行容器定期更新基础镜像扫描镜像中的漏洞经过这个完整流程你应该已经掌握了一个Spring Boot应用从开发到容器化部署的核心技能。在实际项目中可能还需要考虑服务发现、配置中心、熔断限流等微服务配套组件但容器化始终是最基础也是最重要的一环
返回列表