⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7268183236739383337 「云笈」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

导读

在容器化实践中部署spring boot应用普遍采用基础java镜像再添加jar包层来构建应用镜像制品。随着公司业务大量上云,每个变更日上传到云上镜像日渐增多,导致本地机房到云上带宽压力倍增。为解决镜像上传问题,调研了相关技术栈决定采用spring boot 2.3新增的镜像分层构建功能。

基础环境

  • spring boot version >= 2.3
  • java oracle jdk 8u201
  • docker version 20.10.13

基于传统单个jar包构建模式

基础Dockerfile

以下是我们基于基础镜像构建spring boot镜像制品的Dockerfile,采用了比较传统的COPY jar包。相信这也是大家普遍采用的模式。Dockefile如下,该Dockerfile存在一个坑,会在下边阐述。

FROM registry.xxx.com/base/oracle-jdk:8u201
ENV TZ=Asia/Shanghai
ENV LC_ALL en_US.utf8
WORKDIR /app
ADD ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
ADD ./entrypoint.sh /app/bin/entrypoint.sh
ENTRYPOINT exec bash /app/bin/entrypoint.sh
RUN ln -s /app/logs /app/log && chown 1001.1001 -R /app

Base镜像信息

我们base镜像主要分三层添加了相关常用的工具如telnet netstat等以及安全修复

docker image inspect registry.xxx.com/base/oracle-jdk:8u201

分层信息:

"RootFS": {
"Type": "layers",
"Layers": [
"sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02",
"sha256:2105884a1756425b2188084cc1738d6a6b13293773af56f6727af1be979858ed",
"sha256:c33745b350978d855171c996779055195b09e227844b7a03a1d795aee803dbb9"
]
}

Base镜像大小 622MB

镜像大小 622MB 不算太小,对比友商有些基础镜像竟然1-2G😂 简直有点离谱。

registry.xxx.com/base/oracle-jdk  8u201 1869b73a8999  2 years ago  622MB

Base镜像history信息

从构建历史可以看出占用空间主要分为三层分别是

  • centos 7 基础镜像层
  • yum install 层
  • jdk 层
docker image  history registry.xxx.com/base/oracle-jdk:8u201
IMAGE CREATED CREATED BY SIZE COMMENT
1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
<missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
<missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
<missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

传统构建方式

docker build -t registry.xxx.com/layer/build:old .
Sending build context to Docker daemon 67.45MB
Step 1/8 : FROM registry.xxx.com/base/oracle-jdk:8u201
---> 1869b73a8999
Step 2/8 : ENV TZ=Asia/Shanghai
---> Running in a67423d7246b
Removing intermediate container a67423d7246b
---> 9304102c278e
Step 3/8 : ENV LC_ALL en_US.utf8
---> Running in 05bf14c10efd
Removing intermediate container 05bf14c10efd
---> 63fb6c823893
Step 4/8 : WORKDIR /app
---> Running in 095764328d18
Removing intermediate container 095764328d18
---> c057ab4a7d18
Step 5/8 : ADD ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
---> 08928447fafa
Step 6/8 : ADD ./entrypoint.sh /app/bin/entrypoint.sh
---> 0902efa62157
Step 7/8 : ENTRYPOINT exec bash /app/bin/entrypoint.sh
---> Running in dc0eb814cfff
Removing intermediate container dc0eb814cfff
---> 20679a170252
Step 8/8 : RUN ln -s /app/logs /app/log && chown 1001.1001 -R /app
---> Running in 34159dca7464
Removing intermediate container 34159dca7464
---> b6043465c072
Successfully built b6043465c072
Successfully tagged registry.xxx.com/layer/build:old

构建后镜像大小 为基础镜像大小 622MB + 2*65M <= 757MB

构建后比我们预期的 jar包加基础镜像所占用的空间大😢 why?

#jar包大小
ls -lh xxx-1.0.0.jar
-rw------- 1 root root 65M Aug 16 10:33 xxx-1.0.0.jar

#镜像大小
docker image ls |grep registry.xxx.com/layer/build
registry.xxx.com/layer/build old b6043465c072 59 seconds ago 757MB

成品构建history信息

查看构建成品的镜像层发现竟然有两层一样大小,也会被推送了两遍。🥲离大谱。通过分析Dockerfile是因为RUN ln -s /app/logs /app/log && chown 1001.1001 -R /app 导致的。为保证镜像安全,生产环境运行统一采用了1001账号运行。为了保证1001对workdir有绝对的读写权限。对目录递归授权导致文件属性发生改变。

在构建时认为文件发生变化产生一样大小的两层导致的。(这还是我自己当时优化引入的屎山😊)具体原因我也不太清楚docker构建时如何判定文件发生变化,我原本以为是基于MD5码。实际上在对文件属主属组改变时MD5码是不对变的。有知道的大神可以在评论区留言交流。

docker image  history  registry.xxx.com/layer/build:old
IMAGE CREATED CREATED BY SIZE COMMENT
b6043465c072 6 minutes ago /bin/sh -c ln -s /app/logs /app/log && chown… 67.4MB
20679a170252 6 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
0902efa62157 6 minutes ago /bin/sh -c #(nop) ADD file:9ac19caf793524884… 128B
08928447fafa 6 minutes ago /bin/sh -c #(nop) ADD file:c7624c195e7c047ee… 67.4MB
c057ab4a7d18 6 minutes ago /bin/sh -c #(nop) WORKDIR /app 0B
63fb6c823893 6 minutes ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
9304102c278e 6 minutes ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
<missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
<missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
<missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

#镜像也推送了两层一样大小
[root@localhost old-nochown]# docker push registry.xxx.com/layer/build:old
The push refers to repository [registry.xxx.com/layer/build]
bb35157fcb0b: Pushing [=============> ] 18.35MB/67.45MB
3c0641004863: Pushed
6ed0abaff975: Pushing [=====================> ] 28.38MB/67.45MB
aa0794231b2c: Pushed
c33745b35097: Layer already exists
2105884a1756: Layer already exists
174f56854903: Layer already exists

优化Dockerfile

原因知道了。优化思路是先创建目录并递归授权。同时构建出来的jar的权限可以通过COPY 指定1001属主属组。

FROM registry.xxx.com/base/oracle-jdk:8u201
ENV TZ=Asia/Shanghai
ENV LC_ALL en_US.utf8
RUN mkdir -pv /app/{bin,lib,logs} && ln -s /app/logs /app/log && chown 1001:1001 -R /app
WORKDIR /app
COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
COPY --chown=1001:1001 ./entrypoint.sh /app/bin/entrypoint.sh
ENTRYPOINT exec bash /app/bin/entrypoint.sh

优化后的镜像只有COPY这一层的jar包了。

docker image history registry.xxx.com/layer/build:old-mkdir
IMAGE CREATED CREATED BY SIZE COMMENT
b9fc3a8a97f2 29 hours ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
c823448f9582 29 hours ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 128B
9a997f3962bf 29 hours ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 67.4MB
f272c4e64f87 29 hours ago /bin/sh -c #(nop) WORKDIR /app 0B
1a526d3df7c2 29 hours ago /bin/sh -c mkdir -pv /app/{bin,lib,logs} && … 9B
63fb6c823893 30 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
9304102c278e 30 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
<missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
<missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
<missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

基于spring boot 分层构建方式

探索基于分层构建原理

直接上手官方文档的demo 把官方文档demo的多阶段构建拆分一下。

cat Dockerfile
FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
WORKDIR /app
COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.0.jar extract

一阶段实际就是将jar解压按照spring boot layers.idx文件中的分层方式将依赖和业务代码分层。

- "dependencies":
- BOOT-INF/lib/library1.jar
- BOOT-INF/lib/library2.jar
- "spring-boot-loader":
- org/springframework/boot/loader/JarLauncher.class
- org/springframework/boot/loader/jar/JarEntry.class
- "snapshot-dependencies":
- BOOT-INF/lib/library3-SNAPSHOT.jar
- "application":
- META-INF/MANIFEST.MF
- BOOT-INF/classes/a/b/C.class

进入到容器中可以看到被解压为4个目录:

[root@b762a63589c1 app]# ls
application dependencies lib logs snapshot-dependencies spring-boot-loader

存储占用如下:其中不出意外dependencies也就是依赖库占用是最大的 业务代码只有可怜的304K🤔。

[root@29d87aaf64b9 app]# du -lh  --max-depth=1
304K ./application
65M ./dependencies
0 ./logs
20K ./snapshot-dependencies
420K ./spring-boot-loader
65M ./lib
130M .

基于分层构建构建制品镜像

在官方的demo上修改得到完整的Dockerfile。其中优化了entrypoint脚本,采用分层构建后启动应用不能采用传统的java $JAVA_OPTS -jar xxx.jar这方式启动应用。要使用java org.springframework.boot.loader.JarLauncher启动应用因此jvm参数需要通过脚本接受容器的环境变量来传入。

FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
WORKDIR /app
COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.0.jar extract

FROM registry.xxx.com/base/oracle-jdk:8u201
ENV TZ=Asia/Shanghai
ENV LC_ALL en_US.utf8
RUN mkdir -pv /app/logs && ln -s /app/logs /app/log && chown 1001:1001 -R /app
WORKDIR /app
COPY --chown=1001:1001 --from=builder /app/dependencies/ ./
COPY --chown=1001:1001 --from=builder /app/spring-boot-loader/ ./
COPY --chown=1001:1001 --from=builder /app/snapshot-dependencies/ ./
COPY --chown=1001:1001 --from=builder /app/application/ ./
CMD ["exec"]
ENTRYPOINT ["bash","/app/entrypoint.sh"]

entrypoint.sh脚本使用exec将java作为容器1号进程,避免无法接受linux 信号导致java进程无法正常退出。

#!/bin/bash
if [ -f /opt/cm/before.sh ]; then
source /opt/cm/before.sh;
fi
exec java $JAVA_OPTS org.springframework.boot.loader.JarLauncher

构建镜像

[root@localhost new]# docker build -t registry.xxx.com/layer/build:new .
Sending build context to Docker daemon 67.45MB
Step 1/14 : FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
---> 1869b73a8999
Step 2/14 : WORKDIR /app
---> Using cache
---> 6973e49f31fa
Step 3/14 : COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
---> Using cache
---> c5a17d5969ea
Step 4/14 : RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.0.jar extract
---> Using cache
---> 911074c3ef21
Step 5/14 : FROM registry.xxx.com/base/oracle-jdk:8u201
---> 1869b73a8999
Step 6/14 : ENV TZ=Asia/Shanghai
---> Using cache
---> 9304102c278e
Step 7/14 : ENV LC_ALL en_US.utf8
---> Using cache
---> 63fb6c823893
Step 8/14 : RUN mkdir -pv /app/logs && ln -s /app/logs /app/log && chown 1001:1001 -R /app
---> Running in 9cac9cb86507
mkdir: created directory ‘/app’
mkdir: created directory ‘/app/logs’
Removing intermediate container 9cac9cb86507
---> 858e77315e6b
Step 9/14 : WORKDIR /app
---> Running in 81c7173692fc
Removing intermediate container 81c7173692fc
---> 5c19ddda3114
Step 10/14 : COPY --chown=1001:1001 --from=builder /app/dependencies/ ./
---> 078e3f4a199c
Step 11/14 : COPY --chown=1001:1001 --from=builder /app/spring-boot-loader/ ./
---> 1542209ccc8b
Step 12/14 : COPY --chown=1001:1001 --from=builder /app/snapshot-dependencies/ ./
---> 75a9584e0952
Step 13/14 : COPY --chown=1001:1001 --from=builder /app/application/ ./
---> 555270edceea
Step 14/14 : ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
---> Running in fe99278683a2
Removing intermediate container fe99278683a2
---> 2cce0deab7e2
Successfully built 2cce0deab7e2
Successfully tagged registry.xxx.com/layer/build:new

查看分层详情,可以看到jar被拆分成4层分别由copy指令创建。

[root@localhost ~]# docker image history registry.xxx.com/layer/build:new
IMAGE CREATED CREATED BY SIZE COMMENT
2cce0deab7e2 28 hours ago /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B
555270edceea 28 hours ago /bin/sh -c #(nop) COPY dir:2f5975d11563ae449… 248kB
75a9584e0952 28 hours ago /bin/sh -c #(nop) COPY dir:a3bb0870001a0ef25… 18.5kB
1542209ccc8b 28 hours ago /bin/sh -c #(nop) COPY dir:16d00ea1f180914e2… 252kB
078e3f4a199c 28 hours ago /bin/sh -c #(nop) COPY dir:1d3190ed598b634a5… 67.1MB
5c19ddda3114 28 hours ago /bin/sh -c #(nop) WORKDIR /app 0B
858e77315e6b 28 hours ago /bin/sh -c mkdir -pv /app/logs && ln -s /app… 9B
63fb6c823893 30 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
9304102c278e 30 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
<missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
<missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
<missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

对比发现jar包被拆分了。

[root@localhost new]# diff old.info  new.info
1,16c1,18
< IMAGE CREATED CREATED BY SIZE COMMENT
< b9fc3a8a97f2 About an hour ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
< c823448f9582 About an hour ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 128B
< 9a997f3962bf About an hour ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 67.4MB
< f272c4e64f87 About an hour ago /bin/sh -c #(nop) WORKDIR /app 0B
< 1a526d3df7c2 About an hour ago /bin/sh -c mkdir -pv /app/{bin,lib,logs} && … 9B
< 63fb6c823893 2 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
< 9304102c278e 2 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
< 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
< <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
< <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
< <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
< <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
< <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
< <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
< <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
---
> IMAGE CREATED CREATED BY SIZE COMMENT
> 2cce0deab7e2 8 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B
> 555270edceea 8 minutes ago /bin/sh -c #(nop) COPY dir:2f5975d11563ae449… 248kB
> 75a9584e0952 8 minutes ago /bin/sh -c #(nop) COPY dir:a3bb0870001a0ef25… 18.5kB
> 1542209ccc8b 8 minutes ago /bin/sh -c #(nop) COPY dir:16d00ea1f180914e2… 252kB
> 078e3f4a199c 8 minutes ago /bin/sh -c #(nop) COPY dir:1d3190ed598b634a5… 67.1MB
> 5c19ddda3114 8 minutes ago /bin/sh -c #(nop) WORKDIR /app 0B
> 858e77315e6b 8 minutes ago /bin/sh -c mkdir -pv /app/logs && ln -s /app… 9B
> 63fb6c823893 2 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
> 9304102c278e 2 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
> 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
> <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
> <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
> <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
> <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
> <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
> <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
> <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

推送到仓库

[root@localhost new]# docker push registry.xxx.com/layer/build:new
The push refers to repository [registry.xxx.com/layer/build]
e5409ea62302: Pushed
7167dfa406ea: Pushed
cf7e94a2dc11: Pushed
8e261e1bae2c: Pushed
770c31a84800: Pushed
c33745b35097: Layer already exists
2105884a1756: Layer already exists
174f56854903: Layer already exists
new: digest: sha256:faef10681394c01d1c2973ed10c7c33e7289eec25f22c90d085f6eef96ce3bff size: 2001

验证模拟开发推送代码更新镜像

开发摸了一天🐟终于开发出新版本

[root@localhost new]# md5sum  bc-1.0.1.jar  bc-1.0.0.jar
3792d3178a4e07708052b7effa9b12f8 xxx-1.0.1.jar
8ee570b94977668631355cb49c5d7cf1 xxx-1.0.0.jar

构建新版本,构建过程阶段二中使用了cache 仅更新了 application层

[root@localhost new]# docker image build -t  registry.xxx.com/layer/build:new-1.0.1 .
Sending build context to Docker daemon 134.9MB
Step 1/16 : FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
---> 1869b73a8999
Step 2/16 : WORKDIR /app
---> Using cache
---> 6973e49f31fa
Step 3/16 : COPY --chown=1001:1001 ./xxx-1.0.1.jar /app/lib/xxx-1.0.1.jar
---> b219210fd8ab
Step 4/16 : RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.1.jar extract
---> Running in d099c10b653c
Removing intermediate container d099c10b653c
---> 66a8593b0291
Step 5/16 : FROM registry.xxx.com/base/oracle-jdk:8u201
---> 1869b73a8999
Step 6/16 : ENV TZ=Asia/Shanghai
---> Using cache
---> 9304102c278e
Step 7/16 : ENV LC_ALL en_US.utf8
---> Using cache
---> 63fb6c823893
Step 8/16 : RUN mkdir -pv /app/logs && ln -s /app/logs /app/log && chown 1001:1001 -R /app
---> Using cache
---> 858e77315e6b
Step 9/16 : WORKDIR /app
---> Using cache
---> 5c19ddda3114
Step 10/16 : COPY --chown=1001:1001 ./entrypoint.sh /app/entrypoint.sh
---> Using cache
---> c47b74bb8cf9
Step 11/16 : COPY --chown=1001:1001 --from=builder /app/dependencies/ ./
---> Using cache
---> 078e3f4a199c
Step 12/16 : COPY --chown=1001:1001 --from=builder /app/spring-boot-loader/ ./
---> Using cache
---> 1542209ccc8b
Step 13/16 : COPY --chown=1001:1001 --from=builder /app/snapshot-dependencies/ ./
---> Using cache
---> 75a9584e0952
Step 14/16 : COPY --chown=1001:1001 --from=builder /app/application/ ./
---> 0f138b106caf
Step 15/16 : CMD ["exec"]
---> Using cache
---> a1170ae7a20e
Step 16/16 : ENTRYPOINT ["bash","/app/entrypoint.sh"]
---> Using cache
---> 5a6bb7613fc8
Successfully built 5a6bb7613fc8
Successfully tagged registry.xxx.com/layer/build:new-1.0.1

推送到仓库可以看到仅推送了application层 只有300K

docker push registry.xxx.com/layer/build:new-1.0.1
The push refers to repository [registry.xxx.com/layer/build]
c33a5c6456bd: Pushed
7167dfa406ea: Layer already exists
cf7e94a2dc11: Layer already exists
8e261e1bae2c: Layer already exists
770c31a84800: Layer already exists
c33745b35097: Layer already exists
2105884a1756: Layer already exists
174f56854903: Layer already exists
new-1.0.1: digest: sha256:53647bb45f0f0bb5bb8d56f14cd40deb22f0d5e4fce1200fed1c225a516dddb5 size: 2001

验证镜像

[root@localhost new]# docker run -it --rm -u 1001:1001  -e JAVA_OPTS="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintCommandLineFlags"  registry.xxx.com/layer/build:new-1.0.1

可以看到打印出了堆栈信息(容器默认是不开启的)应用成功启动😋

[root@localhost ~]# docker run -it --rm -u 1001:1001  -e JAVA_OPTS="-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCApplicationConcurrentTime -XX:+PrintCommandLineFlags"  registry.xxx.com/layer/build:new-1.0.1
-XX:InitialHeapSize=130478208 -XX:MaxHeapSize=2087651328 -XX:+PrintCommandLineFlags -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintTenuringDistribution -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseParallelGC
{Heap before GC invocations=1 (full 0):
PSYoungGen total 37888K, used 32768K [0x00000000d6800000, 0x00000000d9200000, 0x0000000100000000)
eden space 32768K, 100% used [0x00000000d6800000,0x00000000d8800000,0x00000000d8800000)
from space 5120K, 0% used [0x00000000d8d00000,0x00000000d8d00000,0x00000000d9200000)
to space 5120K, 0% used [0x00000000d8800000,0x00000000d8800000,0x00000000d8d00000)
ParOldGen total 86016K, used 0K [0x0000000083800000, 0x0000000088c00000, 0x00000000d6800000)

eden space 32768K, 0% used [0x00000000d6800000,0x00000000d6800000,0x00000000d8800000)
from space 5120K, 72% used [0x00000000d8800000,0x00000000d8ba1748,0x00000000d8d00000)
to space 5120K, 0% used [0x00000000dad00000,0x00000000dad00000,0x00000000db200000)
ParOldGen total 86016K, used 8K [0x0000000083800000, 0x0000000088c00000, 0x00000000d6800000)
object space 86016K, 0% used [0x0000000083800000,0x0000000083802000,0x0000000088c00000)
Metaspace used 6799K, capacity 7074K, committed 7168K, reserved 1056768K
class space used 820K, capacity 935K, committed 1024K, reserved 1048576K
}
...
2023-08-17 20:50:42.253 INFO 1 --- [ main] org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver.<init>(EndpointLinksResolver.java:58) - [] : Exposing 1 endpoint(s) beneath base path '/actuator'
2023-08-17 20:50:42.315 INFO 1 --- [ main] org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - [] : Starting ProtocolHandler ["http-nio-8082"]
2023-08-17 20:50:42.349 INFO 1 --- [ main] org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start(TomcatWebServer.java:220) - [] : Tomcat started on port(s): 8082 (http) with context path '/xxx'
2023-08-17 20:50:42.376 INFO 1 --- [ main] org.springframework.boot.StartupInfoLogger.logStarted(StartupInfoLogger.java:61) - [] : Started Application in 11.242 seconds (JVM running for 12.553)

对比两个版本可以发现只有application成hash值不一样 代码量增加了253kB-248kB=5KB

[root@localhost new]# docker image history  registry.xxx.com/layer/build:new
IMAGE CREATED CREATED BY SIZE COMMENT
2cce0deab7e2 About an hour ago /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B
555270edceea About an hour ago /bin/sh -c #(nop) COPY dir:2f5975d11563ae449… 248kB
75a9584e0952 About an hour ago /bin/sh -c #(nop) COPY dir:a3bb0870001a0ef25… 18.5kB
1542209ccc8b About an hour ago /bin/sh -c #(nop) COPY dir:16d00ea1f180914e2… 252kB
078e3f4a199c About an hour ago /bin/sh -c #(nop) COPY dir:1d3190ed598b634a5… 67.1MB
5c19ddda3114 About an hour ago /bin/sh -c #(nop) WORKDIR /app 0B
858e77315e6b About an hour ago /bin/sh -c mkdir -pv /app/logs && ln -s /app… 9B
63fb6c823893 3 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
9304102c278e 3 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
<missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
<missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
<missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
[root@localhost new]# docker image history registry.xxx.com/layer/build:new-1.0.1
IMAGE CREATED CREATED BY SIZE COMMENT
76aa6233354a 40 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B
0f138b106caf 40 minutes ago /bin/sh -c #(nop) COPY dir:4d21cc5ce0d92794b… 253kB
75a9584e0952 About an hour ago /bin/sh -c #(nop) COPY dir:a3bb0870001a0ef25… 18.5kB
1542209ccc8b About an hour ago /bin/sh -c #(nop) COPY dir:16d00ea1f180914e2… 252kB
078e3f4a199c About an hour ago /bin/sh -c #(nop) COPY dir:1d3190ed598b634a5… 67.1MB
5c19ddda3114 About an hour ago /bin/sh -c #(nop) WORKDIR /app 0B
858e77315e6b About an hour ago /bin/sh -c mkdir -pv /app/logs && ln -s /app… 9B
63fb6c823893 3 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
9304102c278e 3 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO… 302MB
<missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
<missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
<missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i… 116MB
<missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
<missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

完

上述对开发没有恶意,大家都是辛苦勤劳上进的打工人。 哈哈哈又是摸🐟的一天 —Author Logn

引用:spring boot官方文档)

文章目录
  1. 1. 导读
  2. 2. 基础环境
  3. 3. 基于传统单个jar包构建模式
    1. 3.1. 基础Dockerfile
    2. 3.2. Base镜像信息
    3. 3.3. Base镜像大小 622MB
    4. 3.4. Base镜像history信息
    5. 3.5. 传统构建方式
    6. 3.6. 构建后镜像大小 为基础镜像大小 622MB + 2*65M <= 757MB
    7. 3.7. 成品构建history信息
    8. 3.8. 优化Dockerfile
  4. 4. 基于spring boot 分层构建方式
    1. 4.1. 探索基于分层构建原理
    2. 4.2. 基于分层构建构建制品镜像
    3. 4.3. 验证模拟开发推送代码更新镜像
  5. 5. 验证镜像