英文原文:Docker: Lightweight Linux Containers for Consistent Development and Deployment
使用Docker容器——輕量靈活的VM同類,來接管“依賴地獄”。學習Docker是如何基於LXC技術,通過把應用包裝在容器里來使應用具有移植性和獨立性。 想象一下可以輕松地把應用和它的依賴打包,然后在其他的開發、測試和生產環境上平滑的運行。這就是開源Docker項目的目標。盡管它現在還沒正式到生產階段,最新的發布(本篇文章編寫時是0.7.x)使得Docker實現這一偉大目標又近了一步。 |
![]() Ley
|
Docker容器試圖解決“依賴地獄”問題。現代的應用通常從已存在的組件組合而來,並且依賴其他服務和應用。比如,你的Python應用可能使用Postgre所為一個數據存儲,用Redis緩存以及使用Apache作web服務器。每個這些組件都附帶自身的一些依賴,這些依賴可能與其他組件產生沖突。通過打包每個組件及其依賴,Docker容器解決以下問題:
|
![]() jimmyjmh
|
Docker容器:一點背景2013年初,Docker在dotCloud—一個平台即服務的、以雲計算為中心的公司,以一個開源項目的形式誕生。Docker是該公司已經開發的用來在數千台服務器上運行雲業務的一個自然擴展技術。它是用Go語言編寫的,Go語言是由谷歌開發的一種基於C語言且語法松散的靜態類型編程語言。快速發展了6到9個月,這家公司聘請了一個新的CEO,加入了Linux基金會,將公司名改為Docker,並且宣布將工作重心轉移到Docker容器及其生態系統的開發。作為Docker容器的受歡迎程度進一步說明,在寫這篇文章的時候,它已經在GitHub上被 Star 8985次並 Fork1304次。圖1表明了Docker容器在谷歌搜索持續上升的受歡迎度。隨着Docker公司發布了第一個版本容器的產品部署以及廣泛的社區知道了Docker容器的有用性,預計過去12個月的波形圖將會在未來12個月內相形見絀。 圖1. 過去12個月Docker軟件在谷歌搜索上的趨勢圖 |
![]() jimmyjmh
|
在引擎罩下Docker運用了一些強大的內核級技術並讓我們觸手可及。容器虛擬化的概念早在幾年前已經出現,但通過提供一個簡單的工具集和統一的API接口管理一些內核級技術,如LXCs(Linux容器)、cgroups和一個寫復制文件系統,Docker已經創建了一個比其各部件更好的工具。它就是一個潛在的用於開發運營商、系統管理員和開發者的規則轉換器。 Docker提供工具使得利用容器創建和操作盡可能簡單,容器沙箱相互處理。你可以暫時把一個容器當成一個輕量級的虛擬機。 |
![]() jimmyjmh
|
Linux容器和LXC,一個用於Linux容器的用戶空間控制程序包,是組成Docker的核心,LXC使用內核級命名空間將主機和容器相互隔離。用戶命名空間將主機和容器的用戶數據庫分離,這樣保證了容器的root用戶沒有主機的root權限。程序命名空間僅負責顯示和管理程序在容器中,而非在主機運行。而且網絡命名空間提供自己的網絡設備和虛擬IP地址給容器。 LXC提供的另一個組件是控制組(cgroups)。命名空間負責主機與容器之間的隔離,而控制組實現資源核算和限制。當允許Docker限制被一個容器消耗的資源:如內存、磁盤空間和輸入輸出時,控制組也會輸出大量與之相關的指標。這些指標使Docker能夠監控容器內各個進程的資源消耗並確保每個進程只獲取可用的公平共享資源。 |
![]() jimmyjmh
|
除了以上組件,Docker一直在用AuFS(高級多層次統一文件系統)作為容器的文件系統。AuFS是一個能透明覆蓋一或多個現有文件系統的層狀文件系統。當一個進程需要修改一個文件時,AuFS創建該文件的一個副本。AuFS可以把多層合並成文件系統的單層表示。這個過程稱為寫復制。 真正酷斃的是,AuFS允許Docker把某些鏡像作為容器的基礎。例如,你可能有一個可以作為很多不同容器的基礎的CentOS系統鏡像。多虧AuFS,只要一個CentOS鏡像的副本就夠了,這樣既節省了存儲和內存,也保證更快速的容器部署。 |
![]() jimmyjmh
|
使用AuFS的另一個好處是Docker的版本容器鏡像能力。每個新版本都是一個與之前版本的簡單差異改動,有效地保持鏡像文件最小化。但,這也意味着你總是要有一個記錄該容器從一個版本到另一個版本改動的審計跟蹤。 傳統上,Docker依賴AuFS提供了寫復制存儲機制。然而,最近添加的一個存儲啟動API可能降低這種依賴。最初,可用的存儲驅動有三種:AuFS、VFS和設備映射器-與紅帽合作的產物。 自版本0.7起,Docker就與所有Linux發行版協作。然而,它並沒有兼顧大部分非Linux系統,如Windows和OS X。在那些操作系統上使用Docker的推薦方式是,用Vagrant在VirtualBox上提供一個虛擬機。 |
![]() jimmyjmh
|
容器VS.其他虛擬化類型那容器到底什么是以及它與基於管理程序的虛擬化的區別是什么?簡單地說,容器在操作系統層面虛擬化,而基於管理程序的虛擬化在硬件層面。效果類似,但區別很重要,這也是我花了點時間探索它們的差異和由其產生的差異和權衡的原因。 虛擬化: 容器和虛擬機(VMs)都是虛擬化工具。在虛擬機上,一個管理程序使各個孤立的硬件可用。通常,這包括兩種類型的管理程序:類型1直接運行在硬件裸金屬片上,而類型2則在客戶操作系統上作為軟件附加層運行。開源的Xen和VMware的ESX是類型1 的例子,類型2的實例包括Oracle的開源VirtualBox和VMware服務器。雖然相比Docker容器而言,類型1是個更好的候選,但我在文章的其他部分並不區分這兩種類型。 與此相反,容器構造操作系統中可用的受保護部分-它們有效地虛擬化操作系統。運行在同一個操作系統上的兩個容器不知道它們在共享資源,因為彼此擁有自己的抽象網絡層和進程等等。 |
![]() jimmyjmh
|
操作系統和資源由於基於hypervisor的虛擬化僅僅提供了對硬件的訪問,因此你還需要安裝操作系統。這樣就會運行多個完整的操作系統,每個虛擬機上運行一個,這將快速地吃完服務器上的諸如內存(RAM)、CPU和帶寬等資源。 容器運行在操作系統之上,把正在運行的操作系統當作自己的主機環境。它只運行在這樣的空間上:這些空間是主機操作系統的一部分,而且各個容器使用的空間相互獨立。這會帶來兩個非常鮮明的優點。第一個優點是更高效的使用資源。如果一個容器不執行任何操作,那么它就不會耗盡資源,而且容器可以調用自己所在的主機操作系統以實現其所需要的部分或者全部功能。第二個優點是容器成本低,因此可以快速地創建和刪除容器。容器不需要對整個操作系統進行重啟或者關閉。容器僅僅需要的終止運行在自身獨立空間的進程。因此啟動和停止容器更像是啟動和退出某個應用,因此啟動和停止就非常快。 |
![]() 幾點人
|
圖2展示了兩種類型的虛擬機和容器 圖2.虛擬機和容器 獨立的性能和安全Docker容器里所執行的進程與宿主機操作系統上運行的進程或者運行在其它Docker容器里的進程是相互獨立的。不過,所有的進程都是運行在相同的內核里。Docker使用LXC來給每個容器提供獨立的命名空間,內核里的這項技術已經具有5年多的歷史了,已經十分成熟。另外,容器還使用了控制組,Linux內核里的這項技術比LXC的歷史更長,它對資源進行審核和限制。 |
![]() 幾點人
|
Docker服務進程本身還是一個潛在的攻擊載體,這是因為它目前只能以root權限運行。對LXC和Docker的改進都應當允許以非root權限運行容器,而且可以用另外一個用戶運行Docker服務進程。 雖然容器所使用的這種類型的隔離總的來說非常強大,然而是不是像運行在hypervisor上的虛擬機那么強壯仍具有爭議性。如果內核停止,那么所有的容器就會停止運行。虛擬機具有優勢的領域是它十分成熟,而且廣泛的應用在生產環境中。相比之下,Docker和它的支撐技術幾乎沒有任何行動。特別是Docker每天都進行大量的修改變化,而且我們大家都知道變化是安全的天敵. |
![]() 幾點人
|
Docker和虛擬機-亦敵亦友上面我們一直在對Docker和虛擬機進行比較,現在該看看這兩種技術彼此在哪些方面是真正互補的。Docker在虛擬化的環境下運行的非常好。很顯然,你不需要對各個虛擬主機的每個應用或者組件進行封裝。而且假定給你一台Linux虛擬機,你就能夠很容易地部署上Docker容器。這也就是在非Linux系統,比如OS X和Windows上運行Docker的官方安裝方式是在Vagrant的協助下安裝基於Ubuntu虛擬機的Precise64不讓你感到吃驚的原因所在。http://www.docker.io站點有詳細並且簡單的指令。 首先,虛擬化和容器在某些方面表現的非常相似。一開始,這讓你覺得容器就是非常輕量的虛擬機。然而,隨着你對容器的認識,你對容器的理解就會有微妙的並且是重大的不同。Docker在容器最擅長的領域即輕量級應用的打包和部署方面都能充分發揮容器的長處。 |
![]() 幾點人
|
Docker倉庫Docker殺手級特性之一就是能夠快速的查找、下載和啟動由其他開發者創建的容器映像。存儲映像的地方稱為注冊中心。Docker有限公司提供一個公共的注冊中心,這個注冊中心也稱為索引中心。你可以把這個注冊中心和Docker客戶端看作與Node的NPM,Perl的CPAN或者Ruby的RubyGems等同。 除了可以用來創建Docker容器的各種基本映像外,公共的Docker注冊中心還提供即刻即可運行的軟件映像,其中包括數據庫、內容管理系統、開發環境和Web服務器等等。默認情況下Docker命令行客戶端搜索的是公共的注冊中心,不過,也可以維護私有的注冊中心。如果要發布含有專有知識產權代碼的或者僅公司內部使用的組件的映像,那么注冊中心就是一個很好的選擇。把映像上傳到注冊中心就像下載一樣容易。只要求你創建一個賬戶,而且這一切都是免費的。最后,Dcoker有限公司的注冊中心還有Web界面,方便對映像進行搜索、讀取、評論和推薦(即“標記星號”)。映像使用起來出奇的容易,我鼓勵你這篇文檔資源一小節里的鏈接,開始瀏覽映像。 |
![]() 幾點人
|
手把手教你使用DockerDocker是有單個二進制文件組成的,這個二進制文件可以以三種方式來運行。第一種,它可以作為管理容器的服務進程運行。服務進程向外提供既可以進行本地訪問也可以進行遠程訪問的基於REST風格的API。越來越多的客戶端數據庫可與服務進程API進行通信,其中包括Ruby,Python,JavaScript(Angular和Node),Erlang,Go和PHP提供的客戶端庫. 客戶端庫大多數情況下都是通過編程來來訪問服務進程的,不過更經常使用的情況則是通過命令行提交指令。這也就是運行Dcoker二進制文件的第二種方式,即通過命令行客戶端訪問基於REST風格的服務進程。 第三種方式,Docker二進制文件可以運行為訪問遠程映像倉庫的客戶端。生成容器文件系統的映像被稱作倉庫。用戶可以下載別人提供的映像,還可以上傳自己的映像到注冊中心,從而共享這些映像。注冊中心用來收集,羅列和組織這些倉庫。 |
![]() 幾點人
|
讓我們看看實際中運行Docker的這三種方式。在下面的例子里,你將搜索Docker倉庫,查找MySQL映像。因此你找到所喜歡的映像,然后下載它,接着告訴Docker服務進程運行對應的命令(MySQL)。你所做的這些操作都是通過命令行進行的。 圖3.下載Docker映像並啟動容器 一開始,先運行docker search mysql命令,這條命令將顯示公共Docker注冊中心里匹配關鍵詞"mysql"的映像列表。我確定這條命令可以正常運行,接着使用命令docker pull brice/mysql下載"brice/mysql"映像。你可以看到Docker不僅僅下載的是你所指定的映像,而且還可以下載依賴這個包所建立的其他映像。輸入docker images命令,將會羅列出目前本地具有的所有映像,其中包括了"brice/mysql"映像。使用-d選項啟動容器,它將會脫離當前運行的容器之外運行一個容器,此時,你已經在一個容器里運行了MySQL了。你可以使用docker ps命令來驗證,這條命令經羅列出運行的容器,而不是羅列出映像。在命令行的輸出里,你還能看到MySQL服務偵聽的端口號,默認是3306。 |
![]() 幾點人
|
然而,在知道MySQL運行在容器內部情況下,你該怎樣連接到MySQL呢?切記:每個Docker容器有自己的網絡接口。你需要確定的是mysqld服務器進程運行在哪個IP地址和端口上。運行docker inspect <imageId>命令,它將給我們提供大量的信息。不過,由於你所需要的僅僅是IP地址,所以當你使用容器的哈希值對容器進行查看的時候,你就可以抓取到IP地址,即運行docker inspect 5a9005441bb5 | grep IPAddress。現在你可以通過給標准的MYSQL CLI客戶端指定主機地址和端口選項來連接了。當你使用完MySQL服務器后,你可以使用命令docker stop 5a9005441bb5關閉這個容器了。 我們使用了7條命令查找、下載、啟動運行MySQL服務器的Docker容器以及使用完后關閉這個容器。在這個過程中,你不必擔心與已安裝軟件之間存在的沖突,也不必擔心MySQL的版本有什么不一樣,或者存在哪些包依賴。你使用了7條不同的Docker命令:search、pull、images、run、ps、inspect和stop,不過,Docker客戶端實際上有33條命令。你可以通過命令運行docker help命令或者查找在線手冊來查閱全部命令列表。 |
![]() 幾點人
|
在上面例子里進行Docker操作之前,我就提到了客戶端與服務進程和Docker注冊中心之間的通信是通過基於REST的Web服務而進行的。這就隱含地告訴你可以使用本地Docker客戶端與遠程的服務進程通信,從而可以有效地管理遠端服務器上的容器了。Docker站點上對Docker服務進程、注冊中心和索引的API都有很好的文檔,並且舉例給予了說明(見資源一節)。 Docker的工作流程有多種方式可以把Docker引入到開發和部署過程里。讓我們看看演示工作流程的例子,如圖4。我們設想一個公司的開發人員可能運行安裝了Docker的Ubuntu。他可能從公共注冊中心下載映像或者上傳映像到公共注冊中心,並在這個映像的基礎上安裝自己的代碼或者公司專有知識產權的軟件,還要生成可上傳到公司私有注冊中心的映像。 |
![]() 幾點人
|
在這個例子里,公司的產品質量測試環境運行的Centos和Docker。它也從公共或者私有的注冊中心下載映像,然后再環境更新的時候啟動各種容器。 最后,為了方便擴展和伸縮,公司把生產環境部署在雲中,即部署在亞馬遜的WEB服務上(AWS)。亞馬遜Linux上也運行了管理不同容器的Docker。 注意:上面的所有三個環境運行着不同版本的Linux,但這三個環境都與Docker兼容。而且每個環境都運行着不同的容器組合。然而,由於每個容器都把自己的依賴同其他容器分離開來,因此不存在任何沖突,所有容器都平安地並存着。 圖4.使用Docker進行軟件開發的工作流程舉例 |
![]() 幾點人
|
認識到Docker提供的是一個以應用為核心的容器模型是非常重要的。也就是說,容器運行的是單獨的應用或者服務,而不是許多應用或者服務。我們已經知道:創建和運行容器非常快而且消耗的資源也很少。由於你所使用的系統遵循單一責任法則,而且每個容器運行一個主進程,所以系統組件之間就是松耦合的。基於這個理念,我們自己就可以創建屬於自己的,可以啟動容器的映像了。 創建新的Docker映像在前面的例子里,你已經通過命令行與Docker進行交互了。然而在創建映像的時候,更常見的是創建進行自動構建過程的"Dockerfile“。Dockerfile是簡單的文本文件,它描述的是構建過程。你可以對Dockerfile實行版本控制,這樣就可以就可以非常完美地重復創建映像了。 |
![]() 幾點人
|
在接下來的例子里,我們將看看名字為PHP Box的Dockerfile(見代碼清單1)。 代碼清單1.PHP Box
接下來我們仔細看看上面的Dockerfile都做了哪些事情。Dockerfile的語法是命令關鍵字,其后緊跟着是該命令的參數。通常命令關鍵字是大寫的。注釋部分是以#開頭的。 FROM命令向你指明了所使用的基本映像。它必須是Docker文件的第一條命令。在這個例子里,你所做的工作都是建立在剛才新建的基本映像Centos上的。很顯然,MAINTAINER命令則羅列出了維護這個Dockerfile的人員。RUN命令執行一條命令,並給出運行結果映像,因此它新創建了一個映像。這個Dockerfile里的RUN命令獲取其他軟件倉庫的配置文件,然后使用Yum安裝curl、git、wget、unzip、httpd、php-mysql和yum-utils。我們可以把這幾個yum install命令合並成一條RUN命令,從而可以避免連續多次提交。 |
![]() 幾點人
|
接下來的 最后一條命令 在命令行里輸入 這個構建過程下載了基本映像,緊接着安裝Apache httpd以及與其相關的所有依賴。完成安裝之后,將返回一個用來識別新創建映像的哈希值。這個值與你在前面啟動MySQL容器時所使用的值類似。你可以使用php_box標簽來運行Apache和PHP映像,命令如下: |
![]() 幾點人
|
下面我們將以很簡短例子結束這篇文章,這個例子說明在已有的映像基礎上如何簡單地創建新映像:
第二個Dockerfile比第一個要簡短,實際上它僅僅包含了兩條真正起作用的命令。首先通過 |
![]() 幾點人
|
總結輕量級應用及其依賴打包和部署工具Docker的出現是令人激動的事情,Linux社團很快采納了它,而且還試着在生產環境中使用。例如,Red Hat在12月就宣布將在即將發布的Red Hat Linux企業版7里支持Docker。然而,Docker仍然是一個年輕的項目,而且正在飛速發展中。看到Docker項目發布1.0版本將是多么令人激動的時刻,1.0版本將是官方批准的用於生產環境的第一個版本。Docker依靠的現有的技術,其中一些技術已經具有十幾年的歷史了,但這並不意味着它沒有任何創新。我希望這篇文章能給你足夠多有關Docker的信息,並鼓勵你下載Docker,親自試一下。 |
![]() 幾點人
|
Docker最新進展在這篇文章發布的時候,Docker團隊發布了版本0.8。最新的發布增加了對Mac OS X的支持,它有兩個組件組成。客戶端可以運行在OS X操作系統上,而Docker服務進程則運行在由boot2docker管理的輕量級VirtualBox虛擬機上,其中也包含命令行客戶端。由於底層技術,比如LXC和命名空間得不到OS X的支持,所以這么做就是必然的選擇。我認為大家都在期待有類似的方案能用在其他平台上,比如Windows上。 版本0.8還引入了幾個新的構建特性,並試着提供對二叉樹型文件系統的支持(BTRFS)。BTRFS是另一個即寫即拷貝的文件系統,另外BTRFS存儲驅動用來替代AuFS驅動。 尤其值得一提的是: Docker 0.8修補了許多程序漏洞,強化了性能。總的提交數量說明Docker團隊為了生成可用於生產環境的發布版1.0所做的努力。因為Docker團隊是每個月進行提交的,我們期望在4-5月份這個時間窗口發布1.0版本。 資源Docker主站點: https://www.docker.io Docker遠端應用API:http://docs.docker.com/reference/api/docker_remote_api/ 注解:由於翻譯完成時Docker Index API已經更改為Docker Hub API,因此就采用的新的API。 |
目前來看,Docker至少有以下應用場景:
1)測試:Docker 很適合用於測試發布,將 Docker 封裝后可以直接提供給測試人員進行運行,不再需要測試人員與運維、開發進行配合,進行環境搭建與部署。
2)測試數據分離:在測試中,經常由於測試場景變換,需要修改依賴的數據庫數據或者清空變動 memcache、Redis 中的緩存數據。Docker 相較於傳統的虛擬機,更輕量與方便。可以很容易的將這些數據分離到不同的鏡像中,根據不同需要隨時進行切換。
3)開發:開發人員共同使用同一個 Docker 鏡像,同時修改的源代碼都被掛載到本地磁盤。不再因為環境的不同而造成的不同程序行為而傷透腦筋,同時新人到崗時也能迅速建立開發、編譯環境。
4)PaaS 雲服務:Docker 可以支持命令行封裝與編程,通過自動加載與服務自發現,可以很方便的將封裝於 Docker 鏡像中的服務擴展成雲服務。類似像 Doc 轉換預覽這樣的服務封裝於鏡像中,根據業務請求的情況隨時增加和減少容器的運行數量,隨需應變。
具體到Docker技術在測試領域的應用,可以體現在:
1)快速搭建兼容性測試環境
從Docker的鏡像與容器技術特點可以預見,當被測應用要求在各類Web服務器、中間件、數據庫的組合環境中得到充分驗證時,可以快速地利用基礎Docker鏡像創建各類容器,裝載相應的技術組件並快速啟動運行,測試人員省去了大量花在測試環境搭建上的時間。
2)快速搭建復雜分布式測試環境
Docker的輕量虛擬化特點決定了它可以在一台機器上(甚至是測試人員的一台筆記本電腦上)輕松搭建出成百上千個分布式節點的容器環境,從而模擬以前需要耗費大量時間和機器資源才能搭建出來的分布式復雜測試環境。
3)持續集成
Docker可以快速創建和撤銷容器,在持續集成的環境中,可以頻繁和快速地進行部署和驗證工作。