02.28 SpringBoot 项目构建 Docker 镜像调优实践

http://www.mydlq.club/article/16/

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

SpringBoot 项目构建 Docker 镜像调优实践

2、准备 Dockerfile 文件

构建 Docker 镜像需要提前准备 Dockerfile 文件,这个 Dockerfile 文件中的内容为构建 Docker 镜像执行的指令。

下面是一个常用的 SpringBoot 构建 Docker 镜像的 Dockerfile,将它放入 Java 源码目录(target 的上级目录),确保下面设置的 Dockerfile 脚本中设置的路径和 target 路径对应。

<code>FROM openjdk:8u212-b04-jre-slimVOLUME /tmpADD target/*.jar app.jarRUN sh -c 'touch /app.jar'ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"ENV APP_OPTS=""ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]/<code>

3、构建 Docker 镜像

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

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

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

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

构建过程

<code>Sending build context to Docker daemon  148.7MBStep 1/7 : FROM openjdk:8u212-b04-jre-slim8u212-b04-jre-slim: Pulling from library/openjdk743f2d6c1f65: Already exists b83e581826a6: Pull complete 04305660f45e: Pull complete bbe7020b5561: Pull complete Digest: sha256:a5bcd678408a5fe94d13e486d500983ee6fa594940cbbe137670fbb90030456cStatus: Downloaded newer image for openjdk:8u212-b04-jre-slim ---> 7c6b62cf60eeStep 2/7 : VOLUME /tmp ---> Running in 13a67ab65d2bRemoving intermediate container 13a67ab65d2b ---> 52011f49ddefStep 3/7 : ADD target/*.jar app.jar ---> 26aa41a404fdStep 4/7 : RUN sh -c 'touch /app.jar' ---> Running in 722e7e44e04dRemoving intermediate container 722e7e44e04d ---> 7baedb10ec62Step 5/7 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai" ---> Running in 2681d0c5edacRemoving intermediate container 2681d0c5edac ---> 5ef4a794b992Step 6/7 : ENV APP_OPTS="" ---> Running in 5c8924a2a49dRemoving intermediate container 5c8924a2a49d ---> fba87c19053aStep 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ] ---> Running in c4cf97009b3cRemoving intermediate container c4cf97009b3c ---> d5f30cdfeb81Successfully built d5f30cdfeb81Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1real    0m13.778suser    0m0.078ssys 0m0.153s/<code>

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

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

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

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

执行过程

<code>The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]cc1a2376d7c0: Pushed 2b940d07e9e7: Pushed 9544e87fb8dc: Pushed feb5d0e1e192: Pushed 8fd22162ddab: Pushed 6270adb5794c: Pushed 0.0.1: digest: sha256:dc60d304383b1441941ca4e9abc08db775d7be57ccb7c534c929b34ff064a62f size: 1583real    0m24.335suser    0m0.052ssys 0m0.059s/<code>

看到这次在 25s 内完成。扩展:面试官:你简历中写用过docker,能说说容器和镜像的区别吗?

5、拉取镜像

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

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

拉取过程

<code>0.0.1: Pulling from mydlq/springboot743f2d6c1f65: Already exists b83e581826a6: Pull complete 04305660f45e: Pull complete bbe7020b5561: Pull complete 4847672cbfa5: Pull complete b60476972fc4: Pull complete Digest: sha256:dc60d304383b1441941ca4e9abc08db775d7be57ccb7c534c929b34ff064a62fStatus: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1real    0m27.528suser    0m0.033ssys 0m0.192s/<code>

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

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

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

(1)、编译

<code>$ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2 .Sending build context to Docker daemon  148.7MBStep 1/7 : FROM openjdk:8u212-b04-jre-slim ---> 7c6b62cf60eeStep 2/7 : VOLUME /tmp ---> Using cache ---> 52011f49ddefStep 3/7 : ADD target/*.jar app.jar ---> c67160dd2a23Step 4/7 : RUN sh -c 'touch /app.jar' ---> Running in 474900d843a2Removing intermediate container 474900d843a2 ---> 3ce9a8bb2600Step 5/7 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai" ---> Running in f48620b1ad36Removing intermediate container f48620b1ad36 ---> 0478f8f14e5bStep 6/7 : ENV APP_OPTS="" ---> Running in 98485fb15fc8Removing intermediate container 98485fb15fc8 ---> 0b567c848027Step 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ] ---> Running in e32242fc6efeRemoving intermediate container e32242fc6efe ---> 7b223b23ebfdSuccessfully built 7b223b23ebfdSuccessfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2real    0m3.190suser    0m0.039ssys 0m0.403s/<code>

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

(2)、推送

<code>$ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]d66a2fec30b5: Pushed f4da2c7581aa: Pushed 9544e87fb8dc: Layer already exists feb5d0e1e192: Layer already exists 8fd22162ddab: Layer already exists 6270adb5794c: Layer already exists real    0m20.816suser    0m0.024ssys 0m0.081s/<code>

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

(3)、拉取

<code>$ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.20.0.2: Pulling from mydlq/springboot743f2d6c1f65: Already exists b83e581826a6: Already exists 04305660f45e: Already exists bbe7020b5561: Already exists d7e364f0d94a: Pull complete 8d688ada35b1: Pull complete Digest: sha256:7c13c40fa92ec2fdc3a8dfdd3232be1be9c1a1a99bf123743ff2a43907ee03dcStatus: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2real    0m23.214suser    0m0.053ssys 0m0.097s/<code>

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

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

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

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

1、Docker 分层缓存简介

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

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

Dockerfile 的每一行命令都创建新的一层,包含了这一行命令执行前后文件系统的变化。为了优化这个过程,Docker 使用了一种缓存机制:只要这一行命令不变,那么结果和上一次是一样的,直接使用上一次的结果即可。扩展:终于有人把 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 层琢磨。

SpringBoot 项目构建 Docker 镜像调优实践

三、是什么导致 Jar 包臃肿

从上面实验中了解到之所以每次编译、推送、拉取过程中较为缓慢,原因就是庞大的镜像文件。了解到 Docker 缓存概念后就就产生一种想法,如果不经常改变的文件缓存起来,将常改动的文件不进行缓存。扩展:SpringBoot缓存应用实践

由于 SpringBoot 项目是经常变换的,那么应该怎么利用缓存机制来实现呢?如果强行利用缓存那么每次打的镜像不都是缓存中的旧的程序内容吗。

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

1、解压 Jar 包查看内容

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

<code>$ tree -L 3 --si --du.├── [ 74M]  BOOT-INF │   ├── [2.1k]  classes│   └── [ 74M]  lib├── [ 649]  META-INF│   ├── [ 552]  MANIFEST.MF│   └── [  59]  maven└── [  67]  org    └── [  38]  springframework/<code>

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

SpringBoot 项目构建 Docker 镜像调优实践

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

SpringBoot 项目构建 Docker 镜像调优实践

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 包分离开来。

SpringBoot 项目构建 Docker 镜像调优实践

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

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

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

<code><build>    <plugins>                <plugin>            <groupid>org.apache.maven.plugins/<groupid>            <artifactid>maven-jar-plugin/<artifactid>            <configuration>                <archive>                    <manifest>                        <addclasspath>true/<addclasspath>                        <classpathprefix>lib//<classpathprefix>                    /<manifest>                /<archive>            /<configuration>        /<plugin>                <plugin>            <groupid>org.springframework.boot/<groupid>            <artifactid>spring-boot-maven-plugin/<artifactid>            <configuration>                 <includes>                     <include>                         <groupid>nothing/<groupid>                         <artifactid>nothing/<artifactid>                     /<include>                 /<includes>            /<configuration>        /<plugin>                <plugin>            <groupid>org.apache.maven.plugins/<groupid>            <artifactid>maven-dependency-plugin/<artifactid>            <executions>                <execution>                    copy-dependencies                    <phase>prepare-package/<phase>                    <goals>                        <goal>copy-dependencies/<goal>                    /<goals>                    <configuration>                        <outputdirectory>${project.build.directory}/lib/<outputdirectory>                    /<configuration>                /<execution>            /<executions>        /<plugin>    /<plugins>/<build>/<code>

执行 Maven 命令打包 Jar

<code>$ mvn clean install/<code>

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

SpringBoot 项目构建 Docker 镜像调优实践

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

<code>$ java -jar springboot-helloworld-0.0.1.jar/<code>

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

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

SpringBoot 项目构建 Docker 镜像调优实践

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

1、修改 Dockerfile 文件

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

<code>FROM openjdk:8u212-b04-jre-slimVOLUME /tmpCOPY target/lib/ ./lib/ADD target/*.jar app.jarRUN sh -c 'touch /app.jar'ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"ENV APP_OPTS=""ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]/<code>

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

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

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

(1)、编译

<code>$ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1 .Sending build context to Docker daemon  223.2MBStep 1/8 : FROM openjdk:8u212-b04-jre-slim8u212-b04-jre-slim: Pulling from library/openjdk743f2d6c1f65: Already exists b83e581826a6: Pull complete 04305660f45e: Pull complete bbe7020b5561: Pull complete Digest: sha256:a5bcd678408a5fe94d13e486d500983ee6fa594940cbbe137670fbb90030456cStatus: Downloaded newer image for openjdk:8u212-b04-jre-slim ---> 7c6b62cf60eeStep 2/8 : VOLUME /tmp ---> Running in 529369acab24Removing intermediate container 529369acab24 ---> ad689d937118Step 3/8 : COPY target/lib/ ./lib/ ---> 029a64c15853Step 4/8 : ADD target/*.jar app.jar ---> 6265a83a1b90Step 5/8 : RUN sh -c 'touch /app.jar' ---> Running in 839032a58e6bRemoving intermediate container 839032a58e6b ---> 5d877dc35b2bStep 6/8 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai" ---> Running in 4043994c5fedRemoving intermediate container 4043994c5fed ---> 7cf32beb571fStep 7/8 : ENV APP_OPTS="" ---> Running in b7dcfa10458aRemoving intermediate container b7dcfa10458a ---> b6b332bcf0e6Step 8/8 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ] ---> Running in 539093461b59Removing intermediate container 539093461b59 ---> d4c095c4ffecSuccessfully built d4c095c4ffecSuccessfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1real    0m22.983suser    0m0.051ssys 0m0.540s/<code>

(2)、推送

<code>$ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]c16749205e05: Pushed 7fef1a146748: Pushed a3bae74bbdf2: Pushed 9544e87fb8dc: Pushedfeb5d0e1e192: Pushed8fd22162ddab: Pushed6270adb5794c: Pushed 0.0.1: digest: sha256:e2f4db740880dbe5338b823112ba9467fedf8b27cd75572611d0d3837c80f157 size: 1789real    0m30.335suser    0m0.052ssys 0m0.059s/<code>

(3)、拉取

<code>$ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.10.0.1: Pulling from mydlq/springboot743f2d6c1f65: Already exists b83e581826a6: Pull complete 04305660f45e: Pull complete bbe7020b5561: Pull complete de6c4f15d75b: Pull complete 7066947b7d89: Pull complete e0742de67c75: Pull complete Digest: sha256:e2f4db740880dbe5338b823112ba9467fedf8b27cd75572611d0d3837c80f157Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1real    0m36.585suser    0m0.024ssys 0m0.092s/<code>

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

(1)、编译

<code>$ time docker build -t registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2 .Sending build context to Docker daemon  223.2MBStep 1/8 : FROM openjdk:8u212-b04-jre-slim ---> 7c6b62cf60eeStep 2/8 : VOLUME /tmp ---> Using cache ---> ad689d937118Step 3/8 : COPY target/lib/ ./lib/ ---> Using cache ---> 029a64c15853Step 4/8 : ADD target/*.jar app.jar ---> 563773953844Step 5/8 : RUN sh -c 'touch /app.jar' ---> Running in 3b9df57802bdRemoving intermediate container 3b9df57802bd ---> 706a0d47317fStep 6/8 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai" ---> Running in defda61452bfRemoving intermediate container defda61452bf ---> 742c7c926374Step 7/8 : ENV APP_OPTS="" ---> Running in f09b81d054ddRemoving intermediate container f09b81d054dd ---> 929ed5f8b12aStep 8/8 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ] ---> Running in 5dc66a8fc1e6Removing intermediate container 5dc66a8fc1e6 ---> c4942b10992cSuccessfully built c4942b10992cSuccessfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2real    0m2.524suser    0m0.051ssys 0m0.493s/<code> 

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

(2)、推送

<code>$ time docker push registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]d719b9540809: Pushed d45bf4c5fb92: Pushed a3bae74bbdf2: Layer already exists 9544e87fb8dc: Layer already exists feb5d0e1e192: Layer already exists 8fd22162ddab: Layer already exists 6270adb5794c: Layer already exists 0.0.2: digest: sha256:b46d81b153ec64321caaae7ab28da0e362ed7d720a7f0775ea8d1f7bef310d00 size: 1789real    0m0.168suser    0m0.016ssys 0m0.032s/<code>

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

(3)、拉取

<code>$ time docker pull registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.20.0.2: Pulling from mydlq/springboot743f2d6c1f65: Already exists b83e581826a6: Already exists 04305660f45e: Already exists bbe7020b5561: Already exists de6c4f15d75b: Already exists 1c77cc70cc41: Pull complete aa5b8cbca568: Pull complete Digest: sha256:b46d81b153ec64321caaae7ab28da0e362ed7d720a7f0775ea8d1f7bef310d00Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2real    0m1.947suser    0m0.017ssys 0m0.042s/<code>

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

五、最后总结

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

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

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

END


分享到:


相關文章: