目錄
- 前言
- 壓縮鏡像大小
- 利用緩存加速打包速度
- Multi-stage Build
- Java打包測試
前言
當下主流的業務架構大部分會選擇用容器進行部署,并結合一些容器編排技術k8s技術。由于公司業務調整,jenkins打包的工作交付到我這邊來負責。
結果組長上來就給我一個當頭一棒,打包速度太慢,盡量優化下。我尋思過年也沒忘記給拜年啊,不行把送出去的特產要回來吧,沒啥用啊,凈給整這一出。
說歸說鬧歸鬧,別拿績效開玩笑,畢竟這年終還沒發呢,該忍還得忍。君讓臣死,臣不得不死,硬著頭皮上吧
壓縮鏡像大小
優化第一步,瘦身,docker images查看了下基礎服務的鏡像大小,好家伙沒有小于300M的,一個普通的小服務都要300多,顯然在鏡像體積上可以做做文章。
在Docker官方的建議中有一個點,使用更小的基礎鏡像。而在小的基礎鏡像中全網的一致答案都是alpine了。
alpine是一個非常特別的Linux版本,大小才5M左右,最早適用于嵌入式系統,但隨著容器的流行,這個才5M大小的Linux在Docker中流行起來了,因為太小了,非常節省空間。
這里就對比下同樣屬于Linux鏡像centeros與alpine的大小
REPOSITORY TAG IMAGE ID CREATED SIZE alpine 3.16.2 9c6f07244728 7 days ago 5.54MB centeros latest df5de72bdb3b 2 weeks ago 77.8MB
解決完基礎鏡像再來研究下第三方包是不是有可優化的點,仔細分析Dockerfile發現在構建過程中去拉代碼打包的,那么構建過程中就會存在大量運行時不需要的包。這部分清掉基本上就可以瘦身成功了。
構建過程中,通過apk安裝軟件包時,可以指定虛擬包.build-deps
,這樣git之類的工具歸屬到虛擬包下,由于僅是構建階段用到的命令,如執行npm install
或pip install
,當把項目構建完以后,通過apk del .build-deps
清理掉所有臨時命令即可。
這樣就可以保證構建出的鏡像最小了。
利用緩存加速打包速度
docker本身是有緩存機制的,也就是每次build的時候會檢查Dockerfile是否發生了變更,這里要注意是Dockerfile發生了變更,并不是代碼發生變更。
得到這個結論的時候其實我是很迷惑的,照這么來說的話,Dockefile基本不會變,每次走緩存為什么jenkins打包速度這么慢呢。
后來在build命令里發現了端倪,有人在docker build時加了–no-cache參數,因為代碼是在鏡像構建時拉取的,每次走了緩存那么代碼就不會拉取了,每次都會走緩存。所以為了避免代碼不對運維在命令里加了–no-cache
那怎么辦呢,因為Dockefile執行從上到下依次執行。把代碼放到最低端,通過定義隨機數或時間戳的方式使拉代碼的命令緩存失效而不影響上面的第三方包的安裝。
豈不美哉。
Multi-stage Build
Docker 提供了 Multi-stage Build(多階段構建),可以實現鏡像瘦身。
我們將鏡像構建分成兩個階段:
在 ”build“ 階段依然采用 JDK 作為基礎鏡像,并利用 Maven 進行應用構建; 在最終發布的鏡像中,我們會采用 JRE 版本作為基礎鏡像,并從”build“ 鏡像中直接拷貝出生成的 jar 文件。這意味著在最終發布的鏡像中,只包含運行時所需必要內容,不包含任何編譯時依賴,大大減少了鏡像體積。
FROM adoptopenjdk/openjdk8 AS build RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/' /etc/apt/sources.list RUN apt-get update RUN apt-get install -y \ git \ maven WORKDIR /tmp RUN git clone https://github.com/spring-projects/spring-petclinic.git WORKDIR /tmp/spring-petclinic RUN mvn install FROM adoptopenjdk/openjdk8:jre8u222-b10-alpine-jre COPY --from=build /tmp/spring-petclinic/target/spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar CMD ["java","-jar","spring-petclinic-2.1.0.BUILD-SNAPSHOT.jar"]
Java打包測試
springboot背景下,在默認的maven打包插件加入分層打包配置
????<build> ????????<plugins> ????????????<plugin> ????????????????<groupId>org.springframework.boot</groupId> ????????????????<artifactId>spring-boot-maven-plugin</artifactId> ????????????????<configuration> ????????????????????<layers> ????????????????????????<enabled>true</enabled> ????????????????????</layers> ????????????????</configuration> ????????????</plugin> ????????</plugins> ????</build>
再次進行打包分析操作mvn clean package,現在我們可以用下面命令來看分層打包編譯的jar包結構 java -Djarmode=layertools -jar target/dockers-demo-0.0.1-SNAPSHOT.jar list
可以看到layertools識別出jar包內將依賴打包到不同文件夾中,接下來我們改造下原有的dockerfile。
如果不分層打包的話,一次全量包會特別大。如果只更改部分代碼的話。
FROM?openjdk:8?as?builder RUN?mvn?clean?package?-DskipTests #?聲明端口并沒有真正運行在這個端口 EXPOSE?8080 ADD?./target/*.jar?./app.jar RUN?java?-Djarmode=layertools?-jar?app.jar?extract FROM?openjdk:8-jre MAINTAINER?[email protected] WORKDIR?application #?復制第三方依賴、SpringBoot內部配置、快照依賴 COPY?--from=builder?application/dependencies/?./ COPY?--from=builder?application/spring-boot-loader/?./ COPY?--from=builder?application/snapshot-dependencies/?./ COPY?--from=builder?application/application/?./ EXPOSE?8080 ENTRYPOINT?["java",?"org.springframework.boot.loader.JarLauncher"]
依靠docker的分層特征,分次加入文件即可達到分層加速打包的效果