本文介紹一種docker image瘦身的技巧,它基于Chiselled Ubuntu來實現(xiàn),希望能幫助大家將自己的docker image體積縮小約50%(或者至少上百MB)。
Chiselled Ubuntu 容器是一個生產(chǎn)就緒的、安全的超小型容器鏡像,側(cè)重于效率和安全性。這些容器鏡像允許用戶構(gòu)建的鏡像僅包含其應(yīng)用程序及運行時依賴,而不包含不必要的操作系統(tǒng)級包、實用程序或庫。另外,Canonical 還承諾提供安全維護與支持。Chiselled Ubuntu 容器也是旨在縮小容器基礎(chǔ)鏡像。它也帶來了同樣的好處,比如最小化依賴,減少膨脹和資源使用,加快啟動速度,并通過減少鏡像中不需要的文件來增強安全性。
以Java為例介紹Docker image瘦身效果
我在以前通過Docker 鏡像瘦身技巧介紹了一些常見后端語言編寫的程序的整體鏡像瘦身技術(shù)點,并通過Docker 鏡像 OpenJDK 基礎(chǔ)鏡像選型詳細(xì)列舉了Java語言具體的基礎(chǔ)鏡像選擇的最佳實踐,但是一般來講Java程序相關(guān)的Docker image體積至少都是200MB。那么我們是否可以進(jìn)一步的降低image體積呢?我們可以嘗試下Chiselled Ubuntu 容器鏡像,驗證是否如ubuntu的宣稱的這樣。
我們可以使用任意的java程序進(jìn)行測試。我這里使用spring boot web最小項目制作的jar包,將這個jar文件放置到image里面制作成一個可運行的image。其dockerfile為:
# 使用ubuntu/jre,它已經(jīng)是chiselled版本: https://hub.docker.com/r/ubuntu/jre FROM ubuntu/jre:17-22.04_39 # 指定環(huán)境變量 ENV APP_NAME=demo ENV PORT=8080 # 標(biāo)簽 LABEL "AUTHOR"="ThinkTik" LABEL "MAIL_ADDRESS"="thinktik@outlook.com" LABEL "DOMAIN_NAME"="omoz.cc" LABEL "SERVICE_PATH"="${APP_NAME}" # 切換工作目錄 WORKDIR /home/app # 將當(dāng)前項目的可執(zhí)行文件添加到工作目錄:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy ADD ./build/libs/${APP_NAME}-*.jar ./app.jar # This image does not include bash nor a package manager nor the OpenJDK. Its purpose is to serve as a runtime, final-stage base image for compatible Java applications. # 因為chiselled版本的jre沒有bash、包管理器、OpenJDK以及其他的Linux工具組件。所以沒有我們常見的mkdir、curl、useradd等幾乎全部的Linux命令!也沒有/tmp目錄! # 所以當(dāng)java程序需要讀寫/tmp文件夾時,我們只能提前通過其他方式繞過去 ADD ./README.md /tmp/README.md # 暴露的端口號 EXPOSE ${PORT} # 使用該鏡像來啟動容器,指定啟動命令 # 因為ubuntu/jre base image里面已經(jīng)自帶了ENTRYPOINT(目的是指定java命令的具體路徑),這時我們只需要通過CMD來補充啟動參數(shù)即可:https://docs.docker.com/engine/reference/builder/#dockerfile-reference CMD ["-jar","./app.jar"]
作為對比我們使用amazon corretto jdk作為base image的話,做好Docker 鏡像瘦身技巧和Docker 鏡像 OpenJDK 基礎(chǔ)鏡像選型后,其dockerfile為:
# https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ # https://docs.aws.amazon.com/AmazonECS/latest/bestpracticesguide/application.html # 使用JDK21 FROM amazoncorretto:21-al2023-headless # 指定環(huán)境變量 ENV USER=omoz ENV HOME_PATH=/home/${USER} ENV LOG_PATH=${HOME_PATH}/logs ENV APP_NAME=demo ENV PORT=8080 # 標(biāo)簽 LABEL "AUTHOR"="ThinkTik" LABEL "MAIL_ADDRESS"="thinktik@outlook.com" LABEL "DOMAIN_NAME"="omoz.cc" LABEL "SERVICE_PATH"="${APP_NAME}" # 創(chuàng)建omoz-developers用戶組,創(chuàng)建用戶omoz(自動創(chuàng)建home目錄)并加入omoz-developers用戶組 RUN dnf update -y && dnf install shadow-utils procps-ng -y RUN groupadd -r ${USER}-developers && useradd -r -m -g ${USER}-developers ${USER} # 切換用戶(以非root用戶啟動服務(wù)) USER ${USER} # 指定工作目錄 WORKDIR ${HOME_PATH} # 將當(dāng)前項目的可執(zhí)行文件添加到工作目錄 # https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy ADD ./build/libs/${APP_NAME}-*.jar ${HOME_PATH}/app.jar # 周期性健康檢查 # https://docs.docker.com/engine/reference/builder/#healthcheck HEALTHCHECK --start-period=180s --interval=60s --timeout=8s --retries=3 CMD curl -s -f -k https://localhost:${PORT}/ping || exit 1 # 暴露的端口號 EXPOSE ${PORT} # 使用該鏡像來啟動容器,指定啟動命令 ENTRYPOINT ["java","-jar","app.jar"]
我分別使用上面2種dockerfile制作了2個版本的docker image并都做了最大程度的體積優(yōu)化,最后的結(jié)果是兩者對比之下,就我的簡單測試而言Chiselled Ubuntu 容器作為base image可以把java docker image體積縮小為原先的25%左右或者至少100MB,達(dá)到了官方所宣傳的效果?。?!
總結(jié)
Chiselled Ubuntu 容器的適用場景和建議
目前直接支持的解釋型語言還不是太多,主要是python,java,dotnet-runtime 你可以自己為一些不直接支持的解釋型語言制作Chiselled版image,但是技術(shù)要求比較高,這里不詳細(xì)展開 編譯型語言比如go,rust可以直接使用debian base image 和ubuntu base image由于Chiselled Ubuntu刪除了除運行所必須的組件外的其他非必需組件,所以達(dá)到了更好的瘦身效果,但是這也對一些我們在容器運行中的debug、linux命令行的使用有明顯的影響。
建議搭配分布式的日志服務(wù)來接收程序產(chǎn)生的日志而不是使用本地卷。如前面講到的,有些非必要的目錄可能都沒有,比如/tmp文件夾 建議在image發(fā)布到正式環(huán)境前做好詳細(xì)的功能測試和驗證(因為一旦需要debug,在bash都沒有的情況下,很難docker exec進(jìn)入到容器)總之,相比alpine linux,Chiselled Ubuntu是標(biāo)準(zhǔn)的Linux,兼容性更好、適用范圍更大并且體積有時還更低,因為大多數(shù)Linux發(fā)行版都使用GNU版本的標(biāo)準(zhǔn)C庫(glibc),但Alpine Linux使用的是musl,那些二進(jìn)制安裝包是針對glibc編譯的;相比傳統(tǒng)的其他方案,Chiselled Ubuntu的體積明顯有優(yōu)勢。