- Docker镜像分层
- SpringBoot 2.3.x 新增对分层的支持
- spring-boot-maven-plugin开启分层编译支持
- Dockerfile修改
- 分层后的Jar结构
- classpath.idx: 文件列出了依赖的 jar 包列表,到时候会按照这个顺序载入。
- layers.idx: 文件清单,记录了所有要被复制到 Dokcer 镜像中的文件信息。
- 列出可以从分层 Jar 中提取出的文件夹信息(spring-boot-jarmode-layertools)
java -Djarmode=layertools -jar isuwang-mobile-oss-1.0.jar list
dependencies -- 依赖项一般变化不大
spring-boot-loader -- spring-boot启动模块
snapshot-dependencies -- 快照依赖,为快照版本的依赖,更新迭代的会快一些
application -- 业务层,也就是我们最频繁变动的
- 构建速度的测试
普通构建 分层构建 全构建 3m41s 3m58s 修改代码后构建 2m24s 2m54s 修改api后构建 1m58s 3m31s
主要耗时步骤(154m -> 耗时 1m7s / 1m37s )
Step 4/16 : COPY demo-1.0.jar application.jar
(耗时 25s)
Step 5/16 : RUN java -Djarmode=layertools -jar application.jar extract
总结
- 镜像构建 : 在构建上,使用分层 Jar 构建镜像可能比普通方式构建镜像更繁琐(构建两次,还要解压),所以也更耗时,故而在构建上分层 Jar 构建镜像没有优势,甚至处于劣势
- 镜像推送 : 在推送上,如果每次构建镜像都只是修改构建镜像项目的源码,使用分层 Jar 构建镜像,可以大大加快镜像推送速度。如果是修改构建镜像项目中的依赖包,则和普通构建一样速度很慢(因为dependencies层是中间层镜像最大的一层)
- 镜像拉取 : 与推送一样
- 综上,在本地构建方面,普通构建有优势;在网络传输方面(docker pull/docker push),分层构建有优势
最后附上实验用的dockerfile
#FROM openjdk:8u212-jdk-alpine3.9
#MAINTAINER fa "fa@x.com.cn"
## 1.普通镜像构建脚本文件
## 系统编码
#ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
#RUN apk add --no-cache bash
## 设置时区为上海
#RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && apk del tzdata
#VOLUME /tmp
#ADD demo-1.0.jar app.jar
#EXPOSE 8099
#ENTRYPOINT exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
# 2. 分层镜像构建脚本文件
# 指定基础镜像,这是分阶段构建的前期阶段
FROM openjdk:8u212-jdk-alpine3.9 as builder
MAINTAINER fa "fa@x.com.cn"
# 执行工作目录
WORKDIR application
# 配置参数
#ARG JAR_FILE=target/*.jar
# 将编译构建得到的jar文件复制到镜像空间中(主要的耗时步骤)
COPY application.jar application.jar
# 通过工具spring-boot-jarmode-layertools从application.jar中提取拆分后的构建结果
RUN java -Djarmode=layertools -jar application.jar extract
# 正式构建镜像
FROM openjdk:8u212-jdk-alpine3.9
#系统编码
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8
RUN apk add --no-cache bash
# 设置时区为上海
RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && apk del tzdata
EXPOSE 8080
EXPOSE 9595
WORKDIR application
# 前一阶段从jar中提取除了多个文件,这里分别执行COPY命令复制到镜像空间中,每次COPY都是一个layer
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
#ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
ENTRYPOINT exec java ${JAVA_OPTS} org.springframework.boot.loader.JarLauncher