主頁(yè) > 知識(shí)庫(kù) > 在Docker中構(gòu)建長(zhǎng)時(shí)間運(yùn)行的腳本的一些方法

在Docker中構(gòu)建長(zhǎng)時(shí)間運(yùn)行的腳本的一些方法

熱門(mén)標(biāo)簽:地圖標(biāo)注用小紅旗 索契地圖標(biāo)注app 儋州電銷(xiāo)機(jī)器人廠家 巴東單位怎么做地圖標(biāo)注 電話外呼系統(tǒng)線路哪家公司做得好 成都人工外呼系統(tǒng)平臺(tái) 免費(fèi)高德地圖標(biāo)注 外呼系統(tǒng)工作推進(jìn) 地圖標(biāo)注員項(xiàng)目

我想我已經(jīng)找到了一個(gè)非常不錯(cuò)的Docker使用案例。你是不是會(huì)覺(jué)得這是一篇寫(xiě)Docker有多好多好的文章,開(kāi)始之前我想和你確認(rèn),這篇文章會(huì)介紹如何把文件系統(tǒng)作為持久性的數(shù)據(jù)結(jié)構(gòu)。

因此,這篇文章的見(jiàn)解同樣適用于其他的 copy-on-write文件系統(tǒng),如BTRFS和ZFS。
問(wèn)題

讓我們從這個(gè)我試圖解決的問(wèn)題開(kāi)始。我開(kāi)發(fā)了一個(gè)會(huì)運(yùn)行很長(zhǎng)時(shí)間的構(gòu)建腳本,這個(gè)腳本中包含了很多的步驟。

    這個(gè)腳本會(huì)運(yùn)行1-2個(gè)小時(shí)。
    它會(huì)從網(wǎng)絡(luò)下載比較大的文件(超過(guò)300M)。
    后面的構(gòu)建步驟依賴前期構(gòu)建的庫(kù)。

但最最煩人的是,運(yùn)行這個(gè)腳本真的需要花很長(zhǎng)的時(shí)間。
文件系統(tǒng)是固有狀態(tài)

我們一般是通過(guò)一種有狀態(tài)的方式與文件系統(tǒng)進(jìn)行交互的。我們可以添加、刪除或移動(dòng)文件。我們可以修改文件的 權(quán)限或者它的訪問(wèn)時(shí)間。大部分獨(dú)立的操作都可以撤銷(xiāo),例如將文件移動(dòng)到其它地方后,你可以將文件恢復(fù)到原來(lái)的位置。但我們不會(huì)通過(guò)快照的方式來(lái)將它恢復(fù)到 原始狀態(tài)。這篇文章我將會(huì)介紹如何在耗時(shí)較長(zhǎng)的腳本中充分利用快照這一特性。
使用聯(lián)合文件系統(tǒng)的快照

Docker使用的是聯(lián)合文件系統(tǒng)叫做AUFS(譯者注:簡(jiǎn)單來(lái)說(shuō)就是支持將不同目錄掛載到同一個(gè)虛擬文件系統(tǒng)下的文件系統(tǒng))。聯(lián)合文件系統(tǒng)實(shí)現(xiàn)了Union mount。顧名思義,也就是說(shuō)不同的文件系統(tǒng)的文件和目錄可以分層疊加在單個(gè)連貫文件系統(tǒng)之上。這是通過(guò)分層的方式完成的。如果一個(gè)文件出現(xiàn)在兩個(gè)文件系統(tǒng),那最高層級(jí)的文件才會(huì)顯示(該文件其它版本也是存在于層級(jí)中的,不會(huì)改變,只是看不到的)。

在Docker中,每一個(gè)在Union mount轉(zhuǎn)哦給你的文件系統(tǒng)都被稱(chēng)為layers(層)。使用這種技術(shù)可以輕松實(shí)現(xiàn)快照,每個(gè)快照都是所有層的一個(gè)Union mount。
生成腳本的快照

使用快照可以幫助構(gòu)建一個(gè)長(zhǎng)時(shí)運(yùn)行的腳本。總的想法是,將一個(gè)大的腳本分解為許多小的腳本(我喜歡稱(chēng)之為 scriptlets),并單獨(dú)運(yùn)行這些小的腳本,腳本運(yùn)行后為其文件系統(tǒng)打一個(gè)快照 (Docker會(huì)自動(dòng)執(zhí)行此操作)。如果你發(fā)現(xiàn)一個(gè)scriptlet運(yùn)行失敗,你可以快速回退到上次的快照,然后再試一次。一旦你完成腳本的構(gòu)建,并且 可以保證腳本能正常工作,那你就可以將它分配給其它主機(jī)。

回過(guò)頭來(lái)再對(duì)比下,如果你沒(méi)有使用快照功能了?當(dāng)你辛辛苦苦等待了一個(gè)半小時(shí)后,腳本卻構(gòu)建失敗了,我想除了少部分有耐心的人外,很多人是不想再來(lái)一次了,當(dāng)然,你也會(huì)盡最大努力把系統(tǒng)恢復(fù)到失敗前的狀態(tài),比如可以刪除一個(gè)目錄或運(yùn)行make clean。

但是,我們可能沒(méi)有真正地理解我們正在構(gòu)建的組件。它可能有復(fù)雜的Makefile,它會(huì)把把文件放到文件系統(tǒng)中我們不知道的地方,唯一真正確定的途徑是恢復(fù)到快照。
使用快照構(gòu)建腳本的Docker

在本節(jié)中,我將介紹我是如何使用Docker實(shí)現(xiàn)GHC7.8.3 ARM交叉編譯器的構(gòu)建腳本。Docker非常適合做這件事,但并非完美。我做了很多看起來(lái)沒(méi)用的或者不雅的事情,但都是必要的,這都是為了保證將開(kāi)發(fā)腳本的總時(shí)間降到最低限度。構(gòu)建腳本可以在這里找到。
用Dockerfile構(gòu)建

Docker通過(guò)讀取Dockerfile來(lái)構(gòu)建鏡像。Dockerfile會(huì)通過(guò)一些命令來(lái)具體指定應(yīng)該執(zhí)行哪些動(dòng)作。在我的腳本中主要用到WORKDIR、ADD和RUN。ADD命令非常有用因?yàn)樗梢宰屇阍谶\(yùn)行之前將外部文件添加到當(dāng)前Docker鏡像中然后轉(zhuǎn)換成鏡像的文件系統(tǒng)。你可以在這里看到很多scriptlets構(gòu)成的構(gòu)建腳本。
設(shè)計(jì)

1. 在RUN之前ADD scriptlets

如果你很早就將所有的scriptletsADD在Dockerfile,您可能會(huì)遇到以下問(wèn)題:如果你的腳本構(gòu)建失敗,你回去修改scriptlet并再次運(yùn)行docker build。但是你發(fā)現(xiàn),Docker開(kāi)始在首次加入scriptlets的地方構(gòu)建!這樣做會(huì)浪費(fèi)了大量的時(shí)間并且違背了使用快照的目的。

出現(xiàn)這種情況的原因是由于Docker處理它的中間鏡像(快照)的方式。當(dāng)Docker通過(guò)Dockerfile構(gòu)建鏡像時(shí),它會(huì)與中間鏡像比較當(dāng)前命令是否一致。然而,在ADD命令的情況下被裝進(jìn)鏡像的文件里的內(nèi)容也會(huì)被檢查。如果相對(duì)于現(xiàn)有的中間鏡像,文件已經(jīng)改變,那么Docker也別無(wú)選擇,只能從這點(diǎn)開(kāi)始建立一個(gè)新的鏡像。因?yàn)镈ocker不知道這些變化會(huì)不會(huì)影響到構(gòu)建。

此外,使用RUN命令要注意,每次運(yùn)行時(shí)它都會(huì)導(dǎo)致文件系統(tǒng)有不同的更改。在這種情況下,Docker會(huì)發(fā)現(xiàn)中間鏡像并使用它,但是這將是錯(cuò)誤的。RUN命令每次運(yùn)行時(shí)會(huì)造成文件系統(tǒng)相同的改變。舉個(gè)例子,我確保在我的scriptlets我總是下載了一個(gè)已知版本的文件與一個(gè)特定MD5校驗(yàn)。

對(duì)Docker 構(gòu)建緩存更詳細(xì)的解釋可以在這里找到。

2.不要使用ENV命令來(lái)設(shè)置環(huán)境變量,請(qǐng)使用scriptlet。

它似乎看起來(lái)很有誘惑力:使用ENV命令來(lái)設(shè)置所有構(gòu)建腳本需要的環(huán)境變量。但是,它不支持變量替換的方式,例如 ENV BASE=$HOME/base 將設(shè)置BASE的值為$HOME/base著很可能不是你想要的。

相反,我用ADD命令添加一個(gè)名為set-env.sh文件。此文件會(huì)包含在后續(xù)的scriptlet中:

   

復(fù)制代碼
代碼如下:
THIS_DIR="$(nbsp;cdnbsp;"$(nbsp;dirnamenbsp;"${BASH_SOURCE[0]}"nbsp;)"nbsp;nbsp;pwdnbsp;)"
sourcenbsp;$THIS_DIR/set-env-1.sh

如果你沒(méi)有在第一時(shí)間獲取set-env.sh會(huì)怎么樣呢?它很早就被加入Dockerfile并不意味著修改它將會(huì)使隨后的快照無(wú)效?

是的,這會(huì)有問(wèn)題。在開(kāi)發(fā)腳本時(shí),我發(fā)現(xiàn),我已經(jīng)錯(cuò)過(guò)了在set-env.sh添加一個(gè)有用的環(huán)境變量。解決方案是創(chuàng)建一個(gè)新的文件set-env-1.sh包含:

   

復(fù)制代碼
代碼如下:
THIS_DIR="$(nbsp;cdnbsp;"$(nbsp;dirnamenbsp;"${BASH_SOURCE[0]}"nbsp;)"nbsp;nbsp;pwdnbsp;)"
sourcenbsp;$THIS_DIR/set-env.sh
ifnbsp;!nbsp;[nbsp;-enbsp;"$CONFIG_SUB_SRC/config.sub"nbsp;]nbsp;;nbsp;then
CONFIG_SUB_SRC=${CONFIG_SUB_SRC:-$NCURSES_SRC}
fi

然后,在所有后續(xù)的scriptlets文件中包含了此文件?,F(xiàn)在,我已經(jīng)完成了構(gòu)建腳本,我可以回去解決這個(gè)問(wèn)題了,但是,在某種意義上,它會(huì)破壞最初的目標(biāo)。我將不得不從頭開(kāi)始運(yùn)行構(gòu)建腳本看看這種變化是否能成功。
缺點(diǎn)

一個(gè)主要缺點(diǎn)是這種方法是,所構(gòu)建的鏡像尺寸是大于它實(shí)際需求的尺寸。在我的情況下尤其如此,因?yàn)槲以谧詈髣h除了大量文件的。然而,這些文件都仍然存在于聯(lián)合掛載文件系統(tǒng)的底層文件系統(tǒng)內(nèi),所以整個(gè)鏡像是大于它實(shí)際需要的大小至少多余的是刪除文件的大小。

然而,有一個(gè)變通。我沒(méi)有公布此鏡像到Docker Hub Registry。相反,我:

    使用docker export導(dǎo)出內(nèi)容為tar文件。
    創(chuàng)建一個(gè)新的Dockerfile簡(jiǎn)單地添加了這個(gè)tar文件的內(nèi)容。

產(chǎn)生尺寸盡可能小的鏡像。
結(jié)論

這種方法的優(yōu)點(diǎn)是雙重的:

    它使開(kāi)發(fā)時(shí)間降至最低,不再做那些已經(jīng)構(gòu)建成功的子組件。你可以專(zhuān)注于那些失敗的組件。
    這非常便于維護(hù)構(gòu)建腳本。構(gòu)建可能會(huì)失敗,但只要你搞定Dockerfiel,至少你不必再?gòu)念^開(kāi)始。

標(biāo)簽:茂名 儋州 龍巖 長(zhǎng)春 安康 鶴壁 鄂州 江蘇

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《在Docker中構(gòu)建長(zhǎng)時(shí)間運(yùn)行的腳本的一些方法》,本文關(guān)鍵詞  在,Docker,中,構(gòu)建,長(zhǎng)時(shí)間,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《在Docker中構(gòu)建長(zhǎng)時(shí)間運(yùn)行的腳本的一些方法》相關(guān)的同類(lèi)信息!
  • 本頁(yè)收集關(guān)于在Docker中構(gòu)建長(zhǎng)時(shí)間運(yùn)行的腳本的一些方法的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章