SpringBoot-2-3-x分层构建Docker镜像实践

本文分析了Docker镜像构建中缓存机制的应用,展示了SpringBoot2.3.x引入的分层支持如何提高构建效率。通过实例比较了普通镜像与分层镜像在构建速度、推送速度上的差异,突出了分层在资源管理和复用方面的优势。
摘要由CSDN通过智能技术生成

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

$ docker build -t java-test2:latest .

Step 1/6 : FROM openjdk:8u275
—> 82f24ce79de6
Step 2/6 : VOLUME /tmp
—> Using cache
—> a43948bf1b98
Step 3/6 : ADD target/*.jar app.jar
—> Using cache
—> 18f4bc60818f
Step 4/6 : ENV TZ=“Asia/Macao”
—> Running in fd98b90a5485
Removing intermediate container fd98b90a5485
—> afab3fcdab07
Step 5/6 : ENV JVM_OPTS=“-Xmx512m -Xss256k”
—> Running in 19a99576fba9
Removing intermediate container 19a99576fba9
—> 4eeab7d7c720
Step 6/6 : ENTRYPOINT [“sh”,“-c”,“java  J V M O P T S   JVM_OPTS  JVMOPTS JAVA_OPTS -jar /app.jar” ]
—> Running in 2dba72e1eef4
Removing intermediate container 2dba72e1eef4
—> 7c706ecf7698

可以观察到执行过程中,从一开始执行的构建步骤中显示,并没有生成新的中间层镜像,而是直接使用了已经存在的缓存镜像。直至 4⁄6 这部中,由于新的 Dockerfile 与原来 Dockerfile 发生变动,所以这部中间层镜像直接是新创建的,并没有使用缓存中间层镜像。

然后往下观察,发现之后的全部构建都是新创建的中间层镜像,即是脚本最后的一行和原来相同,也没有使用缓存中间层镜像。

上面现象说明,Docker 镜像在构建过程中按照 Dockerfile 自上往下的执行顺序中,如果从最上层开始,其脚本内容和已有的缓存中间层镜像内容一致,就会引入缓存中的中间层镜像(并不是直接复制缓存镜像,而是引入镜像文件地址,多个镜像共享这些中间层镜像)。

但是,如果执行过程中中间任意一行镜像构建的内容发生变化,那么当前行和之后的全部行在执行时就不会使用缓存中的中间层镜像,而是全部创建新的镜像。

SpringBoot 2.3.x分层构建Docker镜像实践

这就是 Docker 镜像中缓存中间层镜像的复用,学会使用缓存构建镜像将大大减少存储空间的占用以及镜像的构建的构建速度,镜像的缓存不仅仅体现在镜像的构建上,在执行”镜像推送”、”镜像拉取”操作时都能观察到其的好处。

  • 镜像缓在镜像推送的体现: 如镜像推送时候,也是将镜像整体构成的中间层镜像并行推送到镜像仓库,如果镜像仓库中已经存某个中间层镜像,那么推送过程就不会再次将该层镜像推送到镜像仓库,而是将仓库中并不存在中间层镜像推送到其中。
  • 镜像缓存在镜像拉取的体现: 在拉取镜像时候,如果本地某个大镜像的中间层镜像的组成中,已经包含新拉取镜像的中间层部分镜像,那么将直接复用本地已经镜像的中间层镜像,不必再将其进行拉取,而本地不存在的中间层镜像将会被继续拉取。

说了这么多,相信大家已经对镜像缓存的使用有了初步了解,那么再谈及为什么需要镜像分层就很好解释,其原因就是 Docker 想提高资源的复用率,将一个大镜像拆分成很多层小镜像组成,以达到镜像中间层的复用的目的。

二、SpringBoot 2.3.x 新增对分层的支持

SpringBoot 2.3.x 以后支持分层打包应用,需要 Pom.xml 中引入 SpringBoot 2.3.x 后的父依赖和使用 SpringBoot 打包插件 spring-boot-maven-plugin,并且开启 layers 功能,然后执行 Maven 编译源码构建 Jar 包,使用该 Jar 包就可以构建基于分层模式的 Docker 镜像:

项目 pom.xml 中引入 SpringBoot 2.3.x 依赖:

org.springframework.boot spring-boot-starter-parent 2.3.6.RELEASE

项目 pom.xml 中引入 spring-boot-maven-plugin 打包插件,并且开启分层功能:

org.springframework.boot spring-boot-maven-plugin true

执行 Maven 命令,构建分层的 JAR 包,命令和平时的 Maven 构建命令相同:

$ mvn install

观察 Jar 结构,可以看到里面多了 classpath.idx 与 layers.idx 两个文件:

  • classpath.idx: 文件列出了依赖的 jar 包列表,到时候会按照这个顺序载入。
  • layers.idx: 文件清单,记录了所有要被复制到 Dokcer 镜像中的文件信息。

根据官方介绍,在构建 Docker 镜像前需要从 Jar 中提起出对应的分层文件到 Jar 外面,可用使用下面命令列出可以从分层 Jar 中提取出的文件夹信息:

$ java -Djarmode=layertools -jar target/springboot-layer-0.0.1.jar list

可用该看到以下输出,下面的内容就是接下来使用分层构建后,生成的 Jar 提取出对应资源后的结构:

dependencies
spring-boot-loader
snapshot-dependencies
application

上面即是使用分层工具提取 Jar 的内容后生成的文件夹,其中各个文件夹作用是:

  • dependencies: 存储项目正常依赖 Jar 的文件夹。
  • snapshot-dependencies: 存储项目快照依赖 Jar 的文件夹。
  • resources: 用于存储静态资源的文件夹。
  • application: 用于存储应用程序类相关文件的文件夹。

三、创建测试的 SpringBoot 应用

创建测试的 SpringBoot 项目,并且在 pom.xml 中开启镜像分层。

1、Maven 中引入相关依赖和插件

<?xml version="1.0" encoding="UTF-8"?>


4.0.0

org.springframework.boot spring-boot-starter-parent 2.3.6.RELEASE

springboot-dockerfile-layer
jar
springboot-dockerfile-layer
springboot build layer example

org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-maven-plugin true

2、创建测试的 Controller 类

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

@GetMapping(“/hello”)
public String hello() {
return “hello world!”;
}

}

3、创建 SpringBoot 启动类

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

四、创建两种构建镜像的 Dockerfile 脚本

为了方便体现出 SpringBoot 2.3.x 支持的分层构建 Dockerfile 的优点,这里在 Java 源码文件夹下,创建普通与分层两种构建镜像的 Dockerfile 脚本,后续会使用这两种脚本构建 Docker 镜像进行构建速度、推送速度、拉取速度的对比。

1、普通镜像构建脚本文件 dockerfile-number

FROM openjdk:8u275
VOLUME /tmp
ADD target/*.jar app.jar
RUN sh -c ‘touch /app.jar’
ENV TZ=“Asia/Shanghai”
RUN ln -snf /usr/share/zoneinfo/KaTeX parse error: Expected 'EOF', got '&' at position 19: …/etc/localtime &̲& echo TZ > /etc/timezone
ENV JVM_OPTS=“-XX:MaxRAMPercentage=80.0”
ENV JAVA_OPTS=“”
ENTRYPOINT [ “sh”, “-c”, “java  J A V A O P T S   − D j a v a . s e c u r i t y . e g d = f i l e : / d e v / . / u r a n d o m   − j a r   / a p p . j a r   JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar  JAVAOPTS Djava.security.egd=file:/dev/./urandom jar /app.jar APP_OPTS” ]

说明:

  • TZ: 时区设置,而 Asia/Shanghai 表示使用中国上海时区。
  • JVM_OPTS: 指定 JVM 启动时候的参数,-XX:MaxRAMPercentage 参数和 -Xmx 类似,都是限制堆内存大小,只不过 -Xmx 需要手动指定限制大小,而 -XX:MaxRAMPercentage 则是根据虚拟机可用内存百分比限制。
  • JAVA_OPTS: 在镜像启动时指定的自定义 Java 参数,例如 -Dspring.application.name=xxx。

2、分层镜像构建脚本文件 dockerfile-layer

FROM openjdk:8u275 as builder
WORKDIR application
COPY target/*.jar application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM openjdk:8u275
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/application/ ./
ENV TZ=“Asia/Shanghai”
ENV JVM_OPTS=“-XX:MaxRAMPercentage=80.0”
ENV JAVA_OPTS=“”
ENTRYPOINT [“sh”,“-c”,“java  J V M O P T S   JVM_OPTS  JVMOPTS JAVA_OPTS org.springframework.boot.loader.JarLauncher”]

说明:

  • TZ: 时区设置,而 Asia/Shanghai 表示使用中国上海时区。
  • -Djarmode=layertools: 指定构建 Jar 的模式。
  • extract: 从 Jar 包中提取构建镜像所需的内容。
  • -from=builder 多级镜像构建中,从上一级镜像复制文件到当前镜像中。

五、使用两种 Dockerfile 构建项目镜像

1、在服务器一构建普通 Docker 镜像

(1)、第一次构建

## 执行 Maven 命令,将源代码构建 Jar 包
$ mvn clean install

## 构建 SpringBoot 应用的 Docker 镜像
$ time docker build -t hub.mydlq.club/library/springboot-normal:0.0.1 .

Docker 镜像构建总共花费 24.98s 时间。

(2)、第二次构建(修改依赖 pom.xml 文件)

## 修改 pom.xml 里面的依赖,随意添加一个新的依赖包,然后再次将源代码构建 Jar 包
$ mvn clean install

## 构建 SpringBoot 应用的 Docker 镜像
$ time docker build -t hub.mydlq.club/library/springboot-normal:0.0.2 .

Docker 镜像构建总共花费 1.27s 时间。

(3)、第三次构建(修改代码内容)

## 修改源代码任意内容后,然后再次将源代码构建 Jar 包
$ mvn clean install

## 构建 SpringBoot 应用的 Docker 镜像
$ time docker build -t hub.mydlq.club/library/springboot-normal:0.0.3 .

Docker 镜像构建总共花费 1.32s 时间。

2、在服务器二构建分层 Docker 镜像

(1)、第一次构建

## 执行 Maven 命令,将源代码构建 Jar 包
$ mvn clean install

## 构建 SpringBoot 应用的 Docker 镜像
$ time docker build -t hub.mydlq.club/library/springboot-layer:0.0.1 .

Docker 镜像构建总共花费 26.12s 时间。

(2)、第二次构建(修改依赖 pom.xml 文件)

## 修改 pom.xml 里面的依赖,随意添加一个新的依赖包,然后再次将源代码构建 Jar 包
$ mvn clean install

## 构建 SpringBoot 应用的 Docker 镜像
$ time docker build -t hub.mydlq.club/library/springboot-layer:0.0.2 .

Docker 镜像构建总共花费 3.44s 时间。

(3)、第三次构建(修改代码内容)

## 修改源代码任意内容后,然后再次将源代码构建 Jar 包
$ mvn clean install

## 构建 SpringBoot 应用的 Docker 镜像
$ time docker build -t hub.mydlq.club/library/springboot-layer:0.0.3 .

Docker 镜像构建总共花费 2.82s 时间。

六、镜像推送到镜像仓库测试

1、推送镜像到镜像仓库测试

服务器一推送普通镜像到镜像仓库1:

## 第一次推送镜像
$ time docker push hub.mydlq.club/library/springboot-normal:0.0.1

real    0m35.215s

## 第二次推送镜像
$ time docker push hub.mydlq.club/library/springboot-normal:0.0.2

real    0m14.051s

## 第三次推送镜像
$ time docker push hub.mydlq.club/library/springboot-normal:0.0.3

real    0m14.183s

服务器二推送分层镜像到镜像仓库2:

## 第一次推送镜像
$ time docker push hub.mydlq.club/library/springboot-layer:0.0.1

real    0m34.121s

## 第二次推送镜像
$ time docker push hub.mydlq.club/library/springboot-layer:0.0.2

real    0m13.605s

## 第三次推送镜像

最后

给大家送一个小福利

附高清脑图,高清知识点讲解教程,以及一些面试真题及答案解析。送给需要的提升技术、准备面试跳槽、自身职业规划迷茫的朋友们。

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!
次推送镜像
$ time docker push hub.mydlq.club/library/springboot-layer:0.0.2

real    0m13.605s

## 第三次推送镜像

最后

给大家送一个小福利

[外链图片转存中…(img-6ztBOLcH-1714755211535)]

附高清脑图,高清知识点讲解教程,以及一些面试真题及答案解析。送给需要的提升技术、准备面试跳槽、自身职业规划迷茫的朋友们。

[外链图片转存中…(img-z4Ydy461-1714755211535)]

《一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码》点击传送门,即可获取!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值