SpringBoot 項目構建 Docker 鏡像調優實踐

2021-12-31 Java知音

點擊上方「Java知音」,選擇「置頂公眾號」

技術文章第一時間送達!

作者:超級小豆丁

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

PS:已經在生產實踐中驗證,解決在生產環境下,網速帶寬小,每次推拉鏡像影響線上服務問題,按本文方式構建鏡像,除了第一次拉取、推送、構建鏡像慢,第二、三…次都是幾百K大小傳輸,速度非常快,構建、打包、推送幾秒內完成。

前言:

以前的 SpringCloud 微服務時代以 「Jar包」 為服務的基礎,每個服務都打成 Jar 供服務間相互關聯與調用。而 現在隨著 Kubernetes 流行,已經變遷到一個鏡像一個服務,依靠 Kubernetes 對鏡像的統一編排進行對服務進行統一管理。在對 Kubernetes 微服務實踐過程中,接觸最多的肯定莫過於 Docker 鏡像。由於本人使用的程式語言是 Java,所以對 Java SpringBoot 項目接觸比較多,所以比較關心如何更好的通過 Dockerfile 編譯 Docker 的鏡像。

Kubernetes 微服務簡單說就是一群鏡像間的排列組合與相互間調的關係,故而如何編譯鏡像會使服務性能更優,使鏡像構建、推送、拉取速度更快,使其佔用網絡資源更少這裡優化,更易使用成為了一個重中之重的事情,也是一個非常值得琢磨的問題。

這裡我將對 SpringBoot 項目打包 Docker 鏡像如何寫 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 路徑對應。

FROM openjdk:8u212-b04-jre-slim
VOLUME /tmp
ADD target/*.jar app.jar
RUN 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" ]

3、構建 Docker 鏡像

通過 Docker build 命令構建 Docker 鏡像,觀察編譯的時間。

由於後續需要將鏡像推送到 Aliyun Docker 倉庫,所以鏡像前綴用了 Aliyun。

time:此參數會顯示執行過程經過的時間

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

構建過程

Sending build context to Docker daemon  148.7MB
Step 1/7 : FROM openjdk:8u212-b04-jre-slim
8u212-b04-jre-slim: Pulling from library/openjdk
743f2d6c1f65: Already exists 
b83e581826a6: Pull complete 
04305660f45e: Pull complete 
bbe7020b5561: Pull complete 
Digest: sha256:a5bcd678408a5fe94d13e486d500983ee6fa594940cbbe137670fbb90030456c
Status: Downloaded newer image for openjdk:8u212-b04-jre-slim
 ---> 7c6b62cf60ee
Step 2/7 : VOLUME /tmp
 ---> Running in 13a67ab65d2b
Removing intermediate container 13a67ab65d2b
 ---> 52011f49ddef
Step 3/7 : ADD target/*.jar app.jar
 ---> 26aa41a404fd
Step 4/7 : RUN sh -c 'touch /app.jar'
 ---> Running in 722e7e44e04d
Removing intermediate container 722e7e44e04d
 ---> 7baedb10ec62
Step 5/7 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
 ---> Running in 2681d0c5edac
Removing intermediate container 2681d0c5edac
 ---> 5ef4a794b992
Step 6/7 : ENV APP_OPTS=""
 ---> Running in 5c8924a2a49d
Removing intermediate container 5c8924a2a49d
 ---> fba87c19053a
Step 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]
 ---> Running in c4cf97009b3c
Removing intermediate container c4cf97009b3c
 ---> d5f30cdfeb81
Successfully built d5f30cdfeb81
Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1

real    0m13.778s
user    0m0.078s
sys 0m0.153s

看到這次編譯在 14s 內完成。

4、將鏡像推送到鏡像倉庫

將鏡像推送到 Aliyun 倉庫,然後查看並記錄推送時間

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

執行過程

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: 1583

real    0m24.335s
user    0m0.052s
sys 0m0.059s

看到這次在 25s 內完成。擴展:面試官:你簡歷中寫用過docker,能說說容器和鏡像的區別嗎?

5、拉取鏡像

這裡切換到另一臺伺服器上進行鏡像拉取操作,觀察鏡像拉取時間。

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

拉取過程

0.0.1: Pulling from mydlq/springboot
743f2d6c1f65: Already exists 
b83e581826a6: Pull complete 
04305660f45e: Pull complete 
bbe7020b5561: Pull complete 
4847672cbfa5: Pull complete 
b60476972fc4: Pull complete 
Digest: sha256:dc60d304383b1441941ca4e9abc08db775d7be57ccb7c534c929b34ff064a62f
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1

real    0m27.528s
user    0m0.033s
sys 0m0.192s

看到這次拉取總共用時 28s 內完成。

6、修改 Java 源碼重新打包 Jar 後再次嘗試

這裡將源碼的 JAVA 文件內容修改,然後重新打 Jar 包,這樣再次嘗試編譯、推送、拉取過程,由於 Docker 在執行構建時會採用分層緩存,所以這是一個執行較快過程。

(1)、編譯

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

Sending build context to Docker daemon  148.7MB
Step 1/7 : FROM openjdk:8u212-b04-jre-slim
 ---> 7c6b62cf60ee
Step 2/7 : VOLUME /tmp
 ---> Using cache
 ---> 52011f49ddef
Step 3/7 : ADD target/*.jar app.jar
 ---> c67160dd2a23
Step 4/7 : RUN sh -c 'touch /app.jar'
 ---> Running in 474900d843a2
Removing intermediate container 474900d843a2
 ---> 3ce9a8bb2600
Step 5/7 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
 ---> Running in f48620b1ad36
Removing intermediate container f48620b1ad36
 ---> 0478f8f14e5b
Step 6/7 : ENV APP_OPTS=""
 ---> Running in 98485fb15fc8
Removing intermediate container 98485fb15fc8
 ---> 0b567c848027
Step 7/7 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]
 ---> Running in e32242fc6efe
Removing intermediate container e32242fc6efe
 ---> 7b223b23ebfd
Successfully built 7b223b23ebfd
Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2

real    0m3.190s
user    0m0.039s
sys 0m0.403s

可以看到在編譯鏡像過程中,前1、2層用的緩存,所以速度非常快。總編譯過程耗時 4s 內完成。

(2)、推送

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

The 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.816s
user    0m0.024s
sys 0m0.081s

可以看到只推送了前兩層,其它四次由於遠程倉庫未變化,所以沒有推送。整個推送過程耗時 21s 內完成。

(3)、拉取

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

0.0.2: Pulling from mydlq/springboot
743f2d6c1f65: Already exists 
b83e581826a6: Already exists 
04305660f45e: Already exists 
bbe7020b5561: Already exists 
d7e364f0d94a: Pull complete 
8d688ada35b1: Pull complete 
Digest: sha256:7c13c40fa92ec2fdc3a8dfdd3232be1be9c1a1a99bf123743ff2a43907ee03dc
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2

real    0m23.214s
user    0m0.053s
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 使用了一種緩存機制:只要這一行命令不變,那麼結果和上一次是一樣的,直接使用上一次的結果即可。擴展:終於有人把 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緩存應用實踐

由於 SpringBoot 項目是經常變換的,那麼應該怎麼利用緩存機制來實現呢?如果強行利用緩存那麼每次打的鏡像不都是緩存中的舊的程序內容嗎。

所以就考慮一下應用 Jar 包裡面都包含了什麼文件, Java 的哪些文件是經常變動的,哪些不經常變動,對此,下面將針對 SpringBoot 打的應用 Jar 包進行分析。

1、解壓 Jar 包查看內容

顯示解壓後的列表,查看各個文件夾大小

$ 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

可以看到最大的文件就是 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 中

<build>
    <plugins>
        <!--設置應用 Main 參數啟動依賴查找的地址指向外部 lib 文件夾-->
        <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>
        <!--設置 SpringBoot 打包插件不包含任何 Jar 依賴包-->
        <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>
        <!--設置將 lib 拷貝到應用 Jar 外面-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

執行 Maven 命令打包 Jar

$ mvn clean install

當 Maven 命令執行完成後,查看 target 目錄如下圖:

然後測試下這個 Jar 文件是否能正常運行

$ 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 一致。

FROM openjdk:8u212-b04-jre-slim
VOLUME /tmp
COPY target/lib/ ./lib/
ADD target/*.jar app.jar
RUN 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" ]

這裡新增了一層指令,作用為將 lib 文件夾複製到鏡像之中,由於 Docker 緩存機制原因,這層一定要在複製應用 Jar 之前,這樣改造後每次只要 lib/ 文件夾裡面的依賴 Jar 不變,就不會新創建層,而是復用緩存。

2、改造 Docker 鏡像後的首次編譯、推送、拉取

在執行編譯、推送、拉取之前,先將伺服器上次鏡像相關的所有資源都清除掉,然後再執行。

(1)、編譯

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

Sending build context to Docker daemon  223.2MB
Step 1/8 : FROM openjdk:8u212-b04-jre-slim
8u212-b04-jre-slim: Pulling from library/openjdk
743f2d6c1f65: Already exists 
b83e581826a6: Pull complete 
04305660f45e: Pull complete 
bbe7020b5561: Pull complete 
Digest: sha256:a5bcd678408a5fe94d13e486d500983ee6fa594940cbbe137670fbb90030456c
Status: Downloaded newer image for openjdk:8u212-b04-jre-slim
 ---> 7c6b62cf60ee
Step 2/8 : VOLUME /tmp
 ---> Running in 529369acab24
Removing intermediate container 529369acab24
 ---> ad689d937118
Step 3/8 : COPY target/lib/ ./lib/
 ---> 029a64c15853
Step 4/8 : ADD target/*.jar app.jar
 ---> 6265a83a1b90
Step 5/8 : RUN sh -c 'touch /app.jar'
 ---> Running in 839032a58e6b
Removing intermediate container 839032a58e6b
 ---> 5d877dc35b2b
Step 6/8 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
 ---> Running in 4043994c5fed
Removing intermediate container 4043994c5fed
 ---> 7cf32beb571f
Step 7/8 : ENV APP_OPTS=""
 ---> Running in b7dcfa10458a
Removing intermediate container b7dcfa10458a
 ---> b6b332bcf0e6
Step 8/8 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]
 ---> Running in 539093461b59
Removing intermediate container 539093461b59
 ---> d4c095c4ffec
Successfully built d4c095c4ffec
Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1

real    0m22.983s
user    0m0.051s
sys 0m0.540s

(2)、推送

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

The push refers to repository [registry.cn-beijing.aliyuncs.com/mydlq/springboot]
c16749205e05: Pushed 
7fef1a146748: Pushed 
a3bae74bbdf2: Pushed 
9544e87fb8dc: Pushed
feb5d0e1e192: Pushed
8fd22162ddab: Pushed
6270adb5794c: Pushed 
0.0.1: digest: sha256:e2f4db740880dbe5338b823112ba9467fedf8b27cd75572611d0d3837c80f157 size: 1789

real    0m30.335s
user    0m0.052s
sys 0m0.059s

(3)、拉取

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

0.0.1: Pulling from mydlq/springboot
743f2d6c1f65: Already exists 
b83e581826a6: Pull complete 
04305660f45e: Pull complete 
bbe7020b5561: Pull complete 
de6c4f15d75b: Pull complete 
7066947b7d89: Pull complete 
e0742de67c75: Pull complete 
Digest: sha256:e2f4db740880dbe5338b823112ba9467fedf8b27cd75572611d0d3837c80f157
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.1

real    0m36.585s
user    0m0.024s
sys 0m0.092s

3、再次編譯、推送、拉取

(1)、編譯

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

Sending build context to Docker daemon  223.2MB
Step 1/8 : FROM openjdk:8u212-b04-jre-slim
 ---> 7c6b62cf60ee
Step 2/8 : VOLUME /tmp
 ---> Using cache
 ---> ad689d937118
Step 3/8 : COPY target/lib/ ./lib/
 ---> Using cache
 ---> 029a64c15853
Step 4/8 : ADD target/*.jar app.jar
 ---> 563773953844
Step 5/8 : RUN sh -c 'touch /app.jar'
 ---> Running in 3b9df57802bd
Removing intermediate container 3b9df57802bd
 ---> 706a0d47317f
Step 6/8 : ENV JAVA_OPTS="-Duser.timezone=Asia/Shanghai"
 ---> Running in defda61452bf
Removing intermediate container defda61452bf
 ---> 742c7c926374
Step 7/8 : ENV APP_OPTS=""
 ---> Running in f09b81d054dd
Removing intermediate container f09b81d054dd
 ---> 929ed5f8b12a
Step 8/8 : ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar $APP_OPTS" ]
 ---> Running in 5dc66a8fc1e6
Removing intermediate container 5dc66a8fc1e6
 ---> c4942b10992c
Successfully built c4942b10992c
Successfully tagged registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2

real    0m2.524s
user    0m0.051s
sys 0m0.493s

可以看到,這次在第 3 層直接用的緩存,整個編譯過程才花了 2.5 秒時間

(2)、推送

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

The 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: 1789

real    0m0.168s
user    0m0.016s
sys 0m0.032s

可以看到在 0.2s 內就完成了鏡像推送

(3)、拉取

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

0.0.2: Pulling from mydlq/springboot
743f2d6c1f65: Already exists 
b83e581826a6: Already exists 
04305660f45e: Already exists 
bbe7020b5561: Already exists 
de6c4f15d75b: Already exists 
1c77cc70cc41: Pull complete 
aa5b8cbca568: Pull complete 
Digest: sha256:b46d81b153ec64321caaae7ab28da0e362ed7d720a7f0775ea8d1f7bef310d00
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/mydlq/springboot:0.0.2

real    0m1.947s
user    0m0.017s
sys 0m0.042s

可以看到在 2s 內就完成了鏡像拉取

五、最後總結

由於網絡波動和系統變化,所以時間只能當做參考,不過執行編譯、推送、拉取過程的確快了不少,大部分用文件都進行了緩存,只有幾百 KB 的流量交互自然速度比幾十 MB 甚至幾百 MB 速度要快很多。

最後說明一下,這種做法只是提供了一種參考,現在的微服務服務 Docker 鏡像化以來,維護的是整個鏡像而不是一個服務程序,所以關心的是 Docker 鏡像能否能正常運行,怎麼構建鏡像會使構建的鏡像更好用。

在生產環境下由於版本變化較慢,不會動不動就更新,所以在生產環境下暫時最好還是按部就班,應用原來 SpringBoot 鏡像編譯方式以確保安裝(除非已大量實例驗證該構建方法)。

END

Java面試題專欄

我知道你 「在看

相關焦點

  • 使用Gradle構建SpringBoot項目Docker鏡像
    使用Gradle快速構建SpringBoot項目Docker鏡像,將鏡像推送到阿里雲遠程鏡像倉庫。
  • 【超全教程】SpringBoot 2.3.x 分層構建 Docker 鏡像實踐
    Docker 鏡像$ time docker build -t hub.mydlq.club/library/springboot-layer:0.0.2 .2拉取鏡像:## 清理全部鏡像$ docker rm --force $(docker images -qa)## 拉取鏡像 springboot-layer:0.0.1$ time docker push hub.mydlq.club/library/springboot-normal:0.0.1
  • Spring Boot 分層構建 Docker 鏡像實戰
    # 使用兩種 Dockerfile 構建項目鏡像1、在伺服器一構建普通 Docker 鏡像$ mvn clean install$ time docker build -t hub.mydlq.club/library/springboot-normal:0.0.1 .
  • 基於Docker的SpringBoot構建實踐
    然後利用Maven插件 dockerfile-maven-plugin 配置鏡像信息及鏡像構建。POM相關配置如下所示...com.aaron</groupId><artifactId>SpringBootDocker</artifactId><packaging>jar</packaging><version>1.1</version><description>基於Spring Boot的Docker構建實踐
  • SpringBoot第二十四篇: springboot整合docker
    這篇文篇介紹,怎麼為 springboot程序構建一個docker鏡像。docker 是一個開源的應用容器引擎,基於 Go 語言 並遵從Apache2.0協議開源。/urandom -jar /app.jar" ]我們通過maven 構建docker鏡像。
  • 不要手動部署SpringBoot項目了,使用Docker真香!
    /urandom","-jar","/springboot-docker.jar"]FROM:指定存在的鏡像,java:8是我剛剛拉取的鏡像,運行的基礎。VOLUME:指向的一個臨時文件,用於存儲tomcat工作。ADD:複製文件並且重命名文件。ENTRYPOINT:初始化配置或者自定義配置。
  • 還在手動啟動SpringBoot項目?Docker部署不香嗎?
    /urandom","-jar","/springboot-docker.jar"]FROM:指定存在的鏡像,java:8是我剛剛拉取的鏡像,運行的基礎。VOLUME:指向的一個臨時文件,用於存儲tomcat工作。ADD:複製文件並且重命名文件。ENTRYPOINT:初始化配置或者自定義配置。
  • Springboot項目使用docker部署
    、創建連結ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose4、查看版本5、查找tomcat鏡像到此docker環境安裝配置完成,接下來將項目部署到docker中。
  • 使用 Docker 部署 Spring Boot 項目
    首先構建一個簡單的 Spring Boot 項目,然後給項目添加 Docker 支持,最後對項目進行部署。Spring Boot 項目添加 Docker 支持在 pom.xml-properties中添加 Docker 鏡像名稱<properties><docker.image.prefix>springboot</docker.image.prefix></properties
  • 一個網站的微服務架構實戰docker和 docker-compose
    目的是實現整個項目產品的輕量級和靈活性,在將各個模塊的鏡像都上傳公共鏡像倉庫後,任何人都可以通過 「docker-compose up -d」 一行命令,將整個項目的前端、後端、資料庫以及文件伺服器等,運行在自己的伺服器上。
  • Maven構建Docker鏡像
    SpringBoot應構建Docker鏡像 本文主要介紹使用Maven將SpringBoot應用打包成Docker鏡像,並上傳到私有鏡像倉庫Docker Registry.鏡像倉庫Docker Registry的搭建 1.Pull Registry鏡像docker pull registry:22.鏡像倉庫的容器實例docker run -d -p 5000:5000 --restart=always --name registry
  • 初級-手動部署springboot工程到Docker
    #配置yum為阿里雲鏡像yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo#安裝docker-cednf install https://mirrors.aliyun.com/docker-ce/linux
  • 一分鐘玩轉Docker容器化部署
    Docker鏡像按照前面Docker的介紹,如果要讓Spring Boot程序運行在Docker容器上,首先需要構建Docker鏡像,而構建的過程則需要通過Dockerfile文件來描述。例如在項目src/main/docker目錄創建Dockerfile文件,代碼如下:FROM java:8VOLUME /tmpRUN mkdir /appADD springboot-1.0-SNAPSHOT.jar /app/springboot.jarADD runboot.sh /app/RUN bash -c 'touch
  • 基於Dockerfile構建容器鏡像的最佳實踐
    任何鏡像都需要有一個基礎鏡像,那麼問題來了,就好比是先有雞還是先有蛋的問題,基礎鏡像的「祖宗」是什麼呢?能不能在構建時不以任何鏡像為基礎呢?答案是肯定的,可以選用scratch,具體就不展開了,可以參考:baseimages[2],使用scratch鏡像的例子pausebusybox:對比scratch,多了常用的linux工具等3.3.2.2 多階段構建多階段構建非常適用於編譯性語言,簡單來說就是允許一個Dockerfile中出現多條FROM指令,只有最後一條FROM指令中指定的基礎鏡像作為本次構建鏡像的基礎鏡像
  • Dockerfile構建beego鏡像
    Window、Linux、Mac下Beego環境的快速安裝流程:go get github.com/astaxie/beegogo get github.com/beego/beeDocker中也可以根據以上流程快速安裝Beego鏡像,通過Dockerfile編寫構建文件。
  • 基於k8s、docker、jenkins、springboot構建docker服務.
    本文介紹基於Jenkins + github  + k8s + springboot構建docker
  • 多平臺Docker鏡像構建教程
    那麼,你該如何為這些平臺構建鏡像?最明顯的方法是在目標平臺上構建鏡像。這適用於很多情況。但是如果你的目標是 s390x,我希望你有可以使用的 IBM 大型機。更常見的平臺,比如樹莓派、物聯網設備通常電量有限,速度慢或無法構建鏡像。我們該怎麼做?有兩個選項:1. 目標平臺仿真,2. 交叉編譯。有趣的是,我發現有種方法可以將這兩個選項結合的效果最好。
  • 構建安全可靠、最小化的 Docker 鏡像
    本文將針對該問題,通過原理加實踐的方式,從頭到腳幫你擼一遍。文章比較長,主要通過五個部分對容器鏡像進行講解。分別是:鏡像的構建 講解了鏡像的手動構建與自動構建過程。容器鏡像的加固 容器鏡像加固的具體方式。容器鏡像的審查 高質量的項目中容器鏡像也需要向代碼一樣進行審查。讀者可以根據各自情況選擇性閱讀。原文發布在我的個人站點: GitDiG.com. 原文連接:構建安全可靠、最小化的 Docker 鏡像.1.
  • 還在手動部署springboot項目?不妨試試它,讓你部署項目飛起來!
    Ubuntu安裝dockerCentOS安裝docker通過腳本安裝拉取java環境創建springboot項目打包springboot到dockerdocker查看容器的日誌查看log4j2輸出問文件日誌docker介紹Docker 是一個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到一個可移植的鏡像中
  • 理解Docker的多階段鏡像構建
    對於已經接納和使用Docker技術在日常開發工作中的開發者而言,構建Docker鏡像已經是家常便飯。但這是否意味著Docker的image構建機制已經相對完美了呢?不是的,Docker官方依舊在持續優化鏡像構建機制。這不,從今年發布的Docker 17.05版本起,Docker開始支持容器鏡像的多階段構建(multi-stage build)了。什麼是鏡像多階段構建呢?