容器(Docker)技術

本文詳細介紹了Docker技術,簡單易懂。好東西值得傳播,原文地址:http://www.infoq.com/cn/articles/docker-core-technology-preview

【編者按】Docker是PaaS供應商dotCloud開源的一個基於LXC 的高級容器引擎,源代碼託管在 GitHub 上, 基於Go語言開發並遵從Apache 2.0協議開源。Docker提供了一種在安全、可重複的環境中自動部署軟件的方式,它的出現拉開了基於雲計算平臺發佈產品方式的變革序幕。爲了更好的促進Docker在國內的發展以及傳播,我們決定開設《深入淺出Docker》專欄,邀請Docker相關的佈道師、開發人員、技術專家來講述Docker的各方面內容,讓讀者對Docker有更深入的瞭解,並且能夠積極投入到新技術的討論和實踐中。另外,歡迎加入InfoQ Docker技術交流羣交流Docker的最佳實踐,QQ羣號:482445072。

號外:CNUTCon全球容器技術大會正在火熱報名中,本次大會主題是『 剖析容器企業實踐,關注容器生態圈開源項目』,點擊官網瞭解詳情。

1. 背景

1.1. 由PaaS到Container

2013年2月,前Gluster的CEO Ben Golub和dotCloud的CEO Solomon Hykes坐在一起聊天時,Solomon談到想把dotCloud內部使用的Container容器技術單獨拿出來開源,然後圍繞這個技術開一家新公司提供技術支持。28歲的Solomon在使用python開發dotCloud的PaaS雲時發現,使用 LXC(Linux Container) 技術可以打破產品發佈過程中應用開發工程師和系統工程師兩者之間無法輕鬆協作發佈產品的難題。這個Container容器技術可以把開發者從日常部署應用的繁雜工作中解脫出來,讓開發者能專心寫好程序;從系統工程師的角度來看也是一樣,他們迫切需要從各種混亂的部署文檔中解脫出來,讓系統工程師專注在應用的水平擴展、穩定發佈的解決方案上。他們越深入交談,越覺得這是一次雲技術的變革,緊接着在2013年3月Docker 0.1發佈,拉開了基於雲計算平臺發佈產品方式的變革序幕。

1.2 Docker簡介

Docker 是 Docker.Inc 公司開源的一個基於 LXC技術之上構建的Container容器引擎, 源代碼託管在 GitHub 上, 基於Go語言並遵從Apache2.0協議開源。 Docker在2014年6月召開DockerConf 2014技術大會吸引了IBM、Google、RedHat等業界知名公司的關注和技術支持,無論是從 GitHub 上的代碼活躍度,還是Redhat宣佈在RHEL7中正式支持Docker, 都給業界一個信號,這是一項創新型的技術解決方案。 就連 Google 公司的 Compute Engine 也支持 docker 在其之上運行, 國內“BAT”先鋒企業百度Baidu App Engine(BAE)平臺也是以Docker作爲其PaaS雲基礎

Docker產生的目的就是爲了解決以下問題:

1) 環境管理複雜: 從各種OS到各種中間件再到各種App,一款產品能夠成功發佈,作爲開發者需要關心的東西太多,且難於管理,這個問題在軟件行業中普遍存在並需要直接面對。Docker可以簡化部署多種應用實例工作,比如Web應用、後臺應用、數據庫應用、大數據應用比如Hadoop集羣、消息隊列等等都可以打包成一個Image部署。如圖所示:

2) 雲計算時代的到來: AWS的成功, 引導開發者將應用轉移到雲上, 解決了硬件管理的問題,然而軟件配置和管理相關的問題依然存在 (AWS cloudformation是這個方向的業界標準, 樣例模板可參考這裏)。Docker的出現正好能幫助軟件開發者開闊思路,嘗試新的軟件管理方法來解決這個問題。

3) 虛擬化手段的變化: 雲時代採用標配硬件來降低成本,採用虛擬化手段來滿足用戶按需分配的資源需求以及保證可用性和隔離性。然而無論是KVM還是Xen,在 Docker 看來都在浪費資源,因爲用戶需要的是高效運行環境而非OS, GuestOS既浪費資源又難於管理, 更加輕量級的LXC更加靈活和快速。如圖所示:

4) LXC的便攜性: LXC在 Linux 2.6 的 Kernel 裏就已經存在了,但是其設計之初並非爲雲計算考慮的,缺少標準化的描述手段和容器的可便攜性,決定其構建出的環境難於分發和標準化管理(相對於KVM之類image和snapshot的概念)。Docker就在這個問題上做出了實質性的創新方法。

1.3 Docker的Hello World

以Fedora 20作爲主機爲例,直接安裝docker-io:

$ sudo yum -y install docker-io

啓動docker後臺Daemon:

$ sudo systemctl start docker

跑我們第一個Hello World容器:

$ sudo docker run -i -t fedora /bin/echo hello world
Hello world

可以看到在運行命令行後的下一行會打印出經典的Hello World字符串。

2. 核心技術預覽

Docker核心是一個操作系統級虛擬化方法, 理解起來可能並不像VM那樣直觀。我們從虛擬化方法的四個方面:隔離性、可配額/可度量、便攜性、安全性來詳細介紹Docker的技術細節。

2.1. 隔離性: Linux Namespace(ns)

每個用戶實例之間相互隔離, 互不影響。 一般的硬件虛擬化方法給出的方法是VM,而LXC給出的方法是container,更細一點講就是kernel namespace。其中pid、net、ipc、mnt、uts、user等namespace將container的進程、網絡、消息、文件系統、UTS("UNIX Time-sharing System")和用戶空間隔離開。

1) pid namespace

不同用戶的進程就是通過pid namespace隔離開的,且不同 namespace 中可以有相同pid。所有的LXC進程在docker中的父進程爲docker進程,每個lxc進程具有不同的namespace。同時由於允許嵌套,因此可以很方便的實現 Docker in Docker。

2) net namespace

有了 pid namespace, 每個namespace中的pid能夠相互隔離,但是網絡端口還是共享host的端口。網絡隔離是通過net namespace實現的, 每個net namespace有獨立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。這樣每個container的網絡就能隔離開來。docker默認採用veth的方式將container中的虛擬網卡同host上的一個docker bridge: docker0連接在一起。

3) ipc namespace

container中進程交互還是採用linux常見的進程間交互方法(interprocess communication - IPC), 包括常見的信號量、消息隊列和共享內存。然而同 VM 不同的是,container 的進程間交互實際上還是host上具有相同pid namespace中的進程間交互,因此需要在IPC資源申請時加入namespace信息 - 每個IPC資源有一個唯一的 32 位 ID。

4) mnt namespace

類似chroot,將一個進程放到一個特定的目錄執行。mnt namespace允許不同namespace的進程看到的文件結構不同,這樣每個 namespace 中的進程所看到的文件目錄就被隔離開了。同chroot不同,每個namespace中的container在/proc/mounts的信息只包含所在namespace的mount point。

5) uts namespace

UTS("UNIX Time-sharing System") namespace允許每個container擁有獨立的hostname和domain name, 使其在網絡上可以被視作一個獨立的節點而非Host上的一個進程。

6) user namespace

每個container可以有不同的 user 和 group id, 也就是說可以在container內部用container內部的用戶執行程序而非Host上的用戶。

2.2 可配額/可度量 - Control Groups (cgroups)

cgroups 實現了對資源的配額和度量。 cgroups 的使用非常簡單,提供類似文件的接口,在 /cgroup目錄下新建一個文件夾即可新建一個group,在此文件夾中新建task文件,並將pid寫入該文件,即可實現對該進程的資源控制。groups可以限制blkio、cpu、cpuacct、cpuset、devices、freezer、memory、net_cls、ns九大子系統的資源,以下是每個子系統的詳細說明:

  1. blkio 這個子系統設置限制每個塊設備的輸入輸出控制。例如:磁盤,光盤以及usb等等。
  2. cpu 這個子系統使用調度程序爲cgroup任務提供cpu的訪問。
  3. cpuacct 產生cgroup任務的cpu資源報告。
  4. cpuset 如果是多核心的cpu,這個子系統會爲cgroup任務分配單獨的cpu和內存。
  5. devices 允許或拒絕cgroup任務對設備的訪問。
  6. freezer 暫停和恢復cgroup任務。
  7. memory 設置每個cgroup的內存限制以及產生內存資源報告。
  8. net_cls 標記每個網絡包以供cgroup方便使用。
  9. ns 名稱空間子系統。

以上九個子系統之間也存在着一定的關係.詳情請參閱官方文檔

2.3 便攜性: AUFS

AUFS (AnotherUnionFS) 是一種 Union FS, 簡單來說就是支持將不同目錄掛載到同一個虛擬文件系統下(unite several directories into a single virtual filesystem)的文件系統, 更進一步的理解, AUFS支持爲每一個成員目錄(類似Git Branch)設定readonly、readwrite 和 whiteout-able 權限, 同時 AUFS 裏有一個類似分層的概念, 對 readonly 權限的 branch 可以邏輯上進行修改(增量地, 不影響 readonly 部分的)。通常 Union FS 有兩個用途, 一方面可以實現不借助 LVM、RAID 將多個disk掛到同一個目錄下, 另一個更常用的就是將一個 readonly 的 branch 和一個 writeable 的 branch 聯合在一起,Live CD正是基於此方法可以允許在 OS image 不變的基礎上允許用戶在其上進行一些寫操作。Docker 在 AUFS 上構建的 container image 也正是如此,接下來我們從啓動 container 中的 linux 爲例來介紹 docker 對AUFS特性的運用。

典型的啓動Linux運行需要兩個FS: bootfs + rootfs:

bootfs (boot file system) 主要包含 bootloader 和 kernel, bootloader主要是引導加載kernel, 當boot成功後 kernel 被加載到內存中後 bootfs就被umount了. rootfs (root file system) 包含的就是典型 Linux 系統中的 /dev, /proc,/bin, /etc 等標準目錄和文件。

對於不同的linux發行版, bootfs基本是一致的, 但rootfs會有差別, 因此不同的發行版可以公用bootfs 如下圖:

典型的Linux在啓動後,首先將 rootfs 設置爲 readonly, 進行一系列檢查, 然後將其切換爲 "readwrite" 供用戶使用。在Docker中,初始化時也是將 rootfs 以readonly方式加載並檢查,然而接下來利用 union mount 的方式將一個 readwrite 文件系統掛載在 readonly 的rootfs之上,並且允許再次將下層的 FS(file system) 設定爲readonly 並且向上疊加, 這樣一組readonly和一個writeable的結構構成一個container的運行時態, 每一個FS被稱作一個FS層。如下圖:

得益於AUFS的特性, 每一個對readonly層文件/目錄的修改都只會存在於上層的writeable層中。這樣由於不存在競爭, 多個container可以共享readonly的FS層。 所以Docker將readonly的FS層稱作 "image" - 對於container而言整個rootfs都是read-write的,但事實上所有的修改都寫入最上層的writeable層中, image不保存用戶狀態,只用於模板、新建和複製使用。

上層的image依賴下層的image,因此Docker中把下層的image稱作父image,沒有父image的image稱作base image。因此想要從一個image啓動一個container,Docker會先加載這個image和依賴的父images以及base image,用戶的進程運行在writeable的layer中。所有parent image中的數據信息以及 ID、網絡和lxc管理的資源限制等具體container的配置,構成一個Docker概念上的container。如下圖:

2.4 安全性: AppArmor, SELinux, GRSEC

安全永遠是相對的,這裏有三個方面可以考慮Docker的安全特性:

  1. 由kernel namespaces和cgroups實現的Linux系統固有的安全標準;
  2. Docker Deamon的安全接口;
  3. Linux本身的安全加固解決方案,類如AppArmor, SELinux;

由於安全屬於非常具體的技術,這裏不在贅述,請直接參閱Docker官方文檔

3. 最新子項目介紹

我們再來看看Docker社區還有哪些子項目值得我們去好好研究和學習。基於這個目的,我把有趣的核心項目給大家羅列出來,讓熱心的讀者能快速跟進自己感興趣的項目:

  1. Libswarm,是Solomon Hykes (Docker的CTO) 在DockerCon 2014峯會上向社區介紹的新“樂高積木”工具: 它是用來統一分佈式系統的網絡接口的API。Libswarm要解決的問題是,基於Docker構建的分佈式應用已經催生了多個基於Docker的服務發現(Serivce Discovery)項目,例如etcd, fleet, geard, mesos, shipyard, serf等等,每一套解決方案都有自己的通訊協議和使用方法,使用其中的任意一款都會侷限在某一個特定的技術範圍內。所以Docker的CTO就想用libswarm暴露出通用的API接口給分佈式系統使用,打破既定的協議限制。目前項目還在早期發展階段,值得參與。
  2. Libchan,是一個底層的網絡庫,爲上層 Libswarm 提供支持。相當於給Docker加上了ZeroMQ或RabbitMQ,這裏自己實現網絡庫的好處是對Docker做了特別優化,更加輕量級。一般開發者不會直接用到它,大家更多的還是使用Libswarm來和容器交互。喜歡底層實現的網絡工程師可能對此感興趣,不妨一看。
  3. Libcontainer,Docker技術的核心部分,單獨列出來也是因爲這一塊的功能相對獨立,功能代碼的迭代升級非常快。想了解Docker最新的支持特性應該多關注這個模塊。

4. 總結

Docker社區一直在面對技術挑戰,從容地給出自己的解決方案。雲計算髮展至今,有很多重要的問題沒有得到妥善解決,Docker正在嘗試讓主流廠商接受並應用它。至此,以上Docker技術的預覽到此告一段落,筆者也希望讀者能結合自己的實際情況,嘗試使用Docker技術。因爲只有在親自體會的基礎之上,像Docker這樣的雲技術纔會產生更大的價值。

發佈了94 篇原創文章 · 獲贊 184 · 訪問量 31萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章