8 個你可能不知道的 Docker 知識

譯者: 大舒發表於2015-05-06

自從上世紀 90 年代硬體虛擬化被主流的技術廣泛普及之後,對資料中心而言,發生的最大的變革莫過於容器和容器管理工具,例如:Docker。在過去的一年內,Docker 技術已經逐漸走向成熟,並且推動了大型初創公司例如 Twitter 和 Airbnb 的發展,甚至在銀行、連鎖超市、甚至 NASA 的資料中心都贏得了一席之地。當我幾年前第一次直到 Docker 的時候,我還對 Docker 的未來持懷疑的態度,我認為他們是把以前的 Linux 容器的概念拿出來包裝了一番推向市場。但是使用 Docker 成功進行了幾個專案 例如 Spantree 之後,我改變了我的看法:Docker 幫助我們節省了大量的時間和經歷,並且已經成為我們技術團隊中不可或缺的工具。

GitHub 上面每天都會催生出各式各樣的工具、形態各異的語言和千奇百怪的概念。如果你和我一樣,沒有時間去把他們全部都測試一遍,甚至沒有時間去親自測試 Docker,那麼你可以看一下我的這篇文章:我將會用我們在 Docker 中總結的經驗來告訴你什麼是 Docker、為什麼 Docker 會這麼火。

Docker 是容器管理工具

Docker 是一個輕量級、行動式、與外界隔離的容器,也是一個可以在容器中很方便地構建、傳輸、執行應用的引擎。和傳統的虛擬化技術不同的是,Docker 引擎並不虛擬出一臺虛擬機器,而是直接使用宿主機的核心和硬體,直接在宿主機上執行容器內應用。也正是得益於此,Docker 容器內執行的應用和宿主機上執行的應用效能差距幾乎可以忽略不計。

但是 Docker 本身並不是一個容器系統,而是一個基於原有的容器化工具 LXC 用來建立虛擬環境的工具。類似 LXC 的工具已經在生產環境中使用多年,Docker 則基於此提供了更加友好的映象管理工具和部署工具。

Docker 不是虛擬化引擎

Docker 第一次釋出的時候,很多人都拿 Docker 和虛擬機器 VMware、KVM 和 VirtualBox 比較。儘管從功能上看,Docker 和虛擬化技術致力於解決的問題都差不多,但是 Docker 卻是採取了另一種非常不同的方式。虛擬機器是虛擬出一套硬體,虛擬機器的系統進行的磁碟操作,其實都是在對虛擬出來的磁碟進行操作。當執行 CPU 密集型的任務時,是虛擬機器把虛擬系統裡的 CPU 指令“翻譯”成宿主機的CPU指令並進行執行。兩個磁碟層,兩個處理器排程器,兩個作業系統消耗的記憶體,所有虛擬出的這些都會帶來相當多的效能損失,一臺虛擬機器所消耗的硬體資源和對應的硬體相當,一臺主機上跑太多的虛擬機器之後就會過載。而 Docker 就沒有這種顧慮。Docker 執行應用採取的是“容器”的解決方案:使用 namespace 和 CGroup 進行資源限制,和宿主機共享核心,不虛擬磁碟,所有的容器磁碟操作其實都是對 /var/lib/docker/ 的操作。簡言之,Docker 其實只是在宿主機中執行了一個受到限制的應用程式。

從上面不難看出,容器和虛擬機器的概念並不相同,容器也並不能取代虛擬機器。在容器力所不能及的地方,虛擬機器可以大顯身手。例如:宿主機是 Linux,只能透過虛擬機器執行 Windows,Docker 便無法做到。再例如,宿主機是 Windows,Windows 並不能直接執行 Docker,Windows上的 Docker 其實是執行在 VirtualBox 虛擬機器裡的。

Docker 使用層級的檔案系統

前面提到過,Docker 和現有容器技術 LXC 等相比,優勢之一就是 Docker 提供了映象管理。對於 Docker 而言,映象是一個靜態的、只讀的容器檔案系統的快照。然而不僅如此,Docker 中所有的磁碟操作都是對特定的Copy-On-Write檔案系統進行的。下面透過一個例子解釋一下這個問題。

例如我們要建立一個容器執行 JAVA Web 應用,那麼我們應該使用一個已經安裝了 JAVA 的映象。在 Dockerfile(一個用於生成映象的指令檔案)中,應該指明“基於 JAVA 映象”,這樣 Docker 就會去 Docker Hub Registry 上下載提前構建好的 JAVA 映象。然後再 Dockerfile 中指明下載並解壓 Apache Tomcat 軟體到 /opt/tomcat 資料夾中。這條命令並不會對原有的 JAVA 映象產生任何影響,而僅僅是在原有映象上面新增了一個改動層。當一個容器啟動時,容器內的所有改動層都會啟動,容器會從第一層中執行 /usr/bin/java 命令,並且呼叫另外一層中的 /opt/tomcat/bin 命令。實際上,Dockerfile 中每一條指令都會產生一個新的改動層,即便只有一個檔案被改動。如果用過 Git 就能更清楚地認識這一點,每條指令就像是每次 commit,都會留下記錄。但是對於 Docker 來說,這種檔案系統提供了更大的靈活性,也可以更方便地管理應用程式。

我們Spantree的團隊有一個自己維護的含有 Tomcat 的映象。釋出新版本也非常簡單:使用 Dockerfile 將新版本複製進映象從而建立一個新映象,然後給新映象貼上版本的標籤。不同版本的映象的不同之處僅僅是一個 90 MB 大小的 WAR 檔案,他們所基於的主映象都是相同的。如果使用虛擬機器去維護這些不同的版本的話,還要消耗掉很多不同的磁碟去儲存相同的系統,而使用 Docker 就只需要很小的磁碟空間。即便我們同時執行這個映象的很多例項,我們也只需要一個基礎的 JAVA / TOMCAT 映象。

Docker 可以節約時間

很多年前我在為一個連鎖餐廳開發軟體時,僅僅是為了描述如何搭建環境都需要寫一個 12 頁的 Word 文件。例如本地 Oracle 資料庫,特定版本的 JAVA,以及其他七七八八的系統工具和共享庫、軟體包。整個搭建過程浪費掉了我們團隊每個人幾乎一天的時間,如果用金錢衡量的話,花掉了我們上萬美金的時間成本。雖然客戶已經對這種事情習以為常,甚至認為這是引入新成員、讓成員適應環境、讓自己的員工適應我們的軟體所必須的成本,但是相比較起來,我們寧願把更多的時間花在為客戶構建可以增進業務的功能上面。

如果當時有 Docker,那麼構建環境就會像使用自動化搭建工具 Puppet / Chef / Salt / Ansible 一樣簡單,我們也可以把整個搭建時間週期從一天縮短為幾分鐘。但是和這些工具不同的地方在於,Docker 可以不僅僅可以搭建整個環境,還可以將整個環境儲存成磁碟檔案,然後複製到別的地方。需要從原始碼編譯 Node.js 嗎?Docker 做得到。Docker 不僅僅可以構建一個 Node.js 環境,還可以將整個環境做成映象,然後儲存到任何地方。當然,由於 Docker 是一個容器,所以不用擔心容器內執行的東西會對宿主機產生任何的影響。

現在新加入我們團隊的人只需要執行 docker-compose up 命令,便可以喝杯咖啡,然後開始工作了。

Docker 可以節省開銷

當然,時間就是金錢。除了時間外,Docker 還可以節省在基礎設施硬體上的開銷。高德納和麥肯錫的研究表明,資料中心的利用率在 6% - 12% 左右。不僅如此,如果採用虛擬機器的話,你還需要被動地監控和設定每臺虛擬機器的 CPU 硬碟和記憶體的使用率,因為採用了靜態分割槽(static partitioning)所以資源並不能完全被利用。。而容器可以解決這個問題:容器可以在例項之間進行記憶體和磁碟共享。你可以在同一臺主機上執行多個服務、可以不用去限制容器所消耗的資源、可以去限制資源、可以在不需要的時候停止容器,也不用擔心啟動已經停止的程式時會帶來過多的資源消耗。凌晨三點的時候只有很少的人會去訪問你的網站,同時你需要比較多的資源執行夜間的批處理任務,那麼可以很簡單的便實現資源的交換。

虛擬機器所消耗的記憶體、硬碟、CPU 都是固定的,一般動態調整都需要重啟虛擬機器。而用 Docker 的話,你可以進行資源限制,得益於 CGroup,可以很方便動態調整資源限制,讓然也可以不進行資源限制。Docker 容器內的應用對宿主機而言只是兩個隔離的應用程式,並不是兩個虛擬機器,所以宿主機也可以自行去分配資源。

Docker 有一個健壯的映象託管系統

前面提到過,這個託管系統就叫做 Docker Hub Registry。截止到 2015年4月29日,網際網路上大約有 14000 個公共的 Docker,而大部分都被託管在 Docker Hub 上面。和 Github 已經很大程度上成為開源專案的代表一樣,Docker 官方的 Docker Hub 則已經是公共 Docker 映象的代表。這些映象可以作為你應用和資料服務的基礎。

也正是得益於此,你可以隨意嘗試最新的技術:說不定有些人就把圖形化資料庫的例項打包成了 Docker 映象託管在上面。再例如 Gitlab,手工搭建 Gitlab 非常困難,譯者不建議普通使用者去手工搭建,而如果使用 Docker Gitlab,這個映象則會五秒內便搭建完成。再例如特定 Ruby 版本的 Rails 應用,再例如 Linux 上的 .NET 應用,這些都可以使用簡單的一條 Docker 命令搭建完成。

Docker 官方映象都有 official 標籤,安全性可以保證。但是第三方映象的安全性無法保證,所以請謹慎下載第三方映象。生產環境下可以只使用第三方提供的 Dockerfile 構建映象。

Docker Github 介紹:5 秒內搞定一個 Gitlab

關於 Linux 上的 .NET 應用和 Rails 應用,將會在以後的文章中做詳細介紹。

Docker 可以避免產生 Bug

Spantree 一直是“固定基礎設定”(immutable infrastructure)的狂熱愛好者。換句話說,除非有心臟出血這種漏洞,我們儘量不對系統做升級,也儘量不去改變系統的設定。當新增新伺服器的時候,我們也會從頭構建伺服器的系統,然後直接將映象匯入,將伺服器放入負載均衡的叢集裡,然後對要退休的伺服器進行健康檢查,檢查完畢後移除叢集。得益於 Docker 映象可以很輕鬆的匯入匯出,我們可以最大程度地減少因為環境和版本問題導致的不相容,即便有不相容了也可以很輕鬆地回滾。當然,有了 Docker,我們在生產、測試和開發中的執行環境得到統一。以前在協同開發時,會因為每個人開發的電腦配置不同而導致“在我的電腦上是能執行的,你的怎麼不行”的情況,而如今 Docker 已經幫我們解決了這個問題。

Docker 目前只能執行在 Linux 上

前面也提到過,Docker 使用的是經過長時間生產環境檢驗的技術,雖然這些技術已經都出現很長時間了,但是大部分技術都還是 Linux 獨有的,例如 LXC 和 Cgroup。也就是說,截止到現在,Docker 容器內只能在 Linux 上執行 Linux 上的服務和應用。Microsoft 正在和 Docker 緊密合作,並且已經宣佈了下一個版本的 Windows Server 將會支援 Docker 容器,並且命名為 Windows Docker,估計採用的技術應該是Hyper-V Container,我們有望在未來的幾年內看到這個版本。

除此之外,類似 boot2docker 和 Docker Machine 這種工具已經可以讓我們在 Mac 和 Windows 下透過虛擬機器執行 Docker 了。

相關文章