吐槽:Docker真的好嗎?
本文是一篇對Docker“吐槽”的文章,作者從Dockerfile、快取、分層檔案系統、Docker Hub、安全、容器和虛擬機器幾個方面入手,闡述了Docker和容器技術目前存在的一些問題,以至於說Docker的存在並沒有必要。大家可以把這篇文章的觀點作為對Docker認識的一個補充,對Docker有一個更加客觀的認識。
概述
距離我上次發表對Docker的看法已經一年了,那個時候我狠狠的批評了Docker在架構上的缺陷以及其糟糕的使用者體驗。雖然現在專案已經發展到1.0,但是還是得到了一些來自亞馬遜的不滿,使用者失望程度也在不斷增加,面臨大量的指責,甚至還存在一些可能會導致主機汙染的漏洞。然而Docker Hub上個人私有倉庫的引入,使得使用者自己不需要再執行個人的Registry,再加上webhook與GitHub整合,所有這些看起來是一個良好的開始。
於是我決定再給Docker一個“機會”,並且把其投入到生產中執行六個月,看看效果怎樣。結果真的令我很失望,在使用過程中,Docker表現很令人失望,不但效能糟糕,而且由於其本身功能的不足,我們還需要在解決方案上不斷地進行變通,整個過程的使用者體驗也不盡如人意,這使得我幾乎想要把自己的臉撞碎在桌子上!事實上,在我看來Docker的效能的確很糟糕,以至於快取被禁用之後編譯過程變得更快。(看看reddit和hackernews上面討論)
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 Slack, Puppet,甚至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-6407和CVE-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)(翻譯:左偉 校對:王哲)
相關文章
- 前端框架真的好嗎?前端框架
- babel吐槽Babel
- 美女學前端真的好嗎?前端
- WebAssembly真的要取代Docker嗎?WebDocker
- Docker再遇公關危機,GitHub開發者吐槽Docker下載限制DockerGithub
- Ubuntu,真的有那麼好嗎?Ubuntu
- 吐槽visdom
- Docker安全性(一)——Docker容器真的安全嗎?Docker
- 非同步程式設計真的好嗎?非同步程式設計
- 必須被吐槽嗎?聊聊Mac裝Windows那點事MacWindows
- 功能測試吐槽
- DIY攢機-你真的搞懂了硬碟分割槽嗎?硬碟
- 關於js的吐槽JS
- 程式猿找工作吐槽分享
- 火絨安全軟體好用嗎 火絨真的比360好嗎
- 阿里員工吐槽:工作壓力真的大,年假都沒心情用,後悔來阿里阿里
- 吐槽“技術債務” - morethancoding
- 吐槽各大題庫的優劣
- 吐槽: 移動端快取策略快取
- Javascript之旅——第九站:吐槽functionJavaScriptFunction
- 後臺程式碼 拼接table吐槽
- [吐槽] 光Google是不夠的Go
- go語言的一些吐槽Go
- 吐槽微信對開發者的"流氓"行為
- 對“主資料”的一點吐槽
- 3.15 資料庫吐槽大會資料庫
- 吐槽下mac的印表機設定Mac
- 那些被吐槽最多的程式語言
- 吐槽前端元件化的踩坑之路前端元件化
- 軟體定製開發真的比SaaS系統好嗎
- python程式設計真的好學嗎?python入門Python程式設計
- Linux可以增加分割槽大小嗎?有哪些好處?Linux
- 吐槽橫行的面試題分享環境面試題
- 吐槽Javascript系列一:slice()、substr()和 substring()JavaScript
- 假如易立競吐槽程式設計師。。。程式設計師
- 吐槽一下Xcode中的PlaygroundXCode
- Quartz.Net 主要概念介紹和吐槽quartz
- iPhone又被吐槽 這個功能太爛了!iPhone