溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Docker鏡像構(gòu)建的優(yōu)化總結(jié)

發(fā)布時(shí)間:2020-06-28 03:53:45 來(lái)源:網(wǎng)絡(luò) 閱讀:4647 作者:aaron428 欄目:大數(shù)據(jù)

Docker鏡像構(gòu)建的優(yōu)化總結(jié)

隨著我們對(duì)docker鏡像的持續(xù)使用,在此過(guò)程中如果不加以注意并且優(yōu)化,鏡像的體積會(huì)越來(lái)越多。很多時(shí)候我們?cè)谑褂胐ocker部署應(yīng)用時(shí),會(huì)發(fā)現(xiàn)鏡像的體積至少有1G以上。鏡像體積的增大,不單單會(huì)增加磁盤(pán)資源與網(wǎng)絡(luò)資源的開(kāi)銷(xiāo),也會(huì)影響應(yīng)用的部署效率,使得應(yīng)用的部署時(shí)間會(huì)越來(lái)越長(zhǎng)。因此我們需要減少部署鏡像的體積以加快部署效率,降低資源的開(kāi)銷(xiāo)。而對(duì)于鏡像的優(yōu)化,可以通過(guò)對(duì)dockerfile的優(yōu)化來(lái)實(shí)現(xiàn)。

一、鏡像最小化

1、選擇最精簡(jiǎn)的基礎(chǔ)鏡像

選擇體積最小的基礎(chǔ)鏡像可有效降低鏡像體積。如:alpine、busybox等

2、清理鏡像構(gòu)建的中間產(chǎn)物。

構(gòu)建鏡像的過(guò)程中,當(dāng)dockerfile的指令執(zhí)行完成后,刪除鏡像不需要用的的文件。如使用yum安裝組件,最后可使用yum clean all鏡像清理不需要的文件或者使用系統(tǒng)rm命令刪除不需要的源文件等。

3、減少鏡像的層數(shù)

鏡像是一個(gè)分層存儲(chǔ)的文件,并且鏡像對(duì)層數(shù)也是有一定數(shù)量的限制,當(dāng)前鏡像的層數(shù)最高是127層,如果不多加注意,將會(huì)導(dǎo)致鏡像越來(lái)越臃腫。在使用dockerfile構(gòu)建鏡像時(shí),dockerfile中的每一條指令都會(huì)生成一個(gè)層,因此可以通過(guò)合并dockerfile中可合并的指令,減少最終生成鏡像的層數(shù)。例如:在dockerfile中使用RUN執(zhí)行shell命令是,可以用"&&"將多條命令連接起來(lái)。

二、構(gòu)建速度最快化

1、充分利用鏡像構(gòu)建緩存

我們可以利用構(gòu)建的緩存來(lái)加快鏡像構(gòu)建速度,Docker構(gòu)建默認(rèn)會(huì)開(kāi)啟緩存,緩存生效有三個(gè)關(guān)鍵點(diǎn),鏡像父層沒(méi)有發(fā)生變化,構(gòu)建指令不變,添加文件校驗(yàn)和一致。只要一個(gè)構(gòu)建指令滿足這三個(gè)條件,這一層鏡像構(gòu)建就不會(huì)再執(zhí)行,它會(huì)直接利用之前構(gòu)建的結(jié)果。某一層的鏡像緩存失效之后,它之后的鏡像層緩存都會(huì)失效。我們應(yīng)該把變化最少的部分放在Dockerfile的前面,這樣可以充分利用鏡像緩存。dockerfile中有可能導(dǎo)致緩存失效的命令WORKDIR、CMD、ENV、ADD等,像這些命令最好放到dockerfile底部,以便在構(gòu)建鏡像過(guò)程中最大限度使用緩存。

2、刪除構(gòu)建目錄中(默認(rèn):Dockerfile所在目錄)不需要用的的文件。

編寫(xiě).dockerignore文件過(guò)濾構(gòu)建過(guò)程中不必要的文件或者創(chuàng)建單獨(dú)的目錄,并且目錄中僅存在鏡像構(gòu)建過(guò)程中需要使用的文件。
Docker 在運(yùn)行時(shí)分為 Docker 引擎(也就是服務(wù)端守護(hù)進(jìn)程)和客戶端工具。Docker 的引擎提供了一組 REST API,被稱(chēng)為 Docker Remote API,而如 docker 命令這樣的客戶端工具,則是通過(guò)這組 API 與 Docker 引擎交互,從而完成各種功能。因此,雖然表面上我們好像是在本機(jī)執(zhí)行各種 docker 功能,但實(shí)際上,一切都是使用的遠(yuǎn)程調(diào)用形式在服務(wù)端(Docker 引擎)完成。docker build 命令構(gòu)建鏡像,其實(shí)并非在本地構(gòu)建,而是在服務(wù)端,也就是 Docker 引擎中構(gòu)建的。
構(gòu)建鏡像時(shí),Docker需要先準(zhǔn)備context ,將所有需要的文件收集到進(jìn)程中。默認(rèn)的context包含Dockerfile目錄中的所有文件。如果目錄中的存在大量不相關(guān)的文件,不僅會(huì)導(dǎo)致構(gòu)建緩慢,而且還會(huì)導(dǎo)致鏡像體積增大。
.dockerignore示例如下:
在一個(gè)git項(xiàng)目中,我們并不需要.git目錄等內(nèi)容??梢栽?dockerignore文件中加入以下內(nèi)容:
.git/

.dockerignore 的作用和語(yǔ)法類(lèi)似于 .gitignore,可以忽略一些不需要的文件,這樣可以有效加快鏡像構(gòu)建時(shí)間,同時(shí)減少Docker鏡像的大小。

3、注意優(yōu)化網(wǎng)絡(luò)請(qǐng)求

我們使用一些鏡像源或者在dockerfile中使用互聯(lián)網(wǎng)上的url時(shí),去用一些網(wǎng)絡(luò)比較好的開(kāi)源站點(diǎn),這樣可以節(jié)約時(shí)間、減少失敗率

三、dockerfile指令優(yōu)化

1、COPY指令和ADD指令的區(qū)別

COPY 復(fù)制文件
格式:
COPY <源路徑>... <目標(biāo)路徑>
COPY ["<源路徑1>",... "<目標(biāo)路徑>"]
COPY 指令將從構(gòu)建上下文目錄中 <源路徑> 的文件/目錄復(fù)制到新的一層的鏡像內(nèi)的 <目標(biāo)路徑> 位置。比如:
COPY package.json /usr/src/app/
<源路徑> 可以是多個(gè),甚至可以是通配符,其通配符規(guī)則要滿足 Go 的 filepath.Match 規(guī)則,如:
COPY hom* /mydir/
COPY hom?.txt /mydir/
<目標(biāo)路徑> 可以是容器內(nèi)的絕對(duì)路徑,也可以是相對(duì)于工作目錄的相對(duì)路徑(工作目錄可以用 WORKDIR 指令來(lái)指定)。目標(biāo)路徑不需要事先創(chuàng)建,如果目錄不存在會(huì)在復(fù)制文件前先行創(chuàng)建缺失目錄。
此外,還需要注意一點(diǎn),使用 COPY 指令,源文件的各種元數(shù)據(jù)都會(huì)保留。比如讀、寫(xiě)、執(zhí)行權(quán)限、文件變更時(shí)間等。這個(gè)特性對(duì)于鏡像定制很有用。特別是構(gòu)建相關(guān)文件都在使用 Git 進(jìn)行管理的時(shí)候。

ADD 更高級(jí)的復(fù)制文件

ADD 指令和 COPY 的格式和性質(zhì)基本一致。但是在 COPY 基礎(chǔ)上增加了一些功能。

比如 <源路徑> 可以是一個(gè) URL,這種情況下,Docker 引擎會(huì)試圖去下載這個(gè)鏈接的文件放到 <目標(biāo)路徑> 去。下載后的文件權(quán)限自動(dòng)設(shè)置為 600,如果這并不是想要的權(quán)限,那么還需要增加額外的一層 RUN進(jìn)行權(quán)限調(diào)整,另外,如果下載的是個(gè)壓縮包,需要解壓縮,也一樣還需要額外的一層 RUN 指令進(jìn)行解壓縮。所以不如直接使用 RUN 指令,然后使用 wget 或者 curl 工具下載,處理權(quán)限、解壓縮、然后清理無(wú)用文件更合理。因此,這個(gè)功能其實(shí)并不實(shí)用,而且不推薦使用。

如果 <源路徑> 為一個(gè) tar 壓縮文件的話,壓縮格式為 gzip, bzip2 以及 xz 的情況下,ADD 指令將會(huì)自動(dòng)解壓縮這個(gè)壓縮文件到 <目標(biāo)路徑> 去。

在某些情況下,這個(gè)自動(dòng)解壓縮的功能非常有用,比如官方鏡像 ubuntu 中:

FROM scratch
ADD ubuntu-xenial-core-cloudimg-amd64-root.tar.gz /
...
但在某些情況下,如果我們真的是希望復(fù)制個(gè)壓縮文件進(jìn)去,而不解壓縮,這時(shí)就不可以使用 ADD 命令了。

在 Docker 官方的最佳實(shí)踐文檔中要求,盡可能的使用 COPY,因?yàn)?COPY 的語(yǔ)義很明確,就是復(fù)制文件而已,而 ADD 則包含了更復(fù)雜的功能,其行為也不一定很清晰。最適合使用 ADD 的場(chǎng)合,就是所提及的需要自動(dòng)解壓縮的場(chǎng)合。

另外需要注意的是,ADD 指令會(huì)令鏡像構(gòu)建緩存失效,從而可能會(huì)令鏡像構(gòu)建變得比較緩慢。

因此在 COPY 和 ADD 指令中選擇的時(shí)候,可以遵循這樣的原則,所有的文件復(fù)制均使用 COPY 指令,僅在需要自動(dòng)解壓縮的場(chǎng)合使用 ADD。

2、CMD 與 ENTRYPOINT的區(qū)別

CMD
CMD 指令設(shè)置鏡像中的默認(rèn)啟動(dòng)命令和參數(shù). 容器啟動(dòng)之后, 如果沒(méi)有加入任何啟動(dòng)命令(也就是在鏡像參數(shù)之后沒(méi)有添加任何內(nèi)容) 則默認(rèn)執(zhí)行鏡像中 CMD 設(shè)置的默認(rèn)的啟動(dòng)命令

設(shè)置啟動(dòng)命令時(shí), 應(yīng)該盡量使用 JSON 格式 CMD ["command", "arg1", "arg2"]
例如 nginx 的啟動(dòng)方式: CMD ["nginx", "-D"]

如果開(kāi)發(fā)者和使用者都不是很熟悉 CMD 和 ENTRYPOINT 的工作原理的情況下, 盡量避免這兩個(gè)指令配合使用
例如 Django 的啟動(dòng)方式: CMD ["python", "manage.py", "runserver", "0.0.0.0:8989"]

相反, 如果開(kāi)發(fā)者和使用者都很熟悉 CMD 和 ENTRYPOINT 的工作原理, 推薦 CMD 作為 ENTRYPOINT 的參數(shù)來(lái)配套使用

ENTRYPOINT
當(dāng)需要把容器當(dāng)做一個(gè)命令行工具使用時(shí), 推薦通過(guò) ENTRYPOINT 指令設(shè)置鏡像的入口程序

當(dāng)啟動(dòng)主程序之前還需要執(zhí)行大量的前置操作時(shí), 可以將 ENTRYPOINT 的入口指令設(shè)置為一個(gè)腳本 start.sh

當(dāng) dockerfile 中指定了 ENTRYPOINT 的時(shí)候, docker run 如果在鏡像之后添加的指令, 那么這些指令將被當(dāng)做 ENTRYPOINT 的參數(shù)執(zhí)行
如果 dockerfile 中同時(shí)有 CMD 和 ENTRYPOINT 指令, 當(dāng) CMD 指令可執(zhí)行時(shí), 它將在 ENTRYPOINT 之前運(yùn)行; 如果 CMD 不是可執(zhí)行的命令, 則將作為 ENTRYPOINT 的命令參數(shù)追加

3、WORKDIR

盡量使用絕對(duì)路徑
切換目錄的時(shí)候盡量使用 WORKDIR, 而不是使用 RUN cd /data

4、USER

如果容器中的應(yīng)用程序運(yùn)行時(shí)不需要特殊的權(quán)限, 可以通過(guò) USER 指令把應(yīng)用程序的所有者設(shè)置為非 root 用戶. 如果該用戶不存在, 首先需要使用 RUN 命令在鏡像中創(chuàng)建用戶.

如果在每次編譯鏡像時(shí), 對(duì)用戶的 UID/GID 有要求需要保持一致, 應(yīng)該在新建用戶和組的時(shí)候指定 UID和 GID
在鏡像中避免使用sudo 命令. 應(yīng)為該命令使用的 TTY 不確定, 對(duì)接收信號(hào)量也會(huì)造成影響. 如果確實(shí)需要使用 sudo 功能, 則可是使用 gosu 命令替代
可以用 root 用戶初始化一個(gè) daemon, 然后用非 root 用戶啟動(dòng)這個(gè) daemon
為了減少鏡像體積, 應(yīng)該避免不必要的用戶切換

5、EXPOSE

EXPOSE 用來(lái)聲明未來(lái)容器內(nèi)需要監(jiān)聽(tīng)的端口, 在 bridge 模式下, 這些容器內(nèi)部的端口會(huì)映射到宿主機(jī)的端口上, 建議在容器內(nèi)部不要更改應(yīng)用原生的端口號(hào)

EXPOSE 中只能指定未來(lái)容器內(nèi)部需要暴露的端口, 不能指定未來(lái)容器外部與內(nèi)部端口之間的映射關(guān)系, 比如設(shè)置 EXPOSE 80:80 是沒(méi)有任何意義的
向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI