当前位置: 首页 > news >正文

Docker多阶段构建Maven项目

1、Dockerfile

# 第一阶段:构建阶段 (Builder stage)
FROM maven:3.6.3-jdk-11-slim AS builder # <-- 就是这行指令
WORKDIR /app
COPY pom.xml .
COPY src ./src
# 在“builder”容器中执行编译打包命令
RUN mvn clean package -DskipTests# 第二阶段:运行阶段 (Runtime stage)
FROM openjdk:11-jre-slim # <-- 一个更小的运行环境
WORKDIR /app
# 从上一阶段(builder)的容器中复制构建产物,而不是复制本地文件
COPY --from=builder /app/target/my-app.jar ./app.jar
# 暴露端口
EXPOSE 8080
# 启动命令
CMD ["java", "-jar", "app.jar"]

2、基础镜像

FROM maven:3.6.3-jdk-11-slim AS builder

FROM:Dockerfile指令,用于指定当前构建阶段基于的集成镜像

maven:3.6.3-jdk-11-slim:这是官方提供的Maven镜像的一个特定标签

maven:镜像名称

3.6.3:指定的Maven版本

jdk-11:表示这个镜像内部预装了jdk 11

slim:镜像的变种,一个瘦身版本,通常只包含运行指定工具(Maven和JDK)所必须的最小包,去除了文档,不必要的库

as builder:为这个构建阶段命名一个别名(builder)。这个别名将在后续的阶段中被引用,以便从该阶段复杂文件

3、执行过程

当Docker守护进程执行到这个指令时,它会进行以下操作

1、拉取镜像

Docker会检查本地是否存在maven:3.6.3-jdk-11-slim这个镜像,如果不存在,它会自动从Docker Hub(或其他配置的镜像仓库)拉取该镜像

拉取的镜像包含了一个预先配置好的Linux操作系统环境,其中主要安装了:

  • 一个最小化的Linux系统(通常Debian或Alpine精简版)
  • Java开发工具包(JDK11)完整的JDK不仅仅JRE,因为要编译代码需要javac等
  • Apache Maven 3.6.3:预配置好的Maven工具,其setting.xml可能包含基础配置,并且其本地仓库(/root/.m2/repository)可能时空的或只有基本依赖

2、创建并启动一个临时容器

Docker会以这个镜像为基础,创建一个新的、暂时的容器,这个容器被标记为名为builder的构建阶段,此时,这个容器提供了一个高度专门化的环境,这个环境唯一的目的就是用于编译和构建Java Maven项目

3、为后续指令提供上下文

这行指令本身并不执行构建命令,但它设置了舞台,后续的指令(如COPY、RUN、WORKDIR)将在由这个FROM这令创建的临时容器环境中执行

4、设置工作目录

WORKDIR /app

用户指令:设置工作目录为/app,如果目录不存在,则创建它

Docker内部操作:在由上一步FROM指令创建的临时容器中,执行 mkdir -p /app 命令创建目录

设置后续指令(COPY、RUN)的当前工作目录为/app,这意味着任何相对路径都将基于此目录

5、复制

COPY pom.xml .

用户指令:将构建上下文(通常是Dockerfile所在目录)中的pom.xml文件复制到容器当前工作目录(/app)

Docker内部操作:

1、检查缓存:这是构建过程中一个非常重要的优化点,Docker会计算pom.xml文件的校验和(checksum)

2、缓存命中:如果与此前某次构建的校验和完全一致,Docker会直接复用之前构建此步骤时创建的镜像层,跳过后续所有步骤,直接进入第二阶段,提高构建速度

3、缓存未命中:如果文件变化,Docker会继续执行

4、文件复制:将主机上的pom.xml文件复制到临时容器/app目录下,并创建一个新的镜像层来记录这个变化

COPY src ./src

用户指令:将本地src目录递归复制到容器的/app/src目录中

Docker内部操作:

1、类似于上一步,Docker会检查src目录中所有文件的检验和,单由于pom.xml通常先变化,而源代码后变化,所以上一步的缓存失效通常会导致这一步也必须执行

2、将主机上的src目录及全部内容复制到临时容器中,创建另一个新的镜像层

6、构建打包

RUN mvn clean package -DskipTests

用户指令:在容器内执行Maven命令,清理就构建,打包新应用(跳过测试)

Docker内部操作:

1、创建新容器层:RUN 指令总是在新的层上执行命令

2、启动子进程:Docker在当前的临时容器内启动一个shell进程(/bin/sh -c)来运行给定的命令

3、执行Maven

        Maven读取pom.xml文件

        从远程仓库下载所有的依赖(这些依赖会被下载到容器内的Maven本地仓库,通常位于/root/.m2/repository),这是构建过程中最耗时的步骤。

        编译src下的源代码

        运行所有编译阶段的生命周期(跳过test)

        将最终的制品 jar 打包到target 目录

4、提交结果:命令执行成功后,docker将命令执行结果(即包含了编译产物的容器状态)提交为一个新的、只读的镜像层,这个层包含了 target/test.jar

至此,第一个阶段临时容器使命完成,其最终状态是一个包含了源代码,依赖库和最终构建产物的镜像,这个镜像标记为builder

7、运行阶段

FROM openjdk:11-jre-slim

用户指令:开始一个全新的、独立的构建阶段,基于一个包含JRE的轻量级的镜像

Docker内部操作:

1、重置环境:Docker完全抛弃了第一阶段创建的所有临时状态和环境,它从一个全新的镜像开始,与第一阶段的JDK、Maven、源代码完全隔离

2、拉取镜像:同样,检查并拉取openjdk:11-jre-slim镜像,这个镜像比第一阶段的Maven镜像小的多

3、创建新的临时容器:基于这个新的基础镜像创建一个新的临时容器,用于构建最终的运行时镜像

8、设置工作目录

WORKDIR /app

用户指令和操作:与第一阶段相同,在新的临时容器中创建并设置工作目录/app

9、引用第一阶段

COPY --from=builder /app/target/my-app.jar ./app.jar

用户指令:从之前命名为builder的阶段中复制文件,而不是从主机复制

Docker内部操作:

定位源阶段:Docker根据--from=builder参数,定位到第一阶段最终生成的镜像

复制文件:从builder镜像的/app/target目录找到my-app.jar文件,并将其复制到当前第二阶段的临时容器的当前工作目录/app下,并重命名为app.jar

10、监听端口

EXPOSE 8080

用户指令:什么容器运行时监听的网络端口

Docker内部操作:

1、这只是一个元数据指令,它不会实际打开任何端口

2、Docker将此信息记录到镜像的元数据中,当然使用docker inspect 查看镜像时,可以看到这个信息

3、当基于此镜像运行容器时,使用 -p 8080:8080 参数会将主机8080端口映射到这个申明的容器端口

11、执行命令

CMD ["java", "-jar", "app.jar"]

用户指令:指定容器启动默认执行的命令

Docker内部操作:

1、这也是一个元数据指令,Docker将此JSON数据格式的命令记录到镜像的元数据中

2、当运行docker run <image-name>时,容器内的pid 1进程将是 java -jar app.jar

3、因为工作目录是/app,而app.jar就在该目录下,所以命令可以成功找到并执行


文章转载自:

http://Usppha0M.fjkkx.cn
http://mFt74dkv.fjkkx.cn
http://SscAci83.fjkkx.cn
http://HwtIWeU0.fjkkx.cn
http://FG0pBWiE.fjkkx.cn
http://Z4wqpoUx.fjkkx.cn
http://73IDZZxv.fjkkx.cn
http://SGmvKDGb.fjkkx.cn
http://nuQ5OhPA.fjkkx.cn
http://jIPqTa74.fjkkx.cn
http://Xz32zGfv.fjkkx.cn
http://2A0Vuk1M.fjkkx.cn
http://tNmx5Sbc.fjkkx.cn
http://2UdHg6ex.fjkkx.cn
http://t3aXdBCk.fjkkx.cn
http://Dbp4ZuNx.fjkkx.cn
http://7083Y4N1.fjkkx.cn
http://QHZgSmi8.fjkkx.cn
http://2DS4LgkI.fjkkx.cn
http://xA8Ei8WV.fjkkx.cn
http://e9QK6Gnt.fjkkx.cn
http://EJ0LyUB3.fjkkx.cn
http://JGCLxYir.fjkkx.cn
http://LnqHsdqK.fjkkx.cn
http://YoT39mwp.fjkkx.cn
http://lW9pIu5q.fjkkx.cn
http://yy3BjcRj.fjkkx.cn
http://JqXHcvjn.fjkkx.cn
http://43u9zMNJ.fjkkx.cn
http://f8RNLGcD.fjkkx.cn
http://www.dtcms.com/a/367411.html

相关文章:

  • 山姆·奥特曼 (Sam Altman) 分享提高工作效率的方法
  • 【赛题已出】2025高教社杯全国大学生数学建模竞赛ABCDE赛题已发布!
  • Git的强软硬回退(三)
  • 网络计算工具ipcalc详解
  • rabbitmq 入门知识点
  • C++ 中基类和派生类对象的赋值与转换
  • STM32F103_Bootloader程序开发15 - 从Keil到vscode + EIDE + GCC的迁移实践
  • 神马 M21 31T 矿机解析:性能、规格与市场应用
  • 解析 Quartz 报错:Table ‘test.QRTZ_LOCKS‘ doesn‘t exist 的解决方案
  • 【高等数学】第十一章 曲线积分与曲面积分——第二节 对坐标的曲线积分
  • 产品推荐|千眼狼宽光谱高速摄像机NEO系列
  • ECIES实现原理
  • Linux安装RTL8821CE无线网卡驱动
  • 下载及交叉编译libconfig
  • AutoLayout与Masonry:简化iOS布局
  • 《计算机网络安全》实验报告一 现代网络安全挑战 拒绝服务与分布式拒绝服务攻击的演变与防御策略(2)
  • upload-labs通关笔记-第17关文件上传关卡之二次渲染jpg格式
  • 人工智能机器学习——逻辑回归
  • Java Web 是技术与产业的 “交叉赋能点”
  • Linux笔记---UDP套接字实战:简易聊天室
  • 新增MCP工具管理,AI对话节点新增工具设置,支持对接企业微信机器人,MaxKB v2.1.0版本发布
  • 2025年数学建模国赛C题超详细解题思路
  • 【论文阅读】-《Besting the Black-Box: Barrier Zones for Adversarial Example Defense》
  • 小迪web自用笔记27
  • 不会战略、不会融资、不会搭团队?别叫自己 CTO
  • ⸢ 肆 ⸥ ⤳ 默认安全建设方案:b.安全资产建设
  • 【高分论文密码】大尺度空间模拟预测与数字制图
  • 机器翻译:腾讯混元团队开源的模型 Hunyuan-MT 详解
  • #数据结构----2.1线性表
  • IT需求提示未读信息查询:深度技术解析与性能优化指南【类似:钉钉已读 功能】