社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  docker

SpringBoot 项目构建 Docker 镜像深度调优

SpringForAll社区 • 4 年前 • 281 次点击  
点击上方☝SpringForAll社区 轻松关注!
及时获取有趣有料的技术文章

本文来源:http://www.mydlq.club/article/16/


. 一、探究常规 Springboot 如何编译 Docker 镜像

. 1、准备编译镜像的 SpringBoot 项目

. 2、准备 Dockerfile 文件

. 3、构建 Docker 镜像

. 4、将镜像推送到镜像仓库

. 5、拉取镜像

. 6、修改 Java 源码重新打包 Jar 后再次尝试

. 7、使用镜像过程中的感受

. 二、了解 Docker 分层及缓存机制

. 1、Docker 分层缓存简介

. 2、SpringBoot Docker 镜像的分层

. 三、是什么导致 Jar 包臃肿

. 1、解压 Jar 包查看内容

. 2、解决臃肿的新思路

. 3、如何解决 lib 和 class 文件分离

. 四、聊聊如何改造 Springboot 编译 Docker 镜像

. 1、修改 Dockerfile 文件

. 2、改造 Docker 镜像后的首次编译、推送、拉取

. 3、再次编译、推送、拉取

. 五、最后总结


PS:已经在生产实践中验证,解决在生产环境下,网速带宽小,每次推拉镜像影响线上服务问题,按本文方式构建镜像,除了第一次拉取、推送、构建镜像慢,第二、三…次都是几百K大小传输,速度非常快,构建、打包、推送几秒内完成。

前言:

以前的 SpringCloud 微服务时代以 “Jar包” 为服务的基础,每个服务都打成 Jar 供服务间相互关联与调用。而 现在随着 Kubernetes 流行,已经变迁到一个镜像一个服务,依靠 Kubernetes 对镜像的统一编排进行对服务进行统一管理。在对 Kubernetes 微服务实践过程中,接触最多的肯定莫过于 Docker 镜像。由于本人使用的编程语言是 Java,所以对 Java SpringBoot 项目接触比较多,所以比较关心如何更好的通过 Dockerfile 编译 Docker 的镜像。

Kubernetes 微服务简单说就是一群镜像间的排列组合与相互间调的关系,故而如何编译镜像会使服务性能更优,使镜像构建、推送、拉取速度更快,使其占用网络资源更少这里优化,更易使用成为了一个重中之重的事情,也是一个非常值得琢磨的问题。这里我将对 SpringBoot 项目打包 Docker 镜像如何写 Dockerfile 的探究进行简单叙述。

系统环境:

  • Docker 版本: 18.09.3

  • Open JDK 基础镜像版本:openjdk:8u212-b04-jre-slim

  • 测试用的镜像仓库:阿里云 Docker Hub

  • 项目 Github: https://github.com/my-dlq/blog-example/tree/master/springboot/springboot-dockerfile


一、探究常规 Springboot 如何编译 Docker 镜像

这里将用常规 SpringBoot 编译 Docker 镜像的 Dockerfile 写法,感受下这种方式编译的镜像用起来如何。

1、准备编译镜像的 SpringBoot 项目

这里准备一个经过 Maven 编译后的普通的 springboot 项目来进行 Docker 镜像构建,项目内容如下图所示,可以看到要用到的就是里面的应用程序的 Jar 文件,将其存入镜像内完成镜像构建任务。

  • jar 文件大小:70.86mb

2、准备 Dockerfile 文件

构建 Docker 镜像需要提前准备 Dockerfile 文件,这个 Dockerfile 文件中的内容为构建 Docker 镜像执行的指令。下面是一个常用的 SpringBoot 构建 Docker 镜像的 Dockerfile,将它放入 Java 源码目录(target 的上级目录),确保下面设置的 Dockerfile 脚本中设置的路径和 target 路径对应。

  1. FROM openjdk:8u212-b04-jre-slim

  2. VOLUME /tmp

  3. ADD target/*.jar app.jar

  4. RUN sh -c 'touch /app.jar'

  5. ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

  6. ENV APP_OPTS=""

  7. ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

3、构建 Docker 镜像

通过 Docker build 命令构建 Docker 镜像,观察编译的时间。

由于后续需要将镜像推送到 Aliyun Docker 仓库,所以镜像前缀用了 Aliyun。

  • time:此参数会显示执行过程经过的时间

  1. $ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1 .

构建过程

  1. Sending build context to Docker daemon 148.7MB

  2. Step 1/7 : FROM openjdk :8u212-b04-jre-slim

  3. 8u212-b04-jre-slim: Pulling from library/openjdk

  4. 743f2d6c1f65: Already exists

  5. b83e581826a6: Pull complete

  6. 04305660f45e: Pull complete

  7. bbe7020b5561: Pull complete

  8. Digest: sha256 :a5bcd678408a5fe94d13e486d500983ee6fa594940cbbe137670fbb90030456c

  9. Status: Downloaded newer image for openjdk:8u212-b04-jre-slim

  10. ---> 7c6b62cf60ee

  11. Step 2/7 : VOLUME /tmp

  12. ---> Running in 13a67ab65d2b

  13. Removing intermediate container 13a67ab65d2b

  14. ---> 52011f49ddef

  15. Step 3/7 : ADD target/*.jar app.jar

  16. ---> 26aa41a404fd

  17. Step 4/7 : RUN sh -c 'touch /app.jar'

  18. ---> Running in 722e7e44e04d

  19. Removing intermediate container 722e7e44e04d

  20. ---> 7baedb10ec62

  21. Step 5/7 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

  22. ---> Running in 2681d0c5edac

  23. Removing intermediate container 2681d0c5edac

  24. ---> 5ef4a794b992

  25. Step 6/7 : ENV APP_OPTS=""

  26. ---> Running in 5c8924a2a49d

  27. Removing intermediate container 5c8924a2a49d

  28. ---> fba87c19053a

  29. Step 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

  30. ---> Running in c4cf97009b3c

  31. Removing intermediate container c4cf97009b3c

  32. ---> d5f30cdfeb81

  33. Successfully built d5f30cdfeb81

  34. Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1


  35. real 0m13.778s

  36. user 0m0.078s

  37. sys 0m0.153s

看到这次编译在 14s 内完成。

4、将镜像推送到镜像仓库

将镜像推送到 Aliyun 仓库,然后查看并记录推送时间

  1. $ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0 .1

执行过程

  1. The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]

  2. cc1a2376d7c0: Pushed

  3. 2b940d07e9e7: Pushed

  4. 9544e87fb8dc: Pushed

  5. feb5d0e1e192: Pushed

  6. 8fd22162ddab : Pushed

  7. 6270adb5794c: Pushed

  8. 0.0.1: digest: sha256:dc60d304383b1441941ca4e9abc08db775d7be57ccb7c534c929b34ff064a62f size: 1583


  9. real 0m24.335s

  10. user 0m0.052s

  11. sys 0m0.059s

看到这次在 25s 内完成。

5、拉取镜像

这里切换到另一台服务器上进行镜像拉取操作,观察镜像拉取时间。

  1. $ time docker pull registry.cn-beijing.aliyuncs. com/mydlq/springboot:0.0.1

拉取过程

  1. 0.0.1: Pulling from mydlq/springboot

  2. 743f2d6c1f65: Already exists

  3. b83e581826a6: Pull complete

  4. 04305660f45e: Pull complete

  5. bbe7020b5561: Pull complete

  6. 4847672cbfa5: Pull complete

  7. b60476972fc4: Pull complete

  8. Digest: sha256:dc60d304383b1441941ca4e9abc08db775d7be57ccb7c534c929b34ff064a62f

  9. Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1


  10. real 0m27.528s

  11. user 0m0.033s

  12. sys 0m0.192s

看到这次拉取总共用时 28s 内完成。

6、修改 Java 源码重新打包 Jar 后再次尝试

这里将源码的 JAVA 文件内容修改,然后重新打 Jar 包,这样再次尝试编译、推送、拉取过程,由于 Docker 在执行构建时会采用分层缓存,所以这是一个执行较快过程。

(1)、编译

  1. $ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2 .


  2. Sending build context to Docker daemon 148.7MB

  3. Step 1/7 : FROM openjdk:8u212-b04-jre-slim

  4. ---> 7c6b62cf60ee

  5. Step 2/7 : VOLUME /tmp

  6. ---> Using cache

  7. ---> 52011f49ddef

  8. Step 3/7 : ADD target/*.jar app.jar

  9. ---> c67160dd2a23

  10. Step 4/7 : RUN sh -c 'touch /app.jar'

  11. ---> Running in 474900d843a2

  12. Removing intermediate container 474900d843a2

  13. ---> 3ce9a8bb2600

  14. Step 5/7 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

  15. ---> Running in f48620b1ad36

  16. Removing intermediate container f48620b1ad36

  17. ---> 0478f8f14e5b

  18. Step 6/7 : ENV APP_OPTS=""

  19. ---> Running in 98485fb15fc8

  20. Removing intermediate container 98485fb15fc8

  21. ---> 0b567c848027

  22. Step 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

  23. ---> Running in e32242fc6efe

  24. Removing intermediate container e32242fc6efe

  25. ---> 7b223b23ebfd

  26. Successfully built 7b223b23ebfd

  27. Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  28. real 0m3.190s

  29. user 0m0.039s

  30. sys 0m0.403s

可以看到在编译镜像过程中,前1、2层用的缓存,所以速度非常快。总编译过程耗时 4s 内完成。

(2)、推送

  1. $ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  2. The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]

  3. d66a2fec30b5: Pushed

  4. f4da2c7581aa: Pushed

  5. 9544e87fb8dc: Layer already exists

  6. feb5d0e1e192: Layer already exists

  7. 8fd22162ddab: Layer already exists

  8. 6270adb5794c: Layer already exists


  9. real 0m20.816s

  10. user 0m0.024s

  11. sys 0m0.081s

可以看到只推送了前两层,其它四次由于远程仓库未变化,所以没有推送。整个推送过程耗时 21s 内完成。

(3)、拉取

  1. $ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  2. 0.0.2: Pulling from mydlq/springboot

  3. 743f2d6c1f65: Already exists

  4. b83e581826a6: Already exists

  5. 04305660f45e: Already exists

  6. bbe7020b5561: Already exists

  7. d7e364f0d94a: Pull complete

  8. 8d688ada35b1: Pull complete

  9. Digest: sha256:7c13c40fa92ec2fdc3a8dfdd3232be1be9c1a1a99bf123743ff2a43907ee03dc

  10. Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  11. real 0m23.214s

  12. user 0m0.053s

  13. sys 0m0.097s

本地以及缓存前四层,只拉取有变化的后两层。这个过程耗时 24s 内完成。

7、使用镜像过程中的感受

通过这种方式对 SpringBoot 项目构建 Docker 镜像来使用,给我的感受就是只要源码中发生一点点变化,那么 SpringBoot 项目就需要将项目经过 Maven 编译后再经过 Docker 镜像构建,每次都会将一个 70M+ 的应用 Jar 文件存入 Docker 中,有时候明明就改了一个字母,可能又得把整个程序 Jar 重新存入 Docker 镜像中,然后在推送和拉取过程中,每次都得推一个大的镜像或者拉取一个大的镜像来进行传输,感觉非常不方便。

二、了解 Docker 分层及缓存机制

1、Docker 分层缓存简介

Docker 为了节约存储空间,所以采用了分层存储概念。共享数据会对镜像和容器进行分层,不同镜像可以共享相同数据,并且在镜像上为容器分配一个 RW 层来加快容器的启动顺序。

在构建镜像的过程中 Docker 将按照 Dockerfile 中指定的顺序逐步执行 Dockerfile 中的指令。随着每条指令的检查,Docker 将在其缓存中查找可重用的现有镜像,而不是创建一个新的(重复)镜像。

Dockerfile 的每一行命令都创建新的一层,包含了这一行命令执行前后文件系统的变化。为了优化这个过程,Docker 使用了一种缓存机制:只要这一行命令不变,那么结果和上一次是一样的,直接使用上一次的结果即可。

为了充分利用层级缓存,我们必须要理解 Dockerfile 中的命令行是如何工作的,尤其是RUN,ADD和COPY这几个命令。

参考 Docker 文档了解 Docker 镜像缓存:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

2、SpringBoot Docker 镜像的分层

SpringBoot 编译成镜像后,底层会是一个系统,如 Ubantu,上一层是依赖的 JDK 层,然后才是 SpringBoot 层,最下面两层我们无法操作,考虑优化只能是 SpringBoot 层琢磨。

三、是什么导致 Jar 包臃肿

从上面实验中了解到之所以每次编译、推送、拉取过程中较为缓慢,原因就是庞大的镜像文件。了解到 Docker 缓存概念后就就产生一种想法,如果不经常改变的文件缓存起来,将常改动的文件不进行缓存。由于 SpringBoot 项目是经常变换的,那么应该怎么利用缓存机制来实现呢?如果强行利用缓存那么每次打的镜像不都是缓存中的旧的程序内容吗。

所以就考虑一下应用 Jar 包里面都包含了什么文件, Java 的哪些文件是经常变动的,哪些不经常变动,对此,下面将针对 SpringBoot 打的应用 Jar 包进行分析。

1、解压 Jar 包查看内容

显示解压后的列表,查看各个文件夹大小

  1. $ tree -L 3 --si --du


  2. .

  3. ├── [ 74M] BOOT-INF

  4. ├── [2.1k] classes

  5. └── [ 74M] lib

  6. ├── [ 649] META-INF

  7. ├── [ 552] MANIFEST.MF

  8. └── [ 59] maven

  9. └── [ 67] org

  10. └── [ 38] springframework

可以看到最大的文件就是 lib 这个文件夹,打开这个文件夹,里面是一堆相关依赖 Jar,这其中一个 Jar 不大,但是一堆 Jar 组合起来就非常大了,一般 SpringBoot 的项目依赖 Jar 大小维持在 40MB ~ 160MB。

在看看 org 文件夹,里面代码加起来才几百 KB。故此 SpringBoot 程序 Jar 包就是这些 Classes 文件和依赖的 Jar 组成,这些依赖 Jar 总共 74 MB,几乎占了这个应用 Jar 包的全部大小。

2、解决臃肿的新思路

如果一个 Jar 包只包含 class 文件,那么这个 Jar 包的大小可能就几百 KB。现在要探究一下,如果将 lib 依赖的 Jar 和 class 分离,设置应用的 Jar 包只包含 class 文件,将 lib 文件夹下的 Jar 文件放在 SpringBoot Jar 的外面。

当我们写一个程序的时候,常常所依赖的 Jar 不会经常变动,变动多的是源代码程序,依赖的 Jar 包非常大而源代码非常小。仔细思考一下,如果在打包成 Docker 镜像的时候将应用依赖的 Jar 包单独设置一层缓存,而应用 Jar 包只包含 Class 文件,这样在 Docker 执行编译、推送、拉取过程中,除了第一次是全部都要执行外,再往后的执行编译、推送、拉取过程中,只会操作改动的那个只包含 Class 的 Jar 文件,就几百 KB,可以说是能够瞬间完成这个过程。所以思考一下,如何将 lib 文件夹下的依赖 Jar 包和应用 Jar 包分离开来。

3、如何解决 lib 和 class 文件分离

经过查找很多相关资料,发现 SpringBoot 的 Maven 插件在执行 Maven 编译打 Jar 包时候做了很多事情,如果改变某些插件的打包逻辑,致使打应用 Jar 时候将 lib 文件夹下所有的 Jar 包都拷贝到应用 Jar 外面,只留下编译好的字节码文件。

将这几个 Maven 工具引入到项目 pom.xml 中

  1. org.apache.maven.plugins

  2. maven-jar-plugin

  3. true

  4. lib/

  5. org.springframework.boot

  6. spring-boot-maven-plugin

  7. nothing

  8. nothing

  9. org.apache.maven.plugins

  10. maven-dependency-plugin

  11. copy-dependencies

  12. prepare-package

  13. copy-dependencies

  14. ${project.build.directory}/lib

执行 Maven 命令打包 Jar

  1. $ mvn clean install

当 Maven 命令执行完成后,查看 target 目录如下图:

然后测试下这个 Jar 文件是否能正常运行

  1. $ java -jar springboot-helloworld-0.0 .1.jar

然后看到运行日志,OK!下面将继续进行 Dockerfile 改造工作。

四、聊聊如何改造 Springboot 编译 Docker 镜像

项目 Github 地址:https://github.com/my-dlq/blog-example/tree/master/springboot-dockerfile

1、修改 Dockerfile 文件

这里修改上面的 Dockerfile 文件,需要新增一层指令用于将 lib 目录里面的依赖 Jar 复制到镜像中,其它保持和上面 Dockerfile 一致。

  1. FROM openjdk:8u212-b04-jre-slim

  2. VOLUME /tmp

  3. COPY target/lib/ ./lib/

  4. ADD target/*.jar app.jar

  5. RUN sh -c 'touch /app.jar'

  6. ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

  7. ENV APP_OPTS=""

  8. ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

这里新增了一层指令,作用为将 lib 文件夹复制到镜像之中,由于 Docker 缓存机制原因,这层一定要在复制应用 Jar 之前,这样改造后每次只要 lib/ 文件夹里面的依赖 Jar 不变,就不会新创建层,而是复用缓存。

2、改造 Docker 镜像后的首次编译、推送、拉取

在执行编译、推送、拉取之前,先将服务器上次镜像相关的所有资源都清除掉,然后再执行。

(1)、编译

  1. $ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1 .


  2. Sending build context to Docker daemon 223.2MB

  3. Step 1/8 : FROM openjdk:8u212-b04-jre-slim

  4. 8u212-b04-jre-slim: Pulling from library/openjdk

  5. 743f2d6c1f65: Already exists

  6. b83e581826a6: Pull complete

  7. 04305660f45e: Pull complete

  8. bbe7020b5561: Pull complete

  9. Digest : sha256:a5bcd678408a5fe94d13e486d500983ee6fa594940cbbe137670fbb90030456c

  10. Status: Downloaded newer image for openjdk:8u212-b04-jre-slim

  11. ---> 7c6b62cf60ee

  12. Step 2/8 : VOLUME /tmp

  13. ---> Running in 529369acab24

  14. Removing intermediate container 529369acab24

  15. ---> ad689d937118

  16. Step 3/8 : COPY target/lib/ ./lib/

  17. ---> 029a64c15853

  18. Step 4/8 : ADD target/*.jar app.jar

  19. ---> 6265a83a1b90

  20. Step 5/8 : RUN sh - c 'touch /app.jar'

  21. ---> Running in 839032a58e6b

  22. Removing intermediate container 839032a58e6b

  23. ---> 5d877dc35b2b

  24. Step 6/8 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

  25. ---> Running in 4043994c5fed

  26. Removing intermediate container 4043994c5fed

  27. ---> 7cf32beb571f

  28. Step 7/8 : ENV APP_OPTS=""

  29. ---> Running in b7dcfa10458a

  30. Removing intermediate container b7dcfa10458a

  31. ---> b6b332bcf0e6

  32. Step 8/8 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

  33. ---> Running in 539093461b59

  34. Removing intermediate container 539093461b59

  35. ---> d4c095c4ffec

  36. Successfully built d4c095c4ffec

  37. Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1


  38. real 0m22.983s

  39. user 0m0.051s

  40. sys 0m0.540s

(2)、推送

  1. $ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1


  2. The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]

  3. c16749205e05: Pushed

  4. 7fef1a146748: Pushed

  5. a3bae74bbdf2: Pushed

  6. 9544e87fb8dc: Pushed

  7. feb5d0e1e192: Pushed

  8. 8fd22162ddab: Pushed

  9. 6270adb5794c: Pushed

  10. 0.0.1: digest: sha256:e2f4db740880dbe5338b823112ba9467fedf8b27cd75572611d0d3837c80f157 size: 1789


  11. real 0m30.335s

  12. user 0m0.052s

  13. sys 0m0.059s

(3)、拉取

  1. $ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1


  2. 0.0.1: Pulling from mydlq/springboot

  3. 743f2d6c1f65: Already exists

  4. b83e581826a6: Pull complete

  5. 04305660f45e: Pull complete

  6. bbe7020b5561: Pull complete

  7. de6c4f15d75b: Pull complete

  8. 7066947b7d89: Pull complete

  9. e0742de67c75: Pull complete

  10. Digest: sha256:e2f4db740880dbe5338b823112ba9467fedf8b27cd75572611d0d3837c80f157

  11. Status: Downloaded newer image for registry.cn-beijing.aliyuncs. com/mydlq/springboot:0.0.1


  12. real 0m36.585s

  13. user 0m0.024s

  14. sys 0m0.092s

3、再次编译、推送、拉取

(1)、编译

  1. $ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2 .


  2. Sending build context to Docker daemon 223.2MB

  3. Step 1/8 : FROM openjdk:8u212-b04-jre-slim

  4. ---> 7c6b62cf60ee

  5. Step 2/8 : VOLUME /tmp

  6. ---> Using cache

  7. ---> ad689d937118

  8. Step 3/8 : COPY target/lib/ ./lib/

  9. ---> Using cache

  10. ---> 029a64c15853

  11. Step 4/8 : ADD target/*.jar app.jar

  12. ---> 563773953844

  13. Step 5/8 : RUN sh -c 'touch /app.jar'

  14. ---> Running in 3b9df57802bd

  15. Removing intermediate container 3b9df57802bd

  16. ---> 706a0d47317f

  17. Step 6/8 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"

  18. ---> Running in defda61452bf

  19. Removing intermediate container defda61452bf

  20. ---> 742c7c926374

  21. Step 7/8 : ENV APP_OPTS=""

  22. ---> Running in f09b81d054dd

  23. Removing intermediate container f09b81d054dd

  24. ---> 929ed5f8b12a

  25. Step 8/8 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]

  26. ---> Running in 5dc66a8fc1e6

  27. Removing intermediate container 5dc66a8fc1e6

  28. ---> c4942b10992c

  29. Successfully built c4942b10992c

  30. Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  31. real 0m2.524s

  32. user 0m0.051s

  33. sys 0m0.493s

可以看到,这次在第 3 层直接用的缓存,整个编译过程才花了 2.5 秒时间

(2)、推送

  1. $ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  2. The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]

  3. d719b9540809: Pushed

  4. d45bf4c5fb92: Pushed

  5. a3bae74bbdf2 : Layer already exists

  6. 9544e87fb8dc: Layer already exists

  7. feb5d0e1e192: Layer already exists

  8. 8fd22162ddab: Layer already exists

  9. 6270adb5794c: Layer already exists

  10. 0.0.2: digest: sha256:b46d81b153ec64321caaae7ab28da0e362ed7d720a7f0775ea8d1f7bef310d00 size: 1789


  11. real 0m0.168s

  12. user 0m0.016s

  13. sys 0m0.032s

可以看到在 0.2s 内就完成了镜像推送

(3)、拉取

  1. $ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2


  2. 0.0.2: Pulling from mydlq/springboot

  3. 743f2d6c1f65: Already exists

  4. b83e581826a6: Already exists

  5. 04305660f45e: Already exists

  6. bbe7020b5561: Already exists

  7. de6c4f15d75b: Already exists

  8. 1c77cc70cc41: Pull complete

  9. aa5b8cbca568: Pull complete

  10. Digest: sha256:b46d81b153ec64321caaae7ab28da0e362ed7d720a7f0775ea8d1f7bef310d00

  11. Status: Downloaded newer image for registry.cn-beijing .aliyuncs.com/mydlq/springboot:0.0.2


  12. real 0m1.947s

  13. user 0m0.017s

  14. sys 0m0.042s

可以看到在 2s 内就完成了镜像拉取

五、最后总结

由于网络波动和系统变化,所以时间只能当做参考,不过执行编译、推送、拉取过程的确快了不少,大部分用文件都进行了缓存,只有几百 KB 的流量交互自然速度比几十 MB 甚至几百 MB 速度要快很多。

最后说明一下,这种做法只是提供了一种参考,现在的微服务服务 Docker 镜像化以来,维护的是整个镜像而不是一个服务程序,所以关心的是 Docker 镜像能否能正常运行,怎么构建镜像会使构建的镜像更好用。

在生产环境下由于版本变化较慢,不会动不动就更新,所以在生产环境下暂时最好还是按部就班,应用原来 SpringBoot 镜像编译方式以确保安装(除非已大量实例验证该构建方法)。




● CentOS7 安装 Maven

● Spring Cache 操作 Redis 实现数据缓存(下)

● Spring Cache 操作 Redis 实现数据缓存(上)

● Java人应该知道的SpringBoot For Kafka (上)

● Java人应该知道的SpringBoot For Kafka (下)

● SpringBoot 多种读取配置文件中参数的方式

● SpringBoot 操作 ElasticSearch 详解

 SpringBoot 使用 Caffeine 本地缓存

 Github推出了GitHub CLI

 (很全面)SpringBoot 集成 Apollo 配置中心

 你知道如何成为一名靠谱的架构师不?

 Tomcat 在 SpringBoot 中是如何启动的?

 SpringBoot 深度调优,让你的项目飞起来!

 8种经常被忽视的SQL错误用法,你有没有踩过坑?

 Java面试应该知道之深入理解Java的接口和抽象类


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/55401
 
281 次点击