3億Docker容器部署的挑戰(zhàn)及應(yīng)對(duì)方案
IronWorker 是一個(gè)面向開(kāi)發(fā)者的任務(wù)隊(duì)列服務(wù),開(kāi)發(fā)人員可以在不設(shè)置和管理任何基礎(chǔ)設(shè)施的基礎(chǔ)上,調(diào)度執(zhí)行大規(guī)模的任務(wù)。幾個(gè)月前,IronWorker 開(kāi)始使用 Docker,如今其內(nèi)部已經(jīng)部署了3億多個(gè) Docker 容器,本文中分享了 IronWorker 在使用基于 Docker 的基礎(chǔ)架構(gòu)時(shí),遇到的挑戰(zhàn)、解決方法,以及其中的收獲。
以下為譯文:
IronWorker 是一個(gè)任務(wù)隊(duì)列服務(wù),他讓開(kāi)發(fā)人員在不用設(shè)置和管理任何基礎(chǔ)設(shè)施的基礎(chǔ)上,調(diào)度執(zhí)行大規(guī)模的任務(wù)。我們3年多前推出這項(xiàng)服務(wù)時(shí),使用了包含所有的語(yǔ)言和代碼包的LXC容器運(yùn)行任務(wù)。Docker使我們能夠輕松地升級(jí)和管理一組容器,為客戶提供更多的語(yǔ)言環(huán)境和安裝包。
我們剛開(kāi)始使用的是v0.7.4版本的 Dokcer ,使用過(guò)程中遇到一些困難(不能正常關(guān)閉曾是個(gè)大問(wèn)題,不過(guò)后來(lái)被解決了)。我們不僅成功地克服了所有的困難,并且發(fā)現(xiàn) Docker 不僅滿足了我們的需求,更是超出了我們的預(yù)期。因此我們?cè)谖覀兊幕A(chǔ)架構(gòu)中推廣使用 Docker ?;谖覀兊慕?jīng)驗(yàn)來(lái)看,這樣做是有意義的。
Docker的優(yōu)勢(shì):
更新維護(hù)鏡像非常容易
Doker 使用類似 git 的非常強(qiáng)大的方法來(lái)管理 image ,使得它能很方便地管理大量的、不斷變化的環(huán)境,他的 image 分層系統(tǒng)不僅節(jié)省空間而且使我們擁有更細(xì)區(qū)分度的 images 。 現(xiàn)在,我們能夠跟上快速更新的語(yǔ)言的節(jié)奏,例如我們能夠提供一個(gè)新的專為媒體處理而設(shè)計(jì)的 ffmpeg stack 。我們現(xiàn)在有多達(dá)15個(gè)不同的堆棧并且正在迅速擴(kuò)大。
資源分配
基于 LXC 的容器是操作系統(tǒng)級(jí)別的虛擬化方法,所有的容器共享系統(tǒng)內(nèi)核,但是每個(gè)容器可以被約束使用指定的資源,比如 CPU 、內(nèi)存和 I/O 。 Docker 提供 REST API 、環(huán)境版本控制、獲取/提交鏡像、輕松獲取統(tǒng)計(jì)數(shù)據(jù)等功能。 Docker 支持使用 CoW 文件系統(tǒng)來(lái)更安全的隔離數(shù)據(jù)。這意味著,任務(wù)中對(duì)文件的所有改變都分開(kāi)存儲(chǔ),并可以用一個(gè)命令清除。 LXC 不能跟蹤這種變化。
Dockerfiles使得集成簡(jiǎn)單
我們的團(tuán)隊(duì)遍布世界各地。只要發(fā)布一個(gè)簡(jiǎn)單的 Dockerfile 就可以下班,當(dāng)你休息時(shí),可以保證其他工作的人能夠生成和你的一樣的鏡像??朔瞬煌胤降娜擞胁煌淖飨r(shí)間的困難。干凈的鏡像使得它部署和測(cè)試更快。我們的迭代周期更快,團(tuán)隊(duì)里每個(gè)人更加開(kāi)心。
不斷壯大的社區(qū)
Docker 現(xiàn)在更新得非常快,甚至比 chrome 還快。更重要的是,參與增加新功能和修復(fù) bug 的社區(qū)數(shù)量在大量增加。 無(wú)論是為為鏡像貢獻(xiàn)還是為 Docker 做貢獻(xiàn),甚至是為 Docker 的周邊工具做貢獻(xiàn),有一大批聰明的人正在為其努力,因此我們也不能置身事外。我們發(fā)現(xiàn) Docker 的社區(qū)非?;钴S有意義,我們很高興能夠成為其中一員。
Docker + CoreOS
我們也處在探索階段,但我們發(fā)現(xiàn) Docker 和 CoreOS 的結(jié)合對(duì)于我們來(lái)說(shuō)似乎是更好地選擇。Docker 提供了穩(wěn)定的鏡像管理和容器。CoreOS 提供了一個(gè)精簡(jiǎn)的云操作系統(tǒng)、機(jī)器級(jí)別分布式編排和虛擬狀態(tài)管理。這個(gè)組合關(guān)注問(wèn)題的不同方面,是一個(gè)更合理的基礎(chǔ)設(shè)施棧。
挑戰(zhàn)
每一個(gè)服務(wù)器端的技術(shù)需要微調(diào)和定制,尤其是大規(guī)模運(yùn)行時(shí),,Docker 也不例外。(例如:我們跑不到5000萬(wàn)的任務(wù),一個(gè)月50萬(wàn)小時(shí)計(jì)算,并且不斷更新我們的鏡像)。下面是我們使用大量 Docker 容器數(shù)時(shí)遇到的一些挑戰(zhàn):
向后兼容性不夠
該領(lǐng)域的快速創(chuàng)新雖然是一個(gè)優(yōu)勢(shì),但是也存在缺點(diǎn)。其中之一是向后兼容性差。在多數(shù)情況下,我們遇到的問(wèn)題主要是是命令行語(yǔ)法、 API 的改變,從產(chǎn)品角度來(lái)說(shuō)這不是一個(gè)嚴(yán)重的問(wèn)題。
但在某些情況下,它影響了操作性能。例如,在任何啟動(dòng)容器后引發(fā)的 Docker 錯(cuò)誤,我們要解析 STDERR 并根據(jù)錯(cuò)誤類型進(jìn)行響應(yīng)(例如重試)。非常不幸的是,錯(cuò)誤的輸出格式隨著版本不同變化,不得不在不斷變化的結(jié)果中調(diào)試,使我們非常疲憊。
圖注:Docker的錯(cuò)誤率
這個(gè)問(wèn)題相對(duì)來(lái)說(shuō)還比較好解決,但是意味著每次的更新要經(jīng)過(guò)多次驗(yàn)證,并且你需要一直開(kāi)發(fā)直到這個(gè)更新的版本被發(fā)布到了系統(tǒng)大部分環(huán)境中。我們幾個(gè)月前使用v0.7.4,現(xiàn)在我們的系統(tǒng)更新到v1.2.0.在這個(gè)領(lǐng)域我們已經(jīng)有了一個(gè)很大的進(jìn)步。
有限的工具和庫(kù)
雖然 Docker 有一個(gè)四個(gè)月前發(fā)布的穩(wěn)定版本,圍繞它的一些工具仍然不穩(wěn)定。采用 Docker 生態(tài)圈中的大部分工具意味著需要投入更多的精力。為了使用***的功能、修復(fù) bug ,你團(tuán)隊(duì)中需要有人熬夜加班對(duì)這些功能,頻繁的進(jìn)行一些修改.也就是說(shuō),我們很高興有一些 Docker 周邊的工具在開(kāi)發(fā),而且很期待能夠有一個(gè)工具在其中脫穎而出。我們對(duì) etcd 、 fleet 、 kubernetes 比較看好。
戰(zhàn)勝困難
接下來(lái)根據(jù)我們的經(jīng)驗(yàn),更深入的講我們講我們遇到的問(wèn)題和我們的解決方法。問(wèn)題列表主要來(lái)自我們 Ironworker 的***開(kāi)發(fā)兼工程運(yùn)營(yíng)總監(jiān) Roman Kononov 和一直在調(diào)試和規(guī)范化我們 Docker 操作的 Sam Ward 。
圖注:Debug時(shí)的一個(gè)異常
說(shuō)明一下,當(dāng)我們遇到和 Docker 相關(guān)或者其它系統(tǒng)相關(guān)的問(wèn)題,我們可以自動(dòng)的重新執(zhí)行任務(wù),對(duì)用戶沒(méi)有任何影響(重試是平臺(tái)的內(nèi)置功能)。
刪除操作時(shí)間長(zhǎng)
起初刪除容器時(shí)間長(zhǎng),需要太多的磁盤(pán)I/O操作。這導(dǎo)致我們的系統(tǒng)速度明顯變慢,形成了瓶頸。我們不得不增加可用的內(nèi)核數(shù)目,而這個(gè)數(shù)量遠(yuǎn)遠(yuǎn)超出我們所需的。
圖注:快速刪除Docker容器的解決方案
通過(guò)研究使用 devicemapper(一個(gè) Docker 的文件系統(tǒng)驅(qū)動(dòng)),我們發(fā)現(xiàn)設(shè)置一個(gè)選項(xiàng)有作用--storage-opt dm.blkdiscard=false ,這個(gè)選項(xiàng)告訴 Docker 刪除容器時(shí)跳過(guò)花費(fèi)時(shí)間長(zhǎng)的磁盤(pán)操作,大大加速了容器的關(guān)閉過(guò)程。當(dāng)修改好刪除腳本后,這個(gè)問(wèn)題就沒(méi)了。
卷無(wú)法卸載
由于 Docker 沒(méi)有可靠地卸載卷,容器不能正確地停止。這導(dǎo)致容器永遠(yuǎn)在運(yùn)行,即使已經(jīng)完成了任務(wù)。解決辦法就是顯示地調(diào)用用戶自己寫(xiě)得一些列腳本來(lái)卸載卷,刪除文件夾。幸運(yùn)的是,這個(gè)問(wèn)題是之前我們使用 Docker v0.7.6 版本時(shí)遇到的,當(dāng) Docker 更新到 v0.9.0 解決了這個(gè)問(wèn)題后我們就刪除了那些冗長(zhǎng)的腳本。
內(nèi)存限制開(kāi)關(guān)
Docker 其中的一個(gè)發(fā)布的版本中突然新增了內(nèi)存限制選項(xiàng),刪除了 LXC 中的選項(xiàng)。其結(jié)果是一些工作進(jìn)程到達(dá)內(nèi)存界限,然后了整體不響應(yīng)。這弄得我們措手不及,因?yàn)榧词故褂昧怂恢С值脑O(shè)置, Docker 也沒(méi)有出錯(cuò)。解決方法很簡(jiǎn)單,即在 Docker 內(nèi)部設(shè)置內(nèi)存限制。
未來(lái)計(jì)劃
正如你所看到的,我們對(duì) Docker 投入非常多,我們?cè)诮酉碌妹刻鞎?huì)繼續(xù)投入。除了用它來(lái)隔離用戶在 IronWorker 中運(yùn)行的代碼,我們也準(zhǔn)備在其他的一些領(lǐng)域使用它。這些領(lǐng)域包括:
IronWorker 后臺(tái)
除了使用 Docker 作為任務(wù)的容器,我們也在使用它來(lái)管理每個(gè)服務(wù)器上運(yùn)行的用來(lái)管理和啟動(dòng)任務(wù)的進(jìn)稱。每一進(jìn)程著的主要任務(wù)是從隊(duì)列中拿一個(gè)任務(wù),把它放到合適的 Docker 容器中,運(yùn)行,監(jiān)測(cè),運(yùn)行完后刪除環(huán)境。有趣的是同一臺(tái)機(jī)器上我們有容器化的代碼來(lái)管理其它容器。把我們所有的基礎(chǔ)設(shè)施環(huán)境放到 Docker 的容器中讓我們?cè)?CoreOS 上的運(yùn)行相當(dāng)容易。
IronWorker, IronMQ,以及 IronCache APIs
和其他的運(yùn)維團(tuán)隊(duì)一樣,我們也不喜歡部署。能夠把我們的所有的服務(wù)打包 Docker 容器中,然后簡(jiǎn)單、確定地部署,我們非常地激動(dòng)。不用再配置服務(wù)器,我們需要的就只是能夠運(yùn)行 Dokcer 容器的服務(wù)器。我們正在替換我們的服務(wù)器搭建,使用 Docker 容器在服務(wù)器上為我們發(fā)布的產(chǎn)品搭建環(huán)境。變得的靈活、簡(jiǎn)單,有更可靠的協(xié)議棧。
生成和加載程序
我們也在用 Docker 容器在 IronWorker 中生成和加載程序。一個(gè)顯著的進(jìn)步是為用戶改進(jìn)了,大規(guī)模、特定任務(wù)負(fù)載和工作流的創(chuàng)建、上傳、運(yùn)行任務(wù)的過(guò)程。還有一個(gè)好處是用戶可以在本地測(cè)試程序,而測(cè)試環(huán)境和我們的生產(chǎn)服務(wù)一致。
企業(yè)內(nèi)部部署版
使用 Docker 作為主要分發(fā)方法, IronMQ 企業(yè)內(nèi)部部署版簡(jiǎn)化了我們的分發(fā)工作,并且提供了一個(gè)簡(jiǎn)單通用的在幾乎任何云環(huán)境中都能部署的方法。就像我們?cè)诠灿性粕线\(yùn)行的服務(wù),客戶需要的就是可以運(yùn)行 Docker 容器的服務(wù)器,同時(shí)他們可以相對(duì)容易的獲得在測(cè)試或生產(chǎn)環(huán)境中運(yùn)行的多臺(tái)服務(wù)器的云服務(wù)。
原文出自:https://docker.cn/p/docker-in-production-what-weve-learned