Docker構(gòu)建鏡像的三大優(yōu)化方法指南
一、cmd與entrypoint
基本概念:
CMD指令: 指定容器啟動時默認執(zhí)行的命令。它不會在構(gòu)建時執(zhí)行,只是在鏡像中記錄了"當有人運行這個容器時,默認應(yīng)該執(zhí)行什么"。
ENTRYPOINT指令: 類似CMD默認執(zhí)行一個指令,但它是將配置容器作為一個可執(zhí)行程序來運行。它讓容器表現(xiàn)得像一個獨立的二進制文件。
特性:
共同特性:
- 覆蓋特性: 如果在
Dockerfile中寫了很多個這樣的指令,那么后一個的會覆蓋前面的。
區(qū)別:
cmd:docker run時指定命令會把cmd命令覆蓋。entrypoint:docker run 時添加的指令,會默認作為ENTRYPOINT的參數(shù);若需覆蓋ENTRYPOINT,需通過--entrypoint參數(shù)指定
指令的兩種格式:
exec模式:把命令放在Json數(shù)組shell模式:直接把命令放在后面- 效果上的差異:
exec模式:指令程序被直接啟動,pid為1,可直接與程序進行交互。shell模式:不是直接啟動指令程序,pid不是1,而是作為sh的子程序運行。需要通過sh與程序進行交互。
示例:
CMD nginx -g "daemon off"(shell模式)
執(zhí)行:/bin/sh -c "nginx -g "daemon off"
CMD ["nginx","-g","daemon off"](exec模式)
執(zhí)行:nginx -g "daemon off"
使用推薦:
使用exec模式編輯,CMD和ENTRYPOINT配合使用:entrypoint負責可執(zhí)行程序,cmd負責參數(shù)傳入。
覆蓋測試
- 創(chuàng)建Dockerfile
- 填寫多條CMD語句
- 創(chuàng)建鏡像
- 啟動容器
- Dockerfile文件中CMD改為ENTRYPOINT
Dockerfile文件:
FROM busybox CMD echo "hello world" CMD echo "hello docker"
構(gòu)建鏡像:docker build -t cmd:v0.1 .
運行鏡像:
CMD測試:

ENTRYPOINT測試:

可使用–entrypoint選項指定指令執(zhí)行:

shell與exec
exec模式:

shell模式:

cmd與entrypoint組合

二、優(yōu)雅構(gòu)建鏡像(過濾文件)
很多時候我們會將當前目錄(構(gòu)建上下文)中的所有文件拷貝給docker容器。但很多時候,我們的項目中包含一些不需要被打進鏡像的文件,這些文件不僅會增加鏡像大小,延長構(gòu)建時間,還可能帶來安全風險。這時候.dockerignore就該上場了。
什么是 .dockerignore
.dockerignore 文件是 Docker 構(gòu)建過程中的一個重要工具,它的作用類似于 .gitignore,用于指定在構(gòu)建 Docker 鏡像時應(yīng)該忽略哪些文件和目錄,防止它們被復制到鏡像中。
為什么要使用 .dockerignore
主要好處:
- 減小鏡像大小 - 避免將不必要的文件打包進鏡像
- 提高構(gòu)建速度 - 減少
COPY和ADD指令處理的數(shù)據(jù)量 - 增強安全性 - 防止敏感文件(如密鑰、配置文件)意外進入鏡像
- 避免緩存失效 - 不重要的文件變化不會導致構(gòu)建緩存失效
如何使用 .dockerignore
基本語法:
*匹配任意數(shù)量字符?匹配單個字符**匹配任意層級的目錄!表示例外(不忽略)
示例:
# * - 匹配任意數(shù)量字符(除了路徑分隔符) *.log # 忽略所有 .log 文件 src/*.js # 忽略 src 目錄下的所有 .js 文件 #------------------------------------------------------- # ? - 匹配單個字符 file?.txt # 忽略 file1.txt, file2.txt 等 #------------------------------------------------------- # ** - 匹配任意層級的目錄 **/test # 忽略所有 test 目錄 src/**/*.js # 忽略 src 下任意層級的 .js 文件 #------------------------------------------------------- # ! 表示例外(不忽略) !README.md #保留README.md 文件 *.md #忽略其他 .md 文件 #-------------------------------------------------------
文件位置:.dockerignore 應(yīng)該放在 Dockerfile 同一目錄下。
實戰(zhàn)示例:

三、多階段構(gòu)建
Docker 多階段構(gòu)建允許你在一個 Dockerfile 中定義多個“構(gòu)建階段”(圖中的 Stage1, Stage2, …),每個階段都是一個獨立的鏡像構(gòu)建過程,并且你可以有選擇地將前一個階段的產(chǎn)物復制到后一個階段,最終只產(chǎn)出最后一個階段的鏡像。
這解決了傳統(tǒng)單階段構(gòu)建模式(圖中的“單階段”)所帶來的問題。

1.單階段構(gòu)建
- 模式:在一個 Docker 鏡像中完成所有事情(編譯、測試、打包、運行)。
- 問題:層次多,體積大、部署時間長、安全性差。
2.手動拆分
- 模式:開發(fā)人員意識到單階段的問題,于是手動拆分流程。
- 問題:流程復雜、不標準。
3.多階段構(gòu)建
模式:用一個 Dockerfile 定義多個階段,自動完成“按需構(gòu)建和復制”。
如何工作:
- stage1(編譯階段):使用一個包含
java/maven或gcc的較大鏡像,任務(wù)是將源代碼編譯成可執(zhí)行的二進制文件(如 JAR 包或可執(zhí)行文件)。這個階段可以包含多個步驟,比如用junit進行測試。 - stage2(運行階段):使用一個非常精簡的鏡像(比如只包含
java運行時或glibc)。然后,使用COPY --from指令,只從stage1里把編譯好的最終產(chǎn)物(JAR 包)復制過來。 - 最終鏡像:只包含
stage2的內(nèi)容,也就是一個最精簡的運行環(huán)境和你的應(yīng)用程序。stage1中的所有構(gòu)建工具(Maven, GCC)都被拋棄了,不會出現(xiàn)在最終鏡像里。
4.測試
測試文件:
#include <stdio.h>
int main()
{
printf("hello docker");
return 0;
}
單階段構(gòu)建:
FROM ubuntu:22.04
# 設(shè)置國內(nèi)源(阿里云Ubuntu鏡像)
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 更新軟件包列表并安裝gcc
RUN apt-get update && \
apt-get install -y gcc && \
gcc -v
# 設(shè)置工作目錄
WORKDIR /src
# 拷貝源文件
COPY demo.c .
# 編譯源文件并清理
RUN gcc demo.c -o demo && \
rm -f demo.c && \
apt-get remove -y gcc && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 運行可執(zhí)行文件
CMD ["/src/demo"]
多階構(gòu)建:
FROM ubuntu:22.04 as buildstage
# 設(shè)置國內(nèi)源(阿里云Ubuntu鏡像)
RUN sed -i 's/archive.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list && \
sed -i 's/security.ubuntu.com/mirrors.aliyun.com/g' /etc/apt/sources.list
# 更新軟件包列表并安裝gcc
RUN apt-get update && \
apt-get install -y gcc && \
gcc -v
# 設(shè)置工作目錄
WORKDIR /src
# 拷貝源文件
COPY demo.c .
# 編譯源文件并清理
RUN gcc demo.c -o demo && \
rm -f demo.c && \
apt-get remove -y gcc && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
FROM busybox
COPY --from=buildstage /src/demo /src/
CMD ["/src/demo"]

四、合理使用緩存
Docker 層緩存原理
Docker 鏡像由只讀層組成,每一層對應(yīng) Dockerfile 里的一條指令(RUN、COPY、ADD 等)。構(gòu)建時:從第一條指令開始,Docker 檢查是否已有緩存層(基于指令字符串和文件內(nèi)容);如果緩存存在,就復用該層,繼續(xù)下一條;一旦某條指令的緩存沒命中(指令內(nèi)容變化,或 COPY/ADD 的文件內(nèi)容變化),后續(xù)所有指令都會重新執(zhí)行,不再使用緩存。

所以為了提高構(gòu)建效率,通常會把變更頻繁的指令或文件放在后面執(zhí)行。示例:代碼常常會被頻繁修改,所以我們把它放在后面執(zhí)行,把編譯軟件的安裝放在前面就能提高二次構(gòu)建的效率。

注意:兩種方式初次構(gòu)建的時間是一樣的,主要影響的是二次構(gòu)建。
測試方式:
- copy在前run安裝在后,完成初次構(gòu)建
- 更改源代碼,然后再進行二次構(gòu)建并記錄時間
- run安裝前copy放在后,完成初次構(gòu)建
- 更改源代碼,然后再進行二次構(gòu)建并記錄時間
- 對比兩次構(gòu)建的時間
以上就是Docker構(gòu)建鏡像的三大優(yōu)化方法指南的詳細內(nèi)容,更多關(guān)于Docker鏡像構(gòu)建的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
docker network如何創(chuàng)建橋接網(wǎng)絡(luò)
這篇文章主要介紹了docker network如何創(chuàng)建橋接網(wǎng)絡(luò)問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
使用rpm安裝指定版本docker(1.12.6)的詳細步驟
為了防止安裝高版本的docker引發(fā)的錯誤,需要安裝1.12.6版本的docker,下面小編給大家?guī)砹耸褂胷pm安裝指定版本的docker(1.12.6)的步驟,感興趣的朋友一起看看吧2021-08-08
Windows10系統(tǒng)下docker安裝指南以及踩坑解決
這篇文章主要給大家介紹了關(guān)于Windows10系統(tǒng)下docker安裝指南以及踩坑解決的相關(guān)資料,相信大家都知道Docker有很多種安裝的選擇,其中支持最好的是Ubuntu系統(tǒng),而且docker如果想在windows上運行必須借助docker-machine,需要的朋友可以參考下2023-08-08
教你如何利用docker-maven-plugin自動化部署
本文通過兩個例子給大家講解如何利用docker-maven-plugin自動化部署,給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-09-09
docker搭建redis三主三從集群的實現(xiàn)步驟
本文主要介紹了docker搭建redis三主三從集群,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-08-08

