dockerfile构建镜像的命令_编写Dockerfile的最佳实践
雖然 Dockerfile 簡(jiǎn)化了鏡像構(gòu)建的過(guò)程,并且把這個(gè)過(guò)程可以進(jìn)行版本控制,但是很多人構(gòu)建鏡像的時(shí)候,都有一種沖動(dòng)——把可能用到的東西都打包到鏡像中。這種不正當(dāng)?shù)?Dockerfile 使用也會(huì)導(dǎo)致很多問(wèn)題:
- docker 鏡像太大。如果你經(jīng)常使用鏡像或者構(gòu)建鏡像,一定會(huì)遇到那種很大的鏡像,甚至有些能達(dá)到 2G 以上
- docker 鏡像的構(gòu)建時(shí)間過(guò)長(zhǎng)。每個(gè) build 都會(huì)耗費(fèi)很長(zhǎng)時(shí)間,對(duì)于需要經(jīng)常構(gòu)建鏡像(比如單元測(cè)試)的地方這可能是個(gè)大問(wèn)題
- 重復(fù)勞動(dòng)。多次鏡像構(gòu)建之間大部分內(nèi)容都是完全一樣而且重復(fù)的,但是每次都要做一遍,浪費(fèi)時(shí)間和資源
這篇文章會(huì)講述一些做法,希望能解決這些問(wèn)題。
作者:cizixs日期:2017-03-28
原文鏈接:https://cizixs.com/2017/03/28/dockerfile-best-practice/
希望讀者能夠?qū)?docker 鏡像有一定的了解,閱讀這篇文章至少需要一下前提知識(shí):
- 了解 docker 的基礎(chǔ)概念,運(yùn)行過(guò)容器
- 熟悉 docker 鏡像的基礎(chǔ)知識(shí),知道鏡像的分層結(jié)構(gòu)
- 最好是負(fù)責(zé)過(guò)某個(gè) docker 鏡像的構(gòu)建(使用 docker build 命令創(chuàng)建過(guò)自己的鏡像)
Dockerfile 和鏡像構(gòu)建
Dockerfile 是由一個(gè)個(gè)指令組成的,每個(gè)指令都對(duì)應(yīng)著最終鏡像的一層。每行的第一個(gè)單詞就是命令,后面所有的字符串是這個(gè)命令的參數(shù),關(guān)于 Dockerfile 支持的命令以及它們的用法,可以參考官方文檔,這里不再贅述。
當(dāng)運(yùn)行 docker build 命令的時(shí)候,整個(gè)的構(gòu)建過(guò)程是這樣的:
編寫(xiě) Dockerfile 的一些最佳實(shí)踐
1. 使用統(tǒng)一的 base 鏡像
有些文章講優(yōu)化鏡像會(huì)提倡使用盡量小的基礎(chǔ)鏡像,比如 busybox 或者 alpine 等。我更推薦使用統(tǒng)一的大家比較熟悉的基礎(chǔ)鏡像,比如 ubuntu,centos 等,因?yàn)榛A(chǔ)鏡像只需要下載一次可以共享,并不會(huì)造成太多的存儲(chǔ)空間浪費(fèi)。它的好處是這些鏡像的生態(tài)比較完整,方便我們安裝軟件,除了問(wèn)題進(jìn)行調(diào)試。
2. 動(dòng)靜分離
經(jīng)常變化的內(nèi)容和基本不會(huì)變化的內(nèi)容要分開(kāi),把不怎么變化的內(nèi)容放在下層,創(chuàng)建出來(lái)不同基礎(chǔ)鏡像供上層使用。比如可以創(chuàng)建各種語(yǔ)言的基礎(chǔ)鏡像,python2.7、python3.4、go1.7、java7等等,這些鏡像包含了最基本的語(yǔ)言庫(kù),每個(gè)組可以在上面繼續(xù)構(gòu)建應(yīng)用級(jí)別的鏡像。
3. 最小原則:只安裝必需的東西
很多人構(gòu)建鏡像的時(shí)候,都有一種沖動(dòng)——把可能用到的東西都打包到鏡像中。要遏制這種想法,鏡像中應(yīng)該只包含必需的東西,任何可以有也可以沒(méi)有的東西都不要放到里面。因?yàn)殓R像的擴(kuò)展很容易,而且運(yùn)行容器的時(shí)候也很方便地對(duì)其進(jìn)行修改。這樣可以保證鏡像盡可能小,構(gòu)建的時(shí)候盡可能快,也保證未來(lái)的更快傳輸、更省網(wǎng)絡(luò)資源。
4. 一個(gè)原則:每個(gè)鏡像只有一個(gè)功能
不要在容器里運(yùn)行多個(gè)不同功能的進(jìn)程,每個(gè)鏡像中只安裝一個(gè)應(yīng)用的軟件包和文件,需要交互的程序通過(guò) pod(kubernetes 提供的特性) 或者容器之間的網(wǎng)絡(luò)進(jìn)行交流。這樣可以保證模塊化,不同的應(yīng)用可以分開(kāi)維護(hù)和升級(jí),也能減小單個(gè)鏡像的大小。
5. 使用更少的層
雖然看起來(lái)把不同的命令盡量分開(kāi)來(lái),寫(xiě)在多個(gè)命令中容易閱讀和理解。但是這樣會(huì)導(dǎo)致出現(xiàn)太多的鏡像層,而不好管理和分析鏡像,而且鏡像的層是有限的。盡量把相關(guān)的內(nèi)容放到同一個(gè)層,使用換行符進(jìn)行分割,這樣可以進(jìn)一步減小鏡像大小,并且方便查看鏡像歷史。
RUN apt-get update&& apt-get install -y --no-install-recommends bzr cvs git mercurial subversion && apt get clean6. 減少每層的內(nèi)容
盡管只安裝必須的內(nèi)容,在這個(gè)過(guò)程中也可能會(huì)產(chǎn)生額外的內(nèi)容或者臨時(shí)文件,我們要盡量讓每層安裝的東西保持最小。
- 比如使用 --no-install-recommends 參數(shù)告訴 apt-get 不要安裝推薦的軟件包
- 安裝完軟件包,清楚 /var/lib/apt/list/ 緩存
- 刪除中間文件:比如下載的壓縮包
- 刪除臨時(shí)文件:如果命令產(chǎn)生了臨時(shí)文件,也要及時(shí)刪除
7. 不要在 Dockerfile 中單獨(dú)修改文件的權(quán)限
因?yàn)?docker 鏡像是分層的,任何修改都會(huì)新增一個(gè)層,修改文件或者目錄權(quán)限也是如此。如果有一個(gè)命令單獨(dú)修改大文件或者目錄的權(quán)限,會(huì)把這些文件復(fù)制一份,這樣很容易導(dǎo)致鏡像很大。
解決方案也很簡(jiǎn)單,要么在添加到 Dockerfile 之前就把文件的權(quán)限和用戶(hù)設(shè)置好,要么在容器啟動(dòng)腳本(entrypoint)做這些修改,或者拷貝文件和修改權(quán)限放在一起做(這樣最終也只是增加一層)。
8. 利用 cache 來(lái)加快構(gòu)建速度
如果 Docker 發(fā)現(xiàn)某個(gè)層已經(jīng)存在了,它會(huì)直接使用已經(jīng)存在的層,而不會(huì)重新運(yùn)行一次。如果你連續(xù)運(yùn)行 docker build 多次,會(huì)發(fā)現(xiàn)第二次運(yùn)行很快就結(jié)束了。
不過(guò)從 1.10 版本開(kāi)始,Content Addressable Storage 的引入導(dǎo)致緩存功能的實(shí)效,目前引入了 --cache-from 參數(shù)可以手動(dòng)指定一個(gè)鏡像來(lái)使用它的緩存。
9. 版本控制和自動(dòng)構(gòu)建
最好把 Dockerfile 和對(duì)應(yīng)的應(yīng)用代碼一起放到版本控制中,然后能夠自動(dòng)構(gòu)建鏡像。這樣的好處是可以追蹤各個(gè)版本鏡像的內(nèi)容,方便了解不同鏡像有什么區(qū)別,對(duì)于調(diào)試和回滾都有好處。
另外,如果運(yùn)行鏡像的參數(shù)或者環(huán)境變量很多,也要有對(duì)應(yīng)的文檔給予說(shuō)明,并且文檔要隨著 Dockerfile 變化而更新,這樣任何人都能參考著文檔很容易地使用鏡像,而不是下載了鏡像不知道怎么用。
參考資料
Redirecting…
Refactoring a Dockerfile for Image Size
How to Not Be the Engineer Running 3.5GB Docker Images
總結(jié)
以上是生活随笔為你收集整理的dockerfile构建镜像的命令_编写Dockerfile的最佳实践的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 附近有招火补轮胎翻新轮胎的吗?
- 下一篇: 图像重建算法_降噪重建技术路在何方?