Docker的前生今世和未來

InfoQ - 張曉鵬發表於2014-12-04

Docker – 迄今為止的故事

Docker是一種Linux容器工具集,它是為“構建(build)、交付(ship)和執行(執行)”分散式應用而設計的。作為DotCloud公司的開源專案,其首發版本的時間是2013年的3月份。該專案很快就受到歡迎,這也使得DotCloud公司將其品牌改為Docker(並最終將其原有的PaaS業務出售而專注在Docker上)。Docker 1.0在2014年6月釋出,而且延續了之前每月釋出一個版本的節奏。

其1.0版本標誌著Docker公司認為Docker平臺已經足夠成熟,並可以被應用到產品中(公司及其合作伙伴們還提供了一些需要付費的支援選項)。每月的版本更新顯示出該專案仍在快速發展,比如增加新的特性,解決發現的問題。這個專案成功地將“交付”和“執行”解耦,這樣源自任意Docker版本的映象都可以和其它任意不同版本一起工作(前向和後向均可相容),這就為Docker應用提供了穩定的基礎,以應對快速的變化。

Docker發展成最受歡迎的開源專案可能會被人看作是一種炒作,但其實這個結果還是有堅實的基礎來支撐的。Docker吸引了業界眾多知名大牌廠家的支援,其中包括亞馬遜(Amazon)、Canonical、CenturyLink、谷歌(Google)、IBM、 Microsoft、New Relic、Pivotal、Red Hat和VMware,這使得只要在有Linux的地方,Docker就幾乎隨處可用。除了這些大廠家,許多初創企業也圍繞著Docker來發展,或是將它們的發展方向和Docker更好地結合起來。所有這些合作伙伴(或大或小)驅動著核心專案和周邊生態系統的快速發展。

Docker技術的簡要綜述

Docker利用了一些Linux核心工具,比如cGruops、名稱空間和SELinux來支撐容器之間的隔離。起初Docker只是LXC容器管理子系統的前端,但它在0.9版本中引入了libcontainer,這個原生的Go語言庫提供了使用者空間和核心之間的介面。

Docker容器是基於聯合檔案系統(union file system)的,比如AUFS,利用它可以跨多個容器來共享一些元件,如作業系統映象和安裝的庫檔案。這種分層的方式也被Dockerfile DevOps工具充分利用,這可以快取那些已經成功完成的操作。這就省掉了那些安裝作業系統和應用程式依賴檔案的時間,大幅度加速了測試周期。另外,在容器之間共享庫還能減少記憶體的佔用。

Docker容器是從映象開始的,映象可以是本地建立的、本地快取的,或者是從註冊庫中下載的。Docker公司運營著DockerHub公有註冊庫,上面有官方的資料倉儲,是為不同的作業系統、中介軟體和資料庫而建立的。組織和個人可以在Docker Hub上釋出映象的公有庫,也可以將其註冊成私有庫。由於上傳的映象檔案可以包含任何東西,所以Docker Hub提供了一種自動構建工具(之前被稱為“可信的構建”),映象構建於一個Dockerfile,它作為映象內容的清單。

容器和虛擬機器的對比

Docker容器要比虛擬機器有效率的多,這是因為它們可以共享核心和相關的庫。同樣的原因,容器所佔用的記憶體也要比虛擬機器少得多,雖然虛擬機器利用了RAM的過度承諾技術(RAM overcommitment)。容器也減少了對儲存的佔用,因為部署的容器會共享映象的底層。IBM的Boden Russel已經做了一個基準測試(benchmarking)來對比兩者的不同。

容器也表現出比虛擬機器更低的系統負載,所以同樣的應用,在容器中相比在虛擬機器中,效能通常會相當或者更好。IBM的研究者團隊釋出了一個虛擬機器和Linux容器效能對比的報告可以參考。

容器只是在隔離特性上要比虛擬機器差,虛擬機器可以使用ring-1特權的硬體隔離技術,如Intel的VT-d and VT-x。這種隔離技術可以防止虛擬機器破出(breaking out)和彼此互動。容器沒有任何形式的硬體隔離,這使得它容易受到漏洞的利用。從Shocker(可對Docker進行概念攻擊)的驗證來看,Docker 1.0之前的版本都是很脆弱的。儘管利用Shocker,Docker在1.0版本中修復了一些特定的問題,但Docker的CTO Solomon Hykes仍然表示:“當我們感覺可以輕鬆地宣稱Docker開啟箱(out-of-the-box)可以安全容納非受信的uid0程式(譯者注: root和超級使用者許可權)時,我們一定會明言相告”。Hykes的話從另一方面承認仍然存在一些其他的漏洞和相關的風險,在容器變得可靠之前還有很多工作要做。

對於許多使用者案例,在容器和虛擬機器二者之間選擇其一是種錯誤的二分法。Docker可以在虛擬機器中執行地很好,這可以讓它應用在已有的虛擬化框架中,如私有云和公有云。同樣也有可能在容器中執行虛擬機器,這有點像谷歌在它的雲平臺中使用容器的方式。只要IaaS得到廣泛應用,並可按需提供虛擬機器服務,那麼就有理由期待未來數年容器和虛擬機器的應用可以並存。還有一種可能,即將容器管理和虛擬化技術進行融合以提供一種兩全其美的方法:所以硬體信任錨微虛擬化實現支撐libcontainer能夠與Docker的工具鏈和生態系統的前端進行整合,而使用不同的提供了更好隔離性的後端。微虛擬技術(類似於Bromium的 vSentry和VMware的 Project Fargo)已經應用到桌面環境中為應用提供基於硬體的隔離,所以相同的方法可以使用到libcontainer上,作為Linux核心容器機制的替代技術。

“容器化”的應用

幾乎所有的Linux應用都可以執行在Docker容器裡,並且對程式語言或架構的選擇沒有任何的限制。實際上僅有的限制在於從作業系統的角度來看容器被允許做什麼。即使如此,也可以通過在特權模式下執行容器來降低限制,以大幅度地減少受到的控制(與此對應的是裝載到容器裡的應用風險增加,並可能會導致對主機作業系統的損壞。)

容器從映象開始,反過來映象也可以從執行的容器中得到。從本質上說有兩種方法可以把應用置入到容器中-手動和Dockerfile。

手動構建

手動構建從啟動一個基礎作業系統的容器開始,然後通過互動式終端,用所選Linux相關的包管理器安裝應用程式及其依賴項(dependencies)。Zef Hemel在他的文章“使用Linux容器以支援便捷的應用部署”中提供了這個過程的細緻描述。一旦應用完成安裝,新的容器就可以推送到註冊庫(比如Docker Hub)中或者被匯出成一個tar檔案。

Dockerfile

Dockerfile是對Docker容器建立過程進行指令碼化的系統。每個Dockerfile詳細說明了開始的基礎映象,以及隨後一系列在容器中執行的命令和新增到容器中的檔案。Dockerfile也可以說明容器對外的埠,啟動時的工作目錄和預設執行的命令。用Dockerfile構建的容器可以象手動構建那樣被推送到註冊庫中或者匯出成tar檔案。Dockerfile也可以應用到Docker Hub的自動構建系統中,即在Docker公司的控制下,在系統中根據Dockerfile從頭構建映象,並且這個映象的源對於使用它的任何人都是可見的。

一個程式?

手動構建還是使用Dockerfile來構建映象,考慮的關鍵在於容器剛啟動時只能執行一個單程式。如果容器的服務目的比較單一,比如只執行一個應用伺服器,那麼執行單個程式就沒什麼問題(一些爭論說容器本應該只包括一個程式)。對於那些希望在容器中執行多個程式的情況,管理程式(supervisor process)需要先啟動,這樣它可以接著孵化出其他期望的程式。此時容器中沒有初始的系統,所以任何事都要依賴systemd,不修改新興系統或類似系統都無法工作。

容器和微服務

全面描述使用微服務架構的哲理和益處已經超出了本文的範圍(InfoQ eMag: Microservices中有全面的闡述)。容器仍然是一種方便的方法來繫結和部署微服務的例項。

雖然目前微服務大規模的部署例項還是在(大量)虛擬機器上,但容器提供了一種小規模部署的機會。容器具有共享的記憶體和針對作業系統的磁碟佔用、通用程式碼庫,這也意味著可以非常有效地一起部署多個版本的服務。

連線的容器

一些小的應用適合放在單個容器中,但許多情況下應用需要擴充套件到多個容器。Docker成功催生了一系列新的應用合成工具、編制工具以及平臺即服務實現。絕大多數努力的後面,是希望能簡化從一組相互連線的容器來建立應用的過程。很多工具在擴充套件、容錯、效能管理和部署資產的版本控制方面也提供了幫助。

連線性

Docker的網路能力相當原始,容器中的服務對相同主機的其它容器是可見的,並且Docker可以對映埠到主機作業系統,使得服務在網路中也是可見的。Libchan是Docker官方贊助的連線方法,它提供了Go語言的網路服務庫,類似於channels。在libchan找到自己應用的道路之前,還是有空間留給第三方程式來提供一些補充性的網路服務。例如,Flocker採用了基於代理的方法,這使得服務(連同底層的儲存)可以在主機間進行遷移。

合成

Docker有個原生的機制來連線容器,它所依賴的後設資料可以被傳送到相關的容器中,這些後設資料被用做環境變數和主機入口。類似Fig和geard這樣的應用合成工具,可以在單檔案中表達這種依賴關係圖,這樣多個容器就可以互相配合成為一個系統。CenturyLink的Pannamax合成工具在底層採用了和Fig、geard相似的方法,但加入了基於Web的使用者介面,並且直接和GitHub進行了整合,這樣就可以分享合成後的應用了。

編制

編制系統包括Decking、New Relic公司的Centurion和谷歌公司的Kubernetes,它們的目標都是幫助實現容器的部署和它的生命週期管理。也有很多基於Apache Mesos系統(特別是它為應用長期執行設計的Marathon框架)的商業化實現(比如Mesosphere),它們可以和Docker一起使用。通過提供在應用需求和底層架構間的抽象(例如,需求表達為CPU核數和記憶體大小),編制工具提供了兩者之間的解耦,這種設計簡化了應用開發和資料中心的運維。還有各種各樣的編制系統,這主要是因為之前許多內部系統工具冒出來了,它們之前開發出來是用於管理容器大規模部署的。例如Kubernetes就是基於谷歌的Omega系統,而Omega系統是用來管理整個谷歌雲環境中的容器。

合成工具和編制工具功能上會有部分的重合,所以使用時它們彼此可以作為補充。例如Fig可以用來描述容器功能上如何互動,同時Kubernetes pods(譯者注:pods可以被看成一個容器組)可以用來提供相關的監測和擴充套件功能。

平臺即服務

有很多原生於Docker的PaaS實現,例如Deis和Flynn,已經體現出Linux容器在支援開發靈活性上的強大優勢(而不是那些自以為是給定的一套語言和框架)。其它的雲平臺如CloudFoundry、OpenShift和Apcera Continuum,已經採用整合基於Docker相關功能到現有系統中的技術路線,這樣基於Docker映象(或者是建立它們的Dockerfiles)的應用在部署和管理的同時,仍然可以使用之前系統支援的語言和框架。

所有的雲

由於Docker可以執行在任何有合理資料核心的Linux虛擬機器上,所以它可以執行在很多IaaS提供的雲上。許多大的雲提供商宣佈了對Docker和它的生態系統的附加支援。

亞馬遜已經引入Docker到它的彈性豆莖(Elastic Beanstalk)系統中(這是在IaaS之上的編制服務)。谷歌使Docker成為可管理的虛擬機器(managed VMs),它提供了在應用程式引擎的PaaS和計算引擎的的IaaS之間的中間站。微軟和IBM也都宣佈了基於Kubernetes的服務,這樣在他們的雲上就可以部署和管理多容器應用了。

為了給當前使用的廣泛多樣的後端提供一致性的介面,Docker團隊引入了libswarm,它會被整合到多數的雲和資源管理系統中。Libswarm一個明確的目標是“通過切換服務來源的辦法來防止供應商鎖定”。這通過呈現一組一致性的服務(以及相關的API)來完成,這些服務會附著到特定後端的實現上。比如Docker伺服器服務會呈現Docker遠端API到本地Docker命令列工具中,這樣眾多的服務提供者就可以管理相關的容器了。

基於Docker的新的服務型別仍在起步階段。雖然位於倫敦的果園實驗室(Orchard labs)可以提供Docker容器的託管服務,但Docker公司表示,在它收購果園實驗室後相關服務不會被置於優先位置。Docker公司還向cloudControl公司出售了其先前的DotCloud PaaS 業務。如OpenVZ之類基於舊的容器管理系統的服務已經比較普通了,所以在一定程度上Docker需要向主機提供商們證明其價值。

Docker和它的發行版

Docker已經成為主流Linux版本的標準特性,比如Ubuntu, Red Hat Enterprise Linux (RHEL) 和CentOS。遺憾的是這些Linux發行版與Docker專案在步調上並不一致,從而導致這些Linux發行版中Docker的版本比當前能用的老得多。例如Ubuntu 14.04的Docker版本是0.9.1,並且在Ubuntu升級到14.04.1時Docker的版本也沒有變(當時Docker專案版本是1.1.2)。在官方庫中還有一個名稱空間衝突的問題,因為Docker也是KDE系統托盤的名字,所以在Ubuntu 14.04中Docker包和命令列工具起了另一個名稱“docker.io”。

在企業級Linux發行版中情況也沒有太大的不同,CentOS 7中Docker的版本是0.11.1,這是Docker公司宣佈1.0版本產品準備就緒之前的一個開發版。Linux發行版使用者如果要使用最新的版本以保證穩定性、效能和安全,那麼按照Docker安裝指導操作並使用Docker公司提供的庫,要比使用Linux發行版中的版本要好得多。

Docker的到來也催生了新的Linux發行版,比如CoreOS和Red Hat的Project Atomic,它們設計成能執行容器的最小環境系統。這些發行版相比傳統Linux發行版本,有比較新的核心和Docker版本,對記憶體和硬碟的佔用也比較小。新的發行版本中也有一些新的工具用來管理大容量的容器部署,比如fleet負責分散式系統啟動,而etcd負責後設資料管理。這些Linux發行版針對自身的分散式更新採用了新的機制,這樣就可以使用最新版本的核心和Docker了。這表示對Docker應用的其中一種效果的認可,那就是把注意力重心從發行版和包管理解決方案轉到Linux核心(和使用核心的Docker子系統)上來。

儘管新發行版(譯者注:類似於CoreOS)可能是Docker最佳的執行方式,但支援容器的傳統發行版和它們的包管理工具仍然非常重要。Docker Hub上提供了 Debian、Ubuntu和CentOS的正式映象,還有“半官方”Fedora的映象庫。RHEL沒有在Docker Hub上的映象,因為它們是直接由Red Hat發行的。這意味著Docker Hub上的自動構建機制只對那些純開源的Linux發行版本可用(並願意信任那些起源於Docker公司團隊策劃的基礎映象)。

Docker Hub同時整合了源控制系統,如GitHub和Bitbucker,用來自動構建包管理器。包管理器可以在映象構建過程中生成構建規格(在Dockerfile中)和最終構建映象之間的複雜關係。構建過程的結果具有不確定性,這不是Docker的特定問題,而和包管理器如何工作相關。今天構建的是這個版本,在另一個時間構建可能會得到一個新的版本,這也就是包管理器需要更新功能的原因。容器抽象(即較少關注容器中的內容)與容器擴充套件(因為輕量級資源利用率)可能會使這種不確定性成為Docker相關的痛點。

Docker的未來

Docker公司已經建立了清晰的道路,即發展核心能力(libcontainer)、跨業務管理(libswarm)和容器間訊息(libchan)。與此同時,通過收購果園實驗室(Orchard labs),Docker公司表達了利用自身生態系統的意願。但是,這不僅僅關注Docker公司,這個專案的貢獻者還來自於一些大牌公司,如谷歌、IBM和Red Hat。在仁慈的獨裁者、技術長Solomon Hykes的掌舵下,Docker公司和Docker專案的技術領先有著明確的聯絡。在專案初始的18個月裡,它已經顯示出通過自己的輸出來快速前進的能力,並且沒有減弱的跡象。

許多投資者正著眼於十年前VMware公司ESX/ vSphere平臺的功能矩陣,試圖找出已經由虛擬機器普及而驅動的企業預期和現有Docker生態系統之間的差距(和機會)。在網路儲存和細粒度的版本管理(用於容器中的內容)領域,現有Docker生態系統做得並不好,這就為初創企業和在職人員提供了機會。

隨著時間的推移,虛擬機器和容器(Docker中的“執行”部分)之間的區別很可能變得不再那麼重要,這將使注意力轉到“構建(build)”和“交付(ship)”方面。這些變化將使 “Docker會發生什麼?”的問題,相比“Docker會帶給IT業什麼?”的問題,變得更不重要。

相關文章