导读

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

基础环境

  • SpringBoot version >= 2.3
  • Java Oracle Jdk 8u201
  • Docker version 20.10.13

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

基础Dockerfile

以下是基于基础镜像构建SpringBoot镜像制品的Dockerfile,采用了比较传统的COPY jar包。相信这也是大家普遍采用的模式。Dockefile如下,该Dockerfile存在一个坑,会在下边阐述。
  1. FROM registry.xxx.com/base/oracle-jdk:8u201
  2. ENV TZ=Asia/Shanghai
  3. ENV LC_ALL en_US.utf8
  4. WORKDIR /app
  5. ADD ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
  6. ADD ./entrypoint.sh /app/bin/entrypoint.sh
  7. ENTRYPOINT exec bash /app/bin/entrypoint.sh
  8. RUN ln -s /app/logs /app/log && chown 1001.1001 -R /app

Base镜像信息

base镜像主要分三层添加了相关常用的工具如telnet netstat等以及安全修复
  1. docker image inspect registry.xxx.com/base/oracle-jdk:8u201
分层信息:
  1. "RootFS": {
  2. "Type": "layers",
  3. "Layers": [
  4. "sha256:174f5685490326fc0a1c0f5570b8663732189b327007e47ff13d2ca59673db02",
  5. "sha256:2105884a1756425b2188084cc1738d6a6b13293773af56f6727af1be979858ed",
  6. "sha256:c33745b350978d855171c996779055195b09e227844b7a03a1d795aee803dbb9"
  7. ]
  8. }

Base镜像大小 622MB

镜像大小 622MB 不算太小,对比友商有些基础镜像竟然1-2G😂 简直有点离谱。
  1. registry.xxx.com/base/oracle-jdk 8u201 1869b73a8999 2 years ago 622MB

Base镜像history信息

从构建历史可以看出占用空间主要分为三层分别是
  • Centos 7 基础镜像层
  • Yum install 层
  • Jdk 层
  1. docker image history registry.xxx.com/base/oracle-jdk:8u201
  2. IMAGE CREATED CREATED BY SIZE COMMENT
  3. 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO 302MB
  4. <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
  5. <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
  6. <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i 116MB
  7. <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=… 0B
  8. <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  9. <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  10. <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

传统构建方式

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

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

构建后比预期的 jar包加基础镜像所占用的空间大😢 why?
  1. #jar包大小
  2. ls -lh xxx-1.0.0.jar
  3. -rw------- 1 root root 65M Aug 16 10:33 xxx-1.0.0.jar
  4. #镜像大小
  5. docker image ls |grep registry.xxx.com/layer/build
  6. registry.xxx.com/layer/build old b6043465c072 59 seconds ago 757MB

成品构建history信息

查看构建成品的镜像层发现竟然有两层一样大小,也会被推送了两遍。🥲离大谱。通过分析Dockerfile是因为<font style="color:rgb(30, 107, 184);">RUN ln -s /app/logs /app/log && chown 1001.1001 -R /app</font> 导致的。为保证镜像安全,生产环境运行统一采用了1001账号运行。为了保证1001对workdir有绝对的读写权限。对目录递归授权导致文件属性发生改变。 在构建时认为文件发生变化产生一样大小的两层导致的。具体原因也不太清楚docker构建时如何判定文件发生变化,原本以为是基于MD5码。实际上在对文件属主属组改变时MD5码是不对变的。
  1. docker image history registry.xxx.com/layer/build:old
  2. IMAGE CREATED CREATED BY SIZE COMMENT
  3. b6043465c072 6 minutes ago /bin/sh -c ln -s /app/logs /app/log && chown 67.4MB
  4. 20679a170252 6 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
  5. 0902efa62157 6 minutes ago /bin/sh -c #(nop) ADD file:9ac19caf793524884… 128B
  6. 08928447fafa 6 minutes ago /bin/sh -c #(nop) ADD file:c7624c195e7c047ee… 67.4MB
  7. c057ab4a7d18 6 minutes ago /bin/sh -c #(nop) WORKDIR /app 0B
  8. 63fb6c823893 6 minutes ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
  9. 9304102c278e 6 minutes ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
  10. 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO 302MB
  11. <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
  12. <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
  13. <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i 116MB
  14. <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
  15. <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  16. <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  17. <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
  18. #镜像也推送了两层一样大小
  19. [root@localhost old-nochown]# docker push registry.xxx.com/layer/build:old
  20. The push refers to repository [registry.xxx.com/layer/build]
  21. bb35157fcb0b: Pushing [=============> ] 18.35MB/67.45MB
  22. 3c0641004863: Pushed
  23. 6ed0abaff975: Pushing [=====================> ] 28.38MB/67.45MB
  24. aa0794231b2c: Pushed
  25. c33745b35097: Layer already exists
  26. 2105884a1756: Layer already exists
  27. 174f56854903: Layer already exists

优化Dockerfile

原因知道了。优化思路是先创建目录并递归授权。同时构建出来的jar的权限可以通过COPY 指定1001属主属组。
  1. FROM registry.xxx.com/base/oracle-jdk:8u201
  2. ENV TZ=Asia/Shanghai
  3. ENV LC_ALL en_US.utf8
  4. RUN mkdir -pv /app/{bin,lib,logs} && ln -s /app/logs /app/log && chown 1001:1001 -R /app
  5. WORKDIR /app
  6. COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
  7. COPY --chown=1001:1001 ./entrypoint.sh /app/bin/entrypoint.sh
  8. ENTRYPOINT exec bash /app/bin/entrypoint.sh
优化后的镜像只有COPY这一层的jar包了。
  1. docker image history registry.xxx.com/layer/build:old-mkdir
  2. IMAGE CREATED CREATED BY SIZE COMMENT
  3. b9fc3a8a97f2 29 hours ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
  4. c823448f9582 29 hours ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 128B
  5. 9a997f3962bf 29 hours ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 67.4MB
  6. f272c4e64f87 29 hours ago /bin/sh -c #(nop) WORKDIR /app 0B
  7. 1a526d3df7c2 29 hours ago /bin/sh -c mkdir -pv /app/{bin,lib,logs} && 9B
  8. 63fb6c823893 30 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
  9. 9304102c278e 30 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
  10. 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO 302MB
  11. <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
  12. <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
  13. <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i 116MB
  14. <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
  15. <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  16. <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  17. <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB

基于SpringBoot 分层构建方式

探索基于分层构建原理

直接上手官方文档的demo 把官方文档demo的多阶段构建拆分一下。
  1. $ cat Dockerfile
  2. FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
  3. WORKDIR /app
  4. COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
  5. RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.0.jar extract
一阶段实际就是将jar解压按照SpringBoot layers.idx文件中的分层方式将依赖和业务代码分层。
  1. - "dependencies":
  2. - BOOT-INF/lib/library1.jar
  3. - BOOT-INF/lib/library2.jar
  4. - "spring-boot-loader":
  5. - org/springframework/boot/loader/JarLauncher.class
  6. - org/springframework/boot/loader/jar/JarEntry.class
  7. - "snapshot-dependencies":
  8. - BOOT-INF/lib/library3-SNAPSHOT.jar
  9. - "application":
  10. - META-INF/MANIFEST.MF
  11. - BOOT-INF/classes/a/b/C.class
进入到容器中可以看到被解压为4个目录:
  1. [root@b762a63589c1 app]# ls
  2. application dependencies lib logs snapshot-dependencies spring-boot-loader
存储占用如下:其中不出意外dependencies也就是依赖库占用是最大的 业务代码只有可怜的304K🤔
  1. [root@29d87aaf64b9 app]# du -lh --max-depth=1
  2. 304K ./application
  3. 65M ./dependencies
  4. 0 ./logs
  5. 20K ./snapshot-dependencies
  6. 420K ./spring-boot-loader
  7. 65M ./lib
  8. 130M .

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

在官方的Demo上修改得到完整的Dockerfile。其中优化了Entrypoint脚本,采用分层构建后启动应用不能采用传统的<font style="color:rgb(30, 107, 184);">java $JAVA_OPTS -jar xxx.jar</font>这方式启动应用。要使用<font style="color:rgb(30, 107, 184);">java org.springframework.boot.loader.JarLauncher</font>启动应用因此jvm参数需要通过脚本接受容器的环境变量来传入。
  1. FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
  2. WORKDIR /app
  3. COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
  4. RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.0.jar extract
  5. FROM registry.xxx.com/base/oracle-jdk:8u201
  6. ENV TZ=Asia/Shanghai
  7. ENV LC_ALL en_US.utf8
  8. RUN mkdir -pv /app/logs && ln -s /app/logs /app/log && chown 1001:1001 -R /app
  9. WORKDIR /app
  10. COPY --chown=1001:1001 --from=builder /app/dependencies/ ./
  11. COPY --chown=1001:1001 --from=builder /app/spring-boot-loader/ ./
  12. COPY --chown=1001:1001 --from=builder /app/snapshot-dependencies/ ./
  13. COPY --chown=1001:1001 --from=builder /app/application/ ./
  14. CMD ["exec"]
  15. ENTRYPOINT ["bash","/app/entrypoint.sh"]
entrypoint.sh脚本使用exec将Java作为容器1号进程,避免无法接受Linux 信号导致java进程无法正常退出。
  1. #!/bin/bash
  2. if [ -f /opt/cm/before.sh ]; then
  3. source /opt/cm/before.sh;
  4. fi
  5. exec java $JAVA_OPTS org.springframework.boot.loader.JarLauncher
构建镜像
  1. [root@localhost new]# docker build -t registry.xxx.com/layer/build:new .
  2. Sending build context to Docker daemon 67.45MB
  3. Step 1/14 : FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
  4. ---> 1869b73a8999
  5. Step 2/14 : WORKDIR /app
  6. ---> Using cache
  7. ---> 6973e49f31fa
  8. Step 3/14 : COPY --chown=1001:1001 ./xxx-1.0.0.jar /app/lib/xxx-1.0.0.jar
  9. ---> Using cache
  10. ---> c5a17d5969ea
  11. Step 4/14 : RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.0.jar extract
  12. ---> Using cache
  13. ---> 911074c3ef21
  14. Step 5/14 : FROM registry.xxx.com/base/oracle-jdk:8u201
  15. ---> 1869b73a8999
  16. Step 6/14 : ENV TZ=Asia/Shanghai
  17. ---> Using cache
  18. ---> 9304102c278e
  19. Step 7/14 : ENV LC_ALL en_US.utf8
  20. ---> Using cache
  21. ---> 63fb6c823893
  22. Step 8/14 : RUN mkdir -pv /app/logs && ln -s /app/logs /app/log && chown 1001:1001 -R /app
  23. ---> Running in 9cac9cb86507
  24. mkdir: created directory ‘/app
  25. mkdir: created directory ‘/app/logs
  26. Removing intermediate container 9cac9cb86507
  27. ---> 858e77315e6b
  28. Step 9/14 : WORKDIR /app
  29. ---> Running in 81c7173692fc
  30. Removing intermediate container 81c7173692fc
  31. ---> 5c19ddda3114
  32. Step 10/14 : COPY --chown=1001:1001 --from=builder /app/dependencies/ ./
  33. ---> 078e3f4a199c
  34. Step 11/14 : COPY --chown=1001:1001 --from=builder /app/spring-boot-loader/ ./
  35. ---> 1542209ccc8b
  36. Step 12/14 : COPY --chown=1001:1001 --from=builder /app/snapshot-dependencies/ ./
  37. ---> 75a9584e0952
  38. Step 13/14 : COPY --chown=1001:1001 --from=builder /app/application/ ./
  39. ---> 555270edceea
  40. Step 14/14 : ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
  41. ---> Running in fe99278683a2
  42. Removing intermediate container fe99278683a2
  43. ---> 2cce0deab7e2
  44. Successfully built 2cce0deab7e2
  45. Successfully tagged registry.xxx.com/layer/build:new
查看分层详情,可以看到jar被拆分成4层分别由copy指令创建。
  1. [root@localhost ~]# docker image history registry.xxx.com/layer/build:new
  2. IMAGE CREATED CREATED BY SIZE COMMENT
  3. 2cce0deab7e2 28 hours ago /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B
  4. 555270edceea 28 hours ago /bin/sh -c #(nop) COPY dir:2f5975d11563ae449… 248kB
  5. 75a9584e0952 28 hours ago /bin/sh -c #(nop) COPY dir:a3bb0870001a0ef25… 18.5kB
  6. 1542209ccc8b 28 hours ago /bin/sh -c #(nop) COPY dir:16d00ea1f180914e2… 252kB
  7. 078e3f4a199c 28 hours ago /bin/sh -c #(nop) COPY dir:1d3190ed598b634a5… 67.1MB
  8. 5c19ddda3114 28 hours ago /bin/sh -c #(nop) WORKDIR /app 0B
  9. 858e77315e6b 28 hours ago /bin/sh -c mkdir -pv /app/logs && ln -s /app 9B
  10. 63fb6c823893 30 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
  11. 9304102c278e 30 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
  12. 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO 302MB
  13. <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
  14. <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
  15. <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i 116MB
  16. <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
  17. <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  18. <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  19. <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
对比发现jar包被拆分了。
  1. [root@localhost new]# diff old.info new.info
  2. 1,16c1,18
  3. < IMAGE CREATED CREATED BY SIZE COMMENT
  4. < b9fc3a8a97f2 About an hour ago /bin/sh -c #(nop) ENTRYPOINT ["/bin/sh" "-c… 0B
  5. < c823448f9582 About an hour ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 128B
  6. < 9a997f3962bf About an hour ago /bin/sh -c #(nop) COPY --chown=1001:1001file… 67.4MB
  7. < f272c4e64f87 About an hour ago /bin/sh -c #(nop) WORKDIR /app 0B
  8. < 1a526d3df7c2 About an hour ago /bin/sh -c mkdir -pv /app/{bin,lib,logs} && 9B
  9. < 63fb6c823893 2 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
  10. < 9304102c278e 2 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
  11. < 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO 302MB
  12. < <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
  13. < <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
  14. < <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i 116MB
  15. < <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
  16. < <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  17. < <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  18. < <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
  19. ---
  20. > IMAGE CREATED CREATED BY SIZE COMMENT
  21. > 2cce0deab7e2 8 minutes ago /bin/sh -c #(nop) ENTRYPOINT ["java" "org.s… 0B
  22. > 555270edceea 8 minutes ago /bin/sh -c #(nop) COPY dir:2f5975d11563ae449… 248kB
  23. > 75a9584e0952 8 minutes ago /bin/sh -c #(nop) COPY dir:a3bb0870001a0ef25… 18.5kB
  24. > 1542209ccc8b 8 minutes ago /bin/sh -c #(nop) COPY dir:16d00ea1f180914e2… 252kB
  25. > 078e3f4a199c 8 minutes ago /bin/sh -c #(nop) COPY dir:1d3190ed598b634a5… 67.1MB
  26. > 5c19ddda3114 8 minutes ago /bin/sh -c #(nop) WORKDIR /app 0B
  27. > 858e77315e6b 8 minutes ago /bin/sh -c mkdir -pv /app/logs && ln -s /app 9B
  28. > 63fb6c823893 2 hours ago /bin/sh -c #(nop) ENV LC_ALL=en_US.utf8 0B
  29. > 9304102c278e 2 hours ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai 0B
  30. > 1869b73a8999 2 years ago /bin/sh -c set -ex; cd /tmp; curl -fsSLO 302MB
  31. > <missing> 2 years ago /bin/sh -c #(nop) ENV JAVA_VERSION=8 JAVA_U… 0B
  32. > <missing> 2 years ago /bin/sh -c #(nop) ENV TZ=Asia/Shanghai LANG… 0B
  33. > <missing> 2 years ago /bin/sh -c set -ex; yum update -y; yum i 116MB
  34. > <missing> 2 years ago /bin/sh -c #(nop) LABEL maintainer=currycan… 0B
  35. > <missing> 2 years ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
  36. > <missing> 2 years ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
  37. > <missing> 2 years ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
推送到仓库
  1. [root@localhost new]# docker push registry.xxx.com/layer/build:new
  2. The push refers to repository [registry.xxx.com/layer/build]
  3. e5409ea62302: Pushed
  4. 7167dfa406ea: Pushed
  5. cf7e94a2dc11: Pushed
  6. 8e261e1bae2c: Pushed
  7. 770c31a84800: Pushed
  8. c33745b35097: Layer already exists
  9. 2105884a1756: Layer already exists
  10. 174f56854903: Layer already exists
  11. new: digest: sha256:faef10681394c01d1c2973ed10c7c33e7289eec25f22c90d085f6eef96ce3bff size: 2001

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

  1. [root@localhost new]# md5sum bc-1.0.1.jar bc-1.0.0.jar
  2. 3792d3178a4e07708052b7effa9b12f8 xxx-1.0.1.jar
  3. 8ee570b94977668631355cb49c5d7cf1 xxx-1.0.0.jar
构建新版本,构建过程阶段二中使用了cache 仅更新了 application层
  1. [root@localhost new]# docker image build -t registry.xxx.com/layer/build:new-1.0.1 .
  2. Sending build context to Docker daemon 134.9MB
  3. Step 1/16 : FROM registry.xxx.com/base/oracle-jdk:8u201 as builder
  4. ---> 1869b73a8999
  5. Step 2/16 : WORKDIR /app
  6. ---> Using cache
  7. ---> 6973e49f31fa
  8. Step 3/16 : COPY --chown=1001:1001 ./xxx-1.0.1.jar /app/lib/xxx-1.0.1.jar
  9. ---> b219210fd8ab
  10. Step 4/16 : RUN java -Djarmode=layertools -jar /app/lib/xxx-1.0.1.jar extract
  11. ---> Running in d099c10b653c
  12. Removing intermediate container d099c10b653c
  13. ---> 66a8593b0291
  14. Step 5/16 : FROM registry.xxx.com/base/oracle-jdk:8u201
  15. ---> 1869b73a8999
  16. Step 6/16 : ENV TZ=Asia/Shanghai
  17. ---> Using cache
  18. ---> 9304102c278e
  19. Step 7/16 : ENV LC_ALL en_US.utf8
  20. ---> Using cache
  21. ---> 63fb6c823893
  22. Step 8/16 : RUN mkdir -pv /app/logs && ln -s /app/logs /app/log && chown 1001:1001 -R /app
  23. ---> Using cache
  24. ---> 858e77315e6b
  25. Step 9/16 : WORKDIR /app
  26. ---> Using cache
  27. ---> 5c19ddda3114
  28. Step 10/16 : COPY --chown=1001:1001 ./entrypoint.sh /app/entrypoint.sh
  29. ---> Using cache
  30. ---> c47b74bb8cf9
  31. Step 11/16 : COPY --chown=1001:1001 --from=builder /app/dependencies/ ./
  32. ---> Using cache
  33. ---> 078e3f4a199c
  34. Step 12/16 : COPY --chown=1001:1001 --from=builder /app/spring-boot-loader/ ./
  35. ---> Using cache
  36. ---> 1542209ccc8b
  37. Step 13/16 : COPY --chown=1001:1001 --from=builder /app/snapshot-dependencies/ ./
  38. ---> Using cache
  39. ---> 75a9584e0952
  40. Step 14/16 : COPY --chown=1001:1001 --from=builder /app/application/ ./
  41. ---> 0f138b106caf
  42. Step 15/16 : CMD ["exec"]
  43. ---> Using cache
  44. ---> a1170ae7a20e
  45. Step 16/16 : ENTRYPOINT ["bash","/app/entrypoint.sh"]
  46. ---> Using cache
  47. ---> 5a6bb7613fc8
  48. Successfully built 5a6bb7613fc8
  49. Successfully tagged registry.xxx.com/layer/build:new-1.0.1
推送到仓库可以看到仅推送了application层 只有300K
  1. docker push registry.xxx.com/layer/build:new-1.0.1
  2. The push refers to repository [registry.xxx.com/layer/build]
  3. c33a5c6456bd: Pushed
  4. 7167dfa406ea: Layer already exists
  5. cf7e94a2dc11: Layer already exists
  6. 8e261e1bae2c: Layer already exists
  7. 770c31a84800: Layer already exists
  8. c33745b35097: Layer already exists
  9. 2105884a1756: Layer already exists
  10. 174f56854903: Layer already exists
  11. new-1.0.1: digest: sha256:53647bb45f0f0bb5bb8d56f14cd40deb22f0d5e4fce1200fed1c225a516dddb5 size: 2001

验证镜像

  1. 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
可以看到打印出了堆栈信息(容器默认是不开启的)应用成功启动😋
  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
  2. -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
  3. {Heap before GC invocations=1 (full 0):
  4. PSYoungGen total 37888K, used 32768K [0x00000000d6800000, 0x00000000d9200000, 0x0000000100000000)
  5. eden space 32768K, 100% used [0x00000000d6800000,0x00000000d8800000,0x00000000d8800000)
  6. from space 5120K, 0% used [0x00000000d8d00000,0x00000000d8d00000,0x00000000d9200000)
  7. to space 5120K, 0% used [0x00000000d8800000,0x00000000d8800000,0x00000000d8d00000)
  8. ParOldGen total 86016K, used 0K [0x0000000083800000, 0x0000000088c00000, 0x00000000d6800000)
  9. eden space 32768K, 0% used [0x00000000d6800000,0x00000000d6800000,0x00000000d8800000)
  10. from space 5120K, 72% used [0x00000000d8800000,0x00000000d8ba1748,0x00000000d8d00000)
  11. to space 5120K, 0% used [0x00000000dad00000,0x00000000dad00000,0x00000000db200000)
  12. ParOldGen total 86016K, used 8K [0x0000000083800000, 0x0000000088c00000, 0x00000000d6800000)
  13. object space 86016K, 0% used [0x0000000083800000,0x0000000083802000,0x0000000088c00000)
  14. Metaspace used 6799K, capacity 7074K, committed 7168K, reserved 1056768K
  15. class space used 820K, capacity 935K, committed 1024K, reserved 1048576K
  16. }
  17. ...
  18. 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'
  19. 2023-08-17 20:50:42.315 INFO 1 --- [ main] org.apache.juli.logging.DirectJDKLog.log(DirectJDKLog.java:173) - [] : Starting ProtocolHandler ["http-nio-8082"]
  20. 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'
  21. 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值不一样 代码量增加了<font style="color:rgb(30, 107, 184);">253kB-248kB=5KB</font>

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