吐槽:Docker真的好嗎?

dockerone發表於2015-02-12

  本文是一篇對Docker“吐槽”的文章,作者從Dockerfile、快取、分層檔案系統、Docker Hub、安全、容器和虛擬機器幾個方面入手,闡述了Docker和容器技術目前存在的一些問題,以至於說Docker的存在並沒有必要。大家可以把這篇文章的觀點作為對Docker認識的一個補充,對Docker有一個更加客觀的認識。

  概述

  距離我上次發表對Docker的看法已經一年了,那個時候我狠狠的批評了Docker在架構上的缺陷以及其糟糕的使用者體驗。雖然現在專案已經發展到1.0,但是還是得到了一些來自亞馬遜的不滿,使用者失望程度也在不斷增加,面臨大量的指責,甚至還存在一些可能會導致主機汙染的漏洞。然而Docker Hub上個人私有倉庫的引入,使得使用者自己不需要再執行個人的Registry,再加上webhook與GitHub整合,所有這些看起來是一個良好的開始。

  於是我決定再給Docker一個“機會”,並且把其投入到生產中執行六個月,看看效果怎樣。結果真的令我很失望,在使用過程中,Docker表現很令人失望,不但效能糟糕,而且由於其本身功能的不足,我們還需要在解決方案上不斷地進行變通,整個過程的使用者體驗也不盡如人意,這使得我幾乎想要把自己的臉撞碎在桌子上!事實上,在我看來Docker的效能的確很糟糕,以至於快取被禁用之後編譯過程變得更快。(看看reddithackernews上面討論)

  Dockerfile

  Dockerfile有很多問題,在我看來,他很醜陋,有很多侷限性,有的地方甚至相互矛盾,並且有很多根本性的缺陷。讓我們來說說,假如你想建立單個倉庫的多個映象,例如第二個映象包含了除錯工具, 但是對兩個映象的基本要是是一樣的。Docker不支援這樣操作(per #9198), 當前並沒有能力去對Dockerfile進行擴充套件(per #735),使用子目錄的話會破壞建立的上下文以及阻止你使用ADD/COPY(per #2224), 就像管道一樣(per #2112),在容器構建的時候(build time)你也不能夠使用環境變數根據不同的執行條件來改變指令(per #2637)。

  我們的變通方案是建立一個基礎的映象,兩個指定環境的映象,以及一些包含重新命名和sed替換的Makefile自動化指令碼。還有一些意想不到不到的“特性”導致$HOME環境變數消失了,還會產生一些沒用的錯誤資訊,使用起來的確很不方便。

  Docker 快取/分層

  Docker可以使用COW(copy-on-write)檔案系統來快取Dockerfile指令, 類似於LVM的快照,到現在仍然僅僅支援滿是問題的AuFS(AnotherUnionFS)。為了提高穩定性以及效能,之後在0.7版本中對COW做了不同的實現, 你可以在這裡瞭解到詳細的情況。但是這個快取系統並不智慧,導致了一些令人驚訝的情況,比如不能阻止某一個指令被快取(per #1996)。並且很慢, 鑑於這一點,如果你禁用快取或者是避免使用分層,建立的速度反而快一點, 在Docker Hub上傳和下載的時候這個表現的更嚴重,詳情會在下面部分進行描述:

  這些問題都是由Docker的架構設計導致的,Docker作為一個整體,總是線性的執行指令,即便是在很不合適的情況下也這樣 (per #2439)。作為一個改變慢速建立的變通方法,你可以使用一個第三方支援非同步執行的工具,例如Salt SlackPuppet,甚至Bash,這樣的話就完全放棄分層的思想使其毫無用武之地。

  Docker Hub

  Docker鼓勵通過Docker Hub來進行社交合作, 允許你釋出自己的Dokerfiles,不管是公有的還是私有的,這樣其他人可以基於此來通過FROM來進行擴充套件,而不是拷貝,貼上。這個生態系統類似於AWS marketplace的AMIs,以及Vagrant的boxes,原則上說是非常有用的。

  然而由於一些原因,Docker Hub在實現上是有缺陷的。Dockerfile不支援多FROM指令(per #3378, #5714 and #5726),這就意味著你只能繼承自單個的映象。並且他也沒有強制版本化, 例如dockerfile/ubuntu:14.04的作者可以替換掉這個標籤的內容,這就相當於在使用了沒有強制版本的包管理工具。另外在後面也會提到,Docker Hub在速度上的缺陷也很令人失望。

  Docker Hub也有一個自動構建的系統,它可以監測倉庫中新的提交,並且觸發一個容器的建立。因為很多原因,這個功能基本上是沒用處的。建立服務沒有可定製化的功能,甚至連最基本的前/後指令碼鉤子也沒有。它還強制使用一個指定的專案結構,希望在根目錄中只有單一的Dockerfile,導致建立過程變得相當的慢,也破壞了我們之前提到的建立的變通方法。

  我們採用的變通方法是使用CircleCI, 一個持續整合(CI)平臺,可以觸發基於Makefile的Docker建立, 並推送到Docker Hub。這個並不能解決速度慢的問題, 唯一的解法就是使用我們自己的Docker Registry,這樣做確實有點複雜甚至可笑。

  安全

  Docker原來使用LXC作為預設的執行環境,從0.9之後採用libcontainer作為預設的執行環境。當使用合適的執行驅動(exec-driver)時,引入它來調整名稱空間的能力,許可權以及使用定製的LXC配置

  Docker需要一個根守護程式一直在主機上執行,並且有很多安全漏洞,比如CVE-2014-6407CVE-2014-6408,非常坦率的說,這還不應該排在第一位。即便是Gartner, 根據他們可憐的評估記錄,也表達了對Docker不成熟,以及安全問題的擔憂。

  Docker,從設計上來說,對namespace能力過分的信任,但實際上namespace比一般的hypervisor暴露的攻擊面要大很多,Xen在Linux裡面有129個CVEs(Common Vulnerabilities and Exposures),與之相比它卻有1279個。當然,這在某些情況下也是可以接受的,比如在Travis CI裡面以公有的方式來構建, 但是在私有情況下和多使用者的環境下,就顯得比較危險了。

  容器不是虛擬機器

  namespaces和cgroups是非常強大的,允許一個程式及其子程式有一個共享核心資源的私有檢視, 例如網路棧和程式表。這種粒度的控制和隔離,加上chroot jailing和grsec, 可以提供一個很優秀的保護層。 有些應用, 例如uWSGI, 直接對這些優點加以利用,而不是通過Docker。 還有些應用不直接支援namespaces的可以用firejail封裝成沙箱。如果你覺得很冒險的話, 你也可以直接在你的程式碼裡面支援namespace。

  容器化專案,諸如LXC和Docker, 利用這些特性,可以高效的在一個相同的核心空間中執行多個linux的發行版。與hypervisor相比,它們有時候會有一些優點,比如佔用更少的記憶體並且啟動速度更快。 但是這是以損失完全性,穩定性和相容性為代價的。這裡有一個跟Linux核心介面有關的邊緣情況, 在核心和使用者空間執行非相容的和沒有經過測試的glibc版本組合會導致一些不可預料的行為。

  回到2008年, 當LXC被設想出來的時候,硬體輔助的虛擬化才有幾年的時間, 很多hypervisor有效能和穩定性的問題,這樣的虛擬化並沒有被廣泛的使用,也只是為了降低花費和減少物理機而做了折衷。但是現在hypervisor的效能已經可以和物理機器一樣快了,有趣的是,在一些情況下可能更快。執行自定義的虛擬機器也變的更快更便宜,隨著DigitalOcean在效能和花費方面不斷的超越EC2, 使得以一對一的方式執行應用和虛擬機器,在財政上變的成為可能。

  Bryan Cantrill在這裡指出, 虛擬化的效能主要取決於工作負載的型別,比如IO很重的應用會導致更低的效能。

  對於有些特定的情況,使用容器化是正確的選擇, 但是除非你能很明確的解釋為什麼你要使用容器,否則你便可以使用hypervisor來代替。即便是你使用了傳統的虛擬化,你也可以直接應用namespaces的優勢,諸如firejail就可以幫助你的應該在缺少本地支援的情況下來實現這樣的特性。

  Docker是沒有必要的

  Docker增加了一個複雜的入侵層,這使得開發,故障排查以及除錯變得非常困難, 常常製造的問題比解決的問題還多。這對部署沒有一點好處,因為你仍然需要使用的快照來達到自動擴充套件的目的。更糟糕的是,如果你不使用快照的話,你的生產環境的擴充套件需要取決於Docker Hub的穩定性。

  這個已經被baseimage-docker這個專案濫用了,這個映象試圖通過執行init.d作為入口使得檢查、除錯,以及相容變得更容易,它還嘗試提供給你一個可以用ssh登入的伺服器,從而把一個容器看成是一個虛擬機器,儘管作者使用了很無力的論據去反駁這一點。

  結論

  如果你的開發工作流非常的健全,那麼就應該已經明白Docker是沒有必要的。所有它宣傳的特性要麼是沒用的要麼就是實現的非常差,並且它主要的特性直接可以使用namespaces來完成。Dokcer本來應該是8年前的一個很可愛的想法,但是今天已經沒什麼用了。

  更正/修訂

  表面上看,Docker有很多值得關注的地方。它鼓勵開發人員圍繞一個一成不變的部署流程, 可以快速的,簡單的開始一個新的專案,還有些其他的人認為有用的東西。但是需要提醒大家的是,本文是聚焦在一個每日的,長期使用的Docker上面,包括本地和生產環境。

  儘管大多數提到的問題都是顯而易見的,本文並沒有為Docker如何變得更好提出什麼建議。對Docker來說有很多解決方法,畢竟不管什麼專案都是有優缺點的,我會在接下來的文章中作詳細的解釋。

  a-ko對使用容器化有個長期的討論,markbnj也有一個詳細的技術反駁,這兩個都是很有用的。

  我想對所有給他們反饋的人說聲謝謝,看到大家很喜歡我的寫作風格感覺非常的高興,我也讀了幾個高階工程師的回應, 包括那些欣賞我的人,這非常震撼人心。

  原文連結:Lets review.. Docker (again)(翻譯:左偉 校對:王哲)

相關文章