找回密码
立即注册
搜索
发回帖 发新帖

6249

积分

0

好友

764

主题
发表于 18 小时前 | 查看: 2| 回复: 0

导读

在容器化部署 Spring Boot 应用时,大家通常会采用基础 Java 镜像再加 jar 包层的方式构建应用镜像制品。但随着公司业务持续上云,每个变更日需要上传到云端的镜像越来越多,本地机房到云端的带宽压力直线上升。为了解决镜像上传瓶颈,我们调研了相关技术栈,最终决定采用 Spring Boot 2.3 引入的镜像分层构建功能。

Docker 容器镜像分层构建示意图

基础环境

  • Spring Boot version >= 2.3
  • Java Oracle JDK 8u201
  • Docker version 20.10.13

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

基础 Dockerfile

下面是我们基于基础镜像构建 Spring Boot 镜像制品的 Dockerfile,采用的是比较传统的 COPY jar 包方式。相信这也是大多数团队的普遍做法。先看这份 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 包加基础镜像要大😢 问题出在哪?

#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 在构建时判定文件发生了变化,于是生成了大小完全相同的两层。(这其实是我当初自己优化时埋下的屎山😊)具体 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

问题定位清楚了,优化思路也就清晰了:先创建目录并递归授权,再通过 COPY 命令指定 1001 属主属组,避免后续 chown 再产生新层。

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,把多阶段构建拆分来看。

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

构建新版本时,第二阶段命中了缓存,只更新了 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 官方文档

文章有帮助的话,在看,转发吧。谢谢支持哟 (*^__^*)



上一篇:微软开源Garnet缓存存储系统,性能大幅超越Redis
下一篇:PVE Display 菜单详解:14 种显示设备区别与选型指南
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-10-5 22:58 , Processed in 0.095237 second(s), 42 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表