編寫Dockerfile的優(yōu)秀實(shí)踐

雖然 Dockerfile 簡化了鏡像構(gòu)建的過程氛赐,并且把這個(gè)過程可以進(jìn)行版本控制漠吻,但是很多人構(gòu)建鏡像的時(shí)候擅耽,都有一種沖動——把可能用到的東西都打包到鏡像中傻盟。這種不正當(dāng)?shù)? Dockerfile 使用也會導(dǎo)致很多問題:

1.? docker 鏡像太大速蕊。如果你經(jīng)常使用鏡像或者構(gòu)建鏡像,一定會遇到那種很大的鏡像娘赴,甚至有些能達(dá)到 2G 以上

2.? docker 鏡像的構(gòu)建時(shí)間過長规哲。每個(gè) build 都會耗費(fèi)很長時(shí)間,對于需要經(jīng)常構(gòu)建鏡像(比如單元測試)的地方這可能是個(gè)大問題

3.? 重復(fù)勞動诽表。多次鏡像構(gòu)建之間大部分內(nèi)容都是完全一樣而且重復(fù)的唉锌,但是每次都要做一遍,浪費(fèi)時(shí)間和資源

希望讀者能夠?qū)?docker 鏡像有一定的了解竿奏,閱讀這篇文章至少需要一下前提知識:

1.? 了解 docker 的基礎(chǔ)概念袄简,運(yùn)行過容器

2.? 熟悉 docker 鏡像的基礎(chǔ)知識,知道鏡像的分層結(jié)構(gòu)

3.? 最好是負(fù)責(zé)過某個(gè) docker 鏡像的構(gòu)建(使用 docker build 命令創(chuàng)建過自己的鏡像)

Dockerfile 和鏡像構(gòu)建

Dockerfile 是由一個(gè)個(gè)指令組成的泛啸,每個(gè)指令都對應(yīng)著最終鏡像的一層绿语。每行的第一個(gè)單詞就是命令,后面所有的字符串是這個(gè)命令的參數(shù)候址,關(guān)于? Dockerfile 支持的命令以及它們的用法吕粹,可以參考官方文檔,這里不再贅述岗仑。

?當(dāng)運(yùn)行 docker build 命令的時(shí)候匹耕,整個(gè)的構(gòu)建過程是這樣的:

1.? 讀取 Dockerfile 文件發(fā)送到 docker daemon

2.? 讀取當(dāng)前目錄的所有文件(context),發(fā)送到 docker daemon

3.? 對 Dockerfile 進(jìn)行解析荠雕,處理成命令加上對應(yīng)參數(shù)的結(jié)構(gòu)

4.? 按照順序循環(huán)遍歷所有的命令稳其,對每個(gè)命令調(diào)用對應(yīng)的處理函數(shù)進(jìn)行處理

5.? 每個(gè)命令(除了 FROM)都會在一個(gè)容器執(zhí)行,執(zhí)行的結(jié)果會生成一個(gè)新的鏡像

6.? 為最后生成的鏡像打上標(biāo)簽

編寫 Dockerfile 的一些優(yōu)秀實(shí)踐

1. 使用統(tǒng)一的 base 鏡像

有些文章講優(yōu)化鏡像會提倡使用盡量小的基礎(chǔ)鏡像舞虱,比如 busybox 或者 alpine 等欢际。我更推薦使用統(tǒng)一的大家比較熟悉的基礎(chǔ)鏡像,比如? ubuntu矾兜,centos? 等损趋,因?yàn)榛A(chǔ)鏡像只需要下載一次可以共享,并不會造成太多的存儲空間浪費(fèi)椅寺。它的好處是這些鏡像的生態(tài)比較完整浑槽,方便我們安裝軟件,除了問題進(jìn)行調(diào)試返帕。

2. 動靜分離

經(jīng)常變化的內(nèi)容和基本不會變化的內(nèi)容要分開桐玻,把不怎么變化的內(nèi)容放在下層,創(chuàng)建出來不同基礎(chǔ)鏡像供上層使用荆萤。比如可以創(chuàng)建各種語言的基礎(chǔ)鏡像镊靴,python2.7铣卡、python3.4、go1.7偏竟、java7等等煮落,這些鏡像包含了最基本的語言庫,每個(gè)組可以在上面繼續(xù)構(gòu)建應(yīng)用級別的鏡像踊谋。

3. 最小原則:只安裝必需的東西

很多人構(gòu)建鏡像的時(shí)候蝉仇,都有一種沖動——把可能用到的東西都打包到鏡像中。要遏制這種想法殖蚕,鏡像中應(yīng)該只包含必需的東西轿衔,任何可以有也可以沒有的東西都不要放到里面。因?yàn)殓R像的擴(kuò)展很容易睦疫,而且運(yùn)行容器的時(shí)候也很方便地對其進(jìn)行修改害驹。這樣可以保證鏡像盡可能小,構(gòu)建的時(shí)候盡可能快笼痛,也保證未來的更快傳輸裙秋、更省網(wǎng)絡(luò)資源。

4. 一個(gè)原則:每個(gè)鏡像只有一個(gè)功能

不要在容器里運(yùn)行多個(gè)不同功能的進(jìn)程缨伊,每個(gè)鏡像中只安裝一個(gè)應(yīng)用的軟件包和文件摘刑,需要交互的程序通過 pod(kubernetes 提供的特性)? 或者容器之間的網(wǎng)絡(luò)進(jìn)行交流。這樣可以保證模塊化刻坊,不同的應(yīng)用可以分開維護(hù)和升級枷恕,也能減小單個(gè)鏡像的大小。

5. 使用更少的層

雖然看起來把不同的命令盡量分開來谭胚,寫在多個(gè)命令中容易閱讀和理解徐块。但是這樣會導(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 clean

6. 減少每層的內(nèi)容

盡管只安裝必須的內(nèi)容锡搜,在這個(gè)過程中也可能會產(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? 鏡像是分層的,任何修改都會新增一個(gè)層肠缔,修改文件或者目錄權(quán)限也是如此夏跷。如果有一個(gè)命令單獨(dú)修改大文件或者目錄的權(quán)限哼转,會把這些文件復(fù)制一份,這樣很容易導(dǎo)致鏡像很大拓春。

解決方案也很簡單释簿,要么在添加到 Dockerfile? 之前就把文件的權(quán)限和用戶設(shè)置好,要么在容器啟動腳本(entrypoint)做這些修改硼莽,或者拷貝文件和修改權(quán)限放在一起做(這樣最終也只是增加一層)。

8. 利用 cache 來加快構(gòu)建速度

如果 Docker 發(fā)現(xiàn)某個(gè)層已經(jīng)存在了煮纵,它會直接使用已經(jīng)存在的層懂鸵,而不會重新運(yùn)行一次。如果你連續(xù)運(yùn)行 docker build? 多次行疏,會發(fā)現(xiàn)第二次運(yùn)行很快就結(jié)束了匆光。

不過從 1.10 版本開始,Content Addressable Storage 的引入導(dǎo)致緩存功能的實(shí)效酿联,目前引入了 --cache-from? 參數(shù)可以手動指定一個(gè)鏡像來使用它的緩存终息。

9. 版本控制和自動構(gòu)建

最好把 Dockerfile? 和對應(yīng)的應(yīng)用代碼一起放到版本控制中,然后能夠自動構(gòu)建鏡像贞让。這樣的好處是可以追蹤各個(gè)版本鏡像的內(nèi)容周崭,方便了解不同鏡像有什么區(qū)別,對于調(diào)試和回滾都有好處喳张。

另外续镇,如果運(yùn)行鏡像的參數(shù)或者環(huán)境變量很多,也要有對應(yīng)的文檔給予說明销部,并且文檔要隨著 Dockerfile? 變化而更新摸航,這樣任何人都能參考著文檔很容易地使用鏡像,而不是下載了鏡像不知道怎么用舅桩。

每天都會有更新看過的朋友可以點(diǎn)波關(guān)注酱虎,Java學(xué)習(xí)路線和優(yōu)質(zhì)資源評論或點(diǎn)擊“Java”獲取

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市擂涛,隨后出現(xiàn)的幾起案子读串,更是在濱河造成了極大的恐慌,老刑警劉巖歼指,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件爹土,死亡現(xiàn)場離奇詭異,居然都是意外死亡踩身,警方通過查閱死者的電腦和手機(jī)胀茵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來挟阻,“玉大人琼娘,你說我怎么就攤上這事峭弟。” “怎么了脱拼?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵瞒瘸,是天一觀的道長。 經(jīng)常有香客問我熄浓,道長情臭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任赌蔑,我火速辦了婚禮俯在,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娃惯。我一直安慰自己跷乐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布趾浅。 她就那樣靜靜地躺著愕提,像睡著了一般。 火紅的嫁衣襯著肌膚如雪皿哨。 梳的紋絲不亂的頭發(fā)上浅侨,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天,我揣著相機(jī)與錄音往史,去河邊找鬼仗颈。 笑死,一個(gè)胖子當(dāng)著我的面吹牛椎例,可吹牛的內(nèi)容都是我干的挨决。 我是一名探鬼主播,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼订歪,長吁一口氣:“原來是場噩夢啊……” “哼脖祈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起刷晋,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盖高,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后眼虱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體喻奥,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年捏悬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了撞蚕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡过牙,死狀恐怖甥厦,靈堂內(nèi)的尸體忽然破棺而出纺铭,到底是詐尸還是另有隱情,我是刑警寧澤刀疙,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布舶赔,位于F島的核電站,受9級特大地震影響谦秧,放射性物質(zhì)發(fā)生泄漏竟纳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一油够、第九天 我趴在偏房一處隱蔽的房頂上張望蚁袭。 院中可真熱鬧,春花似錦石咬、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亏娜,卻和暖如春焕窝,著一層夾襖步出監(jiān)牢的瞬間尔破,已是汗流浹背伴郁。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留帆啃,地道東北人溯泣。 一個(gè)月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓虐秋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親垃沦。 傳聞我的和親對象是個(gè)殘疾皇子客给,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容