天天看點

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

【編者按】docker是paas供應商dotcloud開源的一個基于lxc 的進階容器引擎,源代碼托管在 github 上, 基于go語言開發并遵從apache 2.0協定開源。docker提供了一種在安全、可重複的環境中自動部署軟體的方式,它的出現拉開了基于雲計算平台釋出産品方式的變革序幕。

<a target="_blank"></a>

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釋出,拉開了基于雲計算平台釋出産品方式的變革序幕。

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽
深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

docker産生的目的就是為了解決以下問題:

1) 環境管理複雜: 從各種os到各種中間件再到各種app,一款産品能夠成功釋出,作為開發者需要關心的東西太多,且難于管理,這個問題在軟體行業中普遍存在并需要直接面對。docker可以簡化部署多種應用執行個體工作,比如web應用、背景應用、資料庫應用、大資料應用比如hadoop叢集、消息隊列等等都可以打包成一個image部署。如圖所示:

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

3) 虛拟化手段的變化: 雲時代采用标配硬體來降低成本,采用虛拟化手段來滿足使用者按需配置設定的資源需求以及保證可用性和隔離性。然而無論是kvm還是xen,在 docker 看來都在浪費資源,因為使用者需要的是高效運作環境而非os, guestos既浪費資源又難于管理, 更加輕量級的lxc更加靈活和快速。如圖所示:

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

4) lxc的便攜性: lxc在 linux 2.6 的 kernel 裡就已經存在了,但是其設計之初并非為雲計算考慮的,缺少标準化的描述手段和容器的可便攜性,決定其建構出的環境難于分發和标準化管理(相對于kvm之類image和snapshot的概念)。docker就在這個問題上做出了實質性的創新方法。

以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字元串。

每個使用者執行個體之間互相隔離, 互不影響。 一般的硬體虛拟化方法給出的方法是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上的使用者。

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

blkio 這個子系統設定限制每個塊裝置的輸入輸出控制。例如:磁盤,CD光牒以及usb等等。

cpu 這個子系統使用排程程式為cgroup任務提供cpu的通路。

cpuacct 産生cgroup任務的cpu資源報告。

cpuset 如果是多核心的cpu,這個子系統會為cgroup任務配置設定單獨的cpu和記憶體。

devices 允許或拒絕cgroup任務對裝置的通路。

freezer 暫停和恢複cgroup任務。

memory 設定每個cgroup的記憶體限制以及産生記憶體資源報告。

net_cls 标記每個網絡包以供cgroup友善使用。

ns 名稱空間子系統。

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:

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

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 如下圖:

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

典型的linux在啟動後,首先将 rootfs 設定為 readonly, 進行一系列檢查, 然後将其切換為 "readwrite" 供使用者使用。在docker中,初始化時也是将 rootfs 以readonly方式加載并檢查,然而接下來利用 union mount 的方式将一個 readwrite 檔案系統挂載在 readonly 的rootfs之上,并且允許再次将下層的 fs(file system) 設定為readonly 并且向上疊加, 這樣一組readonly和一個writeable的結構構成一個container的運作時态, 每一個fs被稱作一個fs層。如下圖:

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

得益于aufs的特性, 每一個對readonly層檔案/目錄的修改都隻會存在于上層的writeable層中。這樣由于不存在競争, 多個container可以共享readonly的fs層。 是以docker将readonly的fs層稱作 "image" - 對于container而言整個rootfs都是read-write的,但事實上所有的修改都寫入最上層的writeable層中, image不儲存使用者狀态,隻用于模闆、建立和複制使用。

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

上層的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。如下圖:

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

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

由kernel namespaces和cgroups實作的linux系統固有的安全标準;

docker deamon的安全接口;

linux本身的安全加強解決方案,類如apparmor, selinux;

深入淺出Docker(一):Docker核心技術預覽深入淺出Docker(一):Docker核心技術預覽

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

libswarm,是solomon hykes (docker的cto) 在dockercon 2014峰會上向社群介紹的新“樂高積木”工具: 它是用來統一分布式系統的網絡接口的api。libswarm要解決的問題是,基于docker建構的分布式應用已經催生了多個基于docker的服務發現(serivce discovery)項目,例如etcd, fleet, geard, mesos, shipyard, serf等等,每一套解決方案都有自己的通訊協定和使用方法,使用其中的任意一款都會局限在某一個特定的技術範圍內。是以docker的cto就想用libswarm暴露出通用的api接口給分布式系統使用,打破既定的協定限制。目前項目還在早期發展階段,值得參與。

libchan,是一個底層的網絡庫,為上層 libswarm 提供支援。相當于給docker加上了zeromq或rabbitmq,這裡自己實作網絡庫的好處是對docker做了特别優化,更加輕量級。一般開發者不會直接用到它,大家更多的還是使用libswarm來和容器互動。喜歡底層實作的網絡工程師可能對此感興趣,不妨一看。

libcontainer,docker技術的核心部分,單獨列出來也是因為這一塊的功能相對獨立,功能代碼的疊代更新非常快。想了解docker最新的支援特性應該多關注這個子產品。

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

原文釋出時間:2014-12-26

本文來自雲栖合作夥伴“linux中國”

繼續閱讀