在“選擇Docker還是Rocket做容器?為何不選擇兩個?”一文中,曾提到CoreOS的創始人Polvi和Docker的創始人Sonomon都認為,Rocket和Docker沒有競爭性。Docker平臺是一個產品,Rocket是一個組件。企業可以選擇Docker替代Cloud Foundry,也可以使用Rocket構建Cloud Foundry。CoreOS在發布Rocket時就指出,Rocket的出現是因為有些人需要一個更“純凈”的容器。換句話說,Rocket算是“App Container Specification”的標準實現。本文作者從“App Container Specification”入手,分析了Rocket和Docker在技術實現上的不同。以下為原文:
Docker和Rocket,殊途同歸
首先,對于那些把Docker與Rocket放在一起比較的人,我想勸你們首先適當地調查一下。如果有這樣兩個軟件:一個已經有1年多的歷史,作為一個開源項目由全世界上千的開發者共同參與,并且已經或即將在實際的生產環境中被部署、測試;而另一個軟件則是“新鮮出爐”的。如果這個較成熟的軟件不是特別爛的話,那么很有可能它就是贏家。
所以,將Docker0.1.1與最近預發行的Rocket拿來比較會更公平一些。此外, CoreOS的CTO Brandon Philips也多次強調,Docker的一些功能將不計劃加入到Rocket中——不只是現在,也許永遠不會。為什么?因為Rocket項目的重點,至少目前的情況——不是重新實現Docker。Rocket是 “App Container Specification”的實現,因此,想比較兩者,最好比較“App Container Specification”和最初的Docker清單或者Docker實現的其它規范。
以下的比較都將基于以上共識:
Systemd
通常情況關于Rocket的討論最多的話題是systemd-spawn或者是 systemd 。 CoreOS已將systemd作為他們Linux發行版的init系統。他們可以接著使用Init 腳本或者upstar,但是他們選擇使用了將來會成為所有主流Linux版本標準的init系統。實話說我并沒有關于systemd獨到的見解,只是讀過Lennart等人的一些文章。對于CoreOS來說,將systemd作為新的Linux發行版的init系統的是不明智的。另外,CoreOS已經獲得了我的信任,我對此深信不疑。你可能會拋出 btrfs與我爭論,但是, 那個會很快消失,我希望它會被修復,或者被其他可靠的方案替換。畢竟穩定性比功能更重要。
好吧,讓我們回到問題上來。其中systemd做的或者說能夠做的事情多是進程管理。你可能會認為,systemd解決這個問題的方式,多少有些重疊了服務、進程管理的概念,并且將一些原本能在PID1之外很簡單的任務復雜化了,但因為CoreOS是systemd的忠實用戶,如果使用其它工具來實現反而顯得奇怪。
此外,據Brandon介紹,Rocket的最初實現使用systemd-nspawn的原因是他們想用systemd,Systemd-naspawn 已經實現,而且正在做他們想做的東西,所以它有助于項目的開始。坦率地說,在0.1.1版本,我并不關心他們使用的技術,沒準以后都會變的,因為Rocket的設計是可插拔的。如果你不喜歡systemd-nspawn,可以用你自己的stage1實現,Rocket已經提供了詳細的命令行參數。
另外需要指出的是,那些認為想使用Rocket,就必須運行systemd的人就完全錯了。Rocket根本不需要systemd。它也能與其它init系統,如SysV或upstart配合工作。我在upstart上測試了Rocket,沒有遇到任何問題。Rocket僅僅是“重用”了systemd和systemd-nspawn,處理stage1和stage2。
App Container
有些人可能還沒有準確地理解“App Container Specification”。他們一直在說systemd,并說Docker是如何好,不需要在容器中用systemd運行進程。Docker通過后臺進程管理單進程的容器。Docker后臺進程未被寫成一個進程管理工具,當你的容器停止時,這種設計的弊端就會顯現出來。你最終要通過主機或者容器中的進程管理工具來應付它。如果你還沒有經歷過這樣的事,要么你可能是幸運的,又或者沒有在環境中運行大量的容器。
我們需要進程管理,或進程管理提供的某些功能。如果讀過“App Container Specification”,你會理解這點的。我將其中一部分摘錄如下:
容器執行一個或多個應用程序,共享PID namespace、network namespace、mount namespace、IPC namespace和UTS namespace。執行之前,每個應用程序將開始轉為(比如chroot)自己特有的讀寫根文件系統。容器的定義是,包含一系列應該在一起啟動的應用,以及應用與整個容器的隔離器。
上面明確提到了幾個進程共享Linux的命名空間。換言之,Kubernetes的Pod與以上對容器的定義很像,我不知道這是否與CoreOS正在積極參與Kubernetes的開發有什么關系。但Kubernetes Pod是一組容器,而不是容器中的一組進程。這讓你能從多個Docker鏡像組成一個Pod中獲益。這是App Container Specification定義了 依賴關系的地方,所以你的容器可以依賴于其他容器,因此通過 Stage0創造的最終容器runtime可能是 這樣的。
現在,你已經在容器中運行多個進程,其中一些可能是后臺進程,并且可能需要被監督,你需要一個進程管理器。至今我用過最好的管理器是runit,但話說回來,當你已經積累了大量關于systemd的經驗時,你為什么會想要寫runit腳本或使用其他管理器?如果我是CoreOS,也會做出一樣的決定——systemd。
Docker和命名空間
現在,讓我們回到Docker。Docker一直倡導一個容器運行一個進程。總的來說,我同意這一點,因為Linux容器主要是為了實現主機的進程隔離,而每個容器運行一個進程,會給你帶來更多的靈活性和復合型,獨立的更新、回滾等,操作更加簡單。然而,當你創建一個新的Docker容器或事實上LXC容器,容器被重新分配一套由libcontainer提供的全新的Linux命名空間。實話說,我覺得這有點浪費。于Docker還挺有意義,因為你要在一個容器中運行一個單獨的進程,并且如果你想提供更通用的進程環境,來覆蓋大多數的用例,你可能需要libcontainer高效提供的大量可用命名空間。
只為一個進程創建一組命名空間,增加了內核大量的額外管理工作。如果你的主機上運行了很多的容器,可能會出現內核某些方面的瓶頸。你可能會說開銷很小,但是為什么非要過度占用內核呢?
因此,為了節省開銷,可以共享進程之間的命名空間。但是有個問題,如果你開始共享命名空間,并且創建它的容器已經終止,它會刪除共享命名空間的所有的進程。Kubernetesde在設計Pod時,就考慮到這個問題了。 Kubernetes Pod中第一個被創建的容器,會被從internal/24 VLAN中分配一個IP地址,該IP地址也被Pod內共享一個network namespaces的容器共享。
你可以看到這里微妙之處。每當“網絡”創建的容器停止時,他會撤銷Pod中所有的其它容器,因為沒有可以共享的命名空間了,所以需要從頭創建新的Pod,重新分配IP。更糟糕的是,你的連接也沒了。所以,當你的容器停止后,不能自動重啟它們。我相信通過觀察Docker銷毀容器的過程,可以找到解決辦法,但是,那有些繞。所以,如果你想要在Docker容器中運行多個進程,你會需要一個進程管理工具。
監管日志
最后,講一下日志。日志由管理進程負責。通常這個進程管理器通過捕獲進程的stdout/stderr,并將其記錄到一個日志。“App Container Specification”上有關日志的說明如下:
應用程序應登錄到stdout和stderr。容器執行程序負責捕捉和不斷輸出。
對于CoreOS來說,systemd似乎是一個顯而易見的選擇。Runit在這方面做得很好,但這又回到我已經在前面提到的,專業上來講,這是不必要的額外工作。
Docker的做法是,把近六個月的日志記錄到日志插件prosposal文檔中。雖然還未實現,但考慮到這是由Michael Crosby提出的,我對它有信心。
用戶體驗和使用經驗
大家對Rocket的另一個不滿在于用戶體驗。但請記住,Rocket最新發布的版本是0.1.1。你知道第一輛車的樣子嗎?它看起來是這樣的。這當然不是最好的用戶體驗,然而這是朝著法拉利和保時捷的第一步.
但同樣也是最重要的是,Rocket是App Container Specification的實現,不會強加給你任何東西。同樣,Dockerfiles、Docker daemon以及其它你想要的實現,都只能靠你自己了。甚至是Stage1!你想讓Docker作為管理器?破解它,并把它作為參數傳遞給rkt run,成為一個Stage1進程。我都能想象在未來,CoreOS很可能會實現一些很棒的工具,甚至提升Ops 和Devs的用戶體驗。但那些工具可能會作為單獨的項目,而不是Rocket的核心部分。在這一點上我認為最重要的是項目的穩定。
結束語
我要十分明確地說,我喜歡Docker,并且一直在關注Docker。這篇博文并不是在討論Docker或Rocket好與壞。大多數人都是沒有讀過“App Container Specification”,才會總是要比較這兩者的好壞。
最后,強烈建議你去了解一下Docker和Rocket。如果你喜歡用C編碼,你也應該試試LXC或其它類似的技術。還有很多事情可以做,很多機會,讓你成為目前這個行業巨變的一部分!