在您的CI或測試環(huán)境中使用Docker-in-Docker?三思而后行

轉(zhuǎn)譯于~jpetazzo/Using Docker-in-Docker for your CI or testing environment? Think twice.

Docker-in-Docker的主要目的是幫助開發(fā)Docker本身。許多人使用它來運行CI(例如使用Jenkins),這看起來很好,但它們會遇到許多“有趣”的問題,可以通過將Docker套接字綁定到Jenkins容器來避免。

讓我們看看這意味著什么。如果您想要沒有詳細(xì)信息的簡短解決方案,只需滾動到本文的底部即可。?

Docker-in-Docker:好的

兩年多以前,我在Docker中貢獻了-privileged標(biāo)志 并編寫了第一版dind。目標(biāo)是幫助核心團隊更快地開發(fā)Docker。在Docker-in-Docker之前,典型的開發(fā)周期是:

  • hackity hack
  • 建立
  • 停止當(dāng)前運行的Docker守護程序
  • 運行新的Docker守護進程
  • 測試
  • 重復(fù)

如果你想要一個漂亮的,可重現(xiàn)的構(gòu)建(即在一個容器中),它會有點復(fù)雜:

  • hackity hack
  • 確??蛇\行的Docker版本正在運行
  • 使用舊Docker構(gòu)建新的Docker
  • 停止Docker守護進程
  • 運行新的Docker守護進程
  • 測試
  • 停止新的Docker守護進程
  • 重復(fù)

隨著Docker-in-Docker的出現(xiàn),這被簡化為:

  • hackity hack
  • 構(gòu)建+一步完成
  • 重復(fù)

好多了,對吧?

Docker-in-Docker:糟糕的

然而,與流行的看法相反,Docker-in-Docker并非100%由閃光,小馬和獨角獸制成。我的意思是,有一些問題需要注意。

一個是關(guān)于像AppArmor和SELinux這樣的LSM(Linux安全模塊):當(dāng)啟動容器時,“內(nèi)部Docker”可能會嘗試應(yīng)用會使“外部Docker”發(fā)生沖突或混淆的安全配置文件。這實際上是最難解決的問題。試圖合并-privileged 標(biāo)志的原始實現(xiàn)。我的更改在我的Debian機器和Ubuntu測試虛擬機上工作(并且所有測試都會通過),但它會在邁克爾克羅斯比的機器上崩潰并燒毀 (如果我記得很好的話,它就是Fedora)。我不記得問題的確切原因,但可能是因為邁克是一個聰明的人SELINUX=enforce (我使用的是AppArmor)并且我的更改沒有將SELinux配置文件考慮在內(nèi)。

Docker-in-Docker:丑陋的

第二個問題與存儲驅(qū)動程序相關(guān)聯(lián)。在Docker中運行Docker時,外部Docker運行在普通文件系統(tǒng)(EXT4,BTRFS,你有什么)之上,但內(nèi)部Docker運行在寫時復(fù)制系統(tǒng)(AUFS,BTRFS,Device Mapper等)之上。 。,取決于外部Docker設(shè)置使用的內(nèi)容)。有許多組合不起作用。例如,您無法在AUFS之上運行AUFS。如果在BTRFS之上運行BTRFS,它應(yīng)該首先工作,但是一旦嵌套子卷,刪除父子卷將失敗。Device Mapper不是命名空間,因此如果Docker的多個實例在同一臺機器上使用它們,它們將能夠看到(并影響)彼此的圖像和容器支持設(shè)備。沒有bueno。

許多問題都有解決方法; 例如,如果你想在內(nèi)部Docker中使用AUFS,只需 /var/lib/docker將其升級為一個卷,你就可以了。Docker為Device Mapper目標(biāo)名稱添加了一些基本的命名空間,因此如果Docker的多次調(diào)用在同一臺機器上運行,它們就不會互相踩踏。

然而,設(shè)置并不完全是直截了當(dāng)?shù)?,正如您可?a target="_blank">從 GitHub 上的存儲庫中的那些問題中看到的 那樣 。 dind

Docker-in-Docker:它變得更糟

那么構(gòu)建緩存呢?那個人也會變得非常棘手。人們常常問我:“我正在運行Docker-in-Docker; 我如何使用位于主機上的圖像,而不是在內(nèi)部Docker中再次拉動所有圖像?“

一些喜歡冒險的人試圖/var/lib/docker 從主機綁定到Docker-in-Docker容器。有時它們/var/lib/docker與多個容器共享。

Sterling Archer建議你不要共享/ var / lib / docker,thx

Docker守護程序明確設(shè)計為具有獨占訪問權(quán)限/var/lib/docker。沒有別的東西可以觸摸,戳或隱藏任何隱藏在那里的Docker文件。

這是為什么?這是dotCloud時代的經(jīng)驗教訓(xùn)之一。dotCloud容器引擎通過讓多個進程/var/lib/dotcloud同時訪問來工作。聰明的技巧,如原子文件替換(而不是就地編輯),通過咨詢和強制鎖定來編寫代碼,以及像SQLite和BDB這樣的安全系統(tǒng)的其他實驗只能讓我們到目前為止; 當(dāng)我們重構(gòu)我們的容器引擎(最終成為Docker)時,一個重大的設(shè)計決策就是在一個守護進程下收集所有容器操作,并完成所有并發(fā)訪問的廢話。

(不要誤解我的意思:完全有可能做一些好的,可靠的,快速的,涉及多個進程和最先進的并發(fā)管理;但我們認(rèn)為它更簡單,更容易編寫和維護,與Docker的單一演員模型一起使用。)

這意味著如果您/var/lib/docker在多個Docker實例之間共享目錄,那么您將度過一段美好時光。當(dāng)然,它可能會起作用,特別是在早期測試期間?!翱茨模铱梢?code>docker run ubuntu!”但是嘗試做更多的事情(從兩個不同的實例中拉出相同的圖像......)并觀察世界燃燒。

這意味著,如果您的CI系統(tǒng)進行構(gòu)建和重建,每次重新啟動Docker-in-Docker容器時,您可能正在調(diào)整其緩存。這真的不酷。

解決方案

我們在這里退一步吧。你真的想要Docker-in-Docker嗎?或者你只是希望能夠從CI系統(tǒng)運行Docker(特別是:構(gòu)建,運行,有時推送容器和圖像),而這個CI系統(tǒng)本身就在容器中?

我敢打賭,大多數(shù)人都想要后者。您想要的只是一個解決方案,以便像Jenkins這樣的CI系統(tǒng)可以啟動容器。

最簡單的方法是將Docker套接字暴露給CI容器,方法是將其與-v標(biāo)志綁定。

簡單地說,當(dāng)您啟動CI容器(Jenkins或其他)時,不要與Docker-in-Docker一起攻擊某些東西,而是啟動它:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

現(xiàn)在這個容器可以訪問Docker套接字,因此可以啟動容器。除了不啟動“子”容器,它將啟動“兄弟”容器。

嘗試使用docker官方圖像(包含Docker二進制文件):

docker run -v /var/run/docker.sock:/var/run/docker.sock \
           -ti docker

這看起來像Docker-in-Docker,感覺就像Docker-in-Docker,但它不是Docker-in-Docker:當(dāng)這個容器創(chuàng)建更多容器時,這些容器將在頂級Docker中創(chuàng)建。您將不會遇到嵌套副作用,并且將在多個調(diào)用之間共享構(gòu)建緩存。

??這篇文章的舊版本建議將docker二進制文件從主機綁定到容器。這不再可靠,因為Docker Engine不再作為(幾乎)靜態(tài)庫分發(fā)。

如果您想使用Jenkins CI系統(tǒng)中的Docker,您有多種選擇:

  • 使用基本映像的打包系統(tǒng)安裝Docker CLI(即如果您的映像基于Debian,請使用.deb包),
  • 使用Docker API。

譯者總結(jié)

與其在容器里創(chuàng)建容器,不如在容器里掛載容器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容