Docker並非全能的,設計之初也不是KVM之類虛擬化手段的替代品,簡單總結幾點:
-
Docker是基於Linux 64bit的,沒法在32bit的linux/Windows/unix環境下使用
-
LXC是基於cgroup等linux kernel功能的,所以container的guest系統只能是linux base的
-
隔離性相比KVM之類的虛擬化方案仍是有些欠缺,全部container公用一部分的運行庫
-
網絡管理相對簡單,主要是基於namespace隔離
-
cgroup的cpu和cpuset提供的cpu功能相比KVM的等虛擬化方案相比難以度量(因此dotcloud主要是按內存收費)
-
Docker對disk的管理比較有限
-
container隨着用戶進程的中止而銷燬,container中的log等用戶數據不便收集
針對1-2,有windows base應用的需求的基本能夠pass了; 3-5主要是看用戶的需求,究竟是須要一個container仍是一個VM, 同時也決定了docker做爲 IaaS 不太可行。
針對6,7雖然是docker自己不支持的功能,可是能夠經過其餘手段解決(disk quota, mount --bind)。總之,選用container仍是vm, 就是在隔離性和資源複用性上作權衡。
另外即使docker 0.7可以支持非AUFS的文件系統,可是因爲其功能還不穩定,商業應用或許會存在問題,而AUFS的穩定版須要kernel 3.8, 因此若是想複製dotcloud的成功案例,可能須要考慮升級kernel或者換用ubuntu的server版本(後者提供deb更新)。這也是爲何開源界更傾向於支持ubuntu的緣由(kernel版本)
Docker並不是適合全部應用場景,Docker只能虛擬基於Linux的服務。Windows Azure 服務可以運行Docker實例,但到目前爲止Windows服務還不能被虛擬化。
可能最大的障礙在於管理實例之間的交互。因爲全部應用組件被拆分到不一樣的容器中,全部的服務器須要以一致的方式彼此通訊。這意味着任何人若是選擇複雜的基礎設施,那麼必須掌握應用編程接口管理以及集羣工具,好比Swarm、Mesos或者Kubernets以確保機器按照預期運轉並支持故障切換。
Docker在本質上是一個附加系統。使用文件系統的不一樣層構建一個應用是有可能的。每一個組件被添加到以前已經建立的組件之上,能夠比做爲一個文件系統更明智。分層架構帶來另外一方面的效率提高,當你重建存在變化的Docker鏡像時,不須要重建整個Docker鏡像,只須要重建變化的部分。
可能更爲重要的是,Docker旨在用於彈性計算。每一個Docker實例的運營生命週期有限,實例數量根據需求增減。在一個管理適度的系統中,這些實例生而平等,再也不須要時便各自消亡了。
針對Docker環境存在的不足,意味着在開始部署Docker前須要考慮以下幾個問題。首先,Docker實例是無狀態的。這意味着它們不該該承載任何交易數據,全部數據應該保存在數據庫服務器中。
其次,開發Docker實例並不像建立一臺虛擬機、添加應用而後克隆那樣簡單。爲成功建立並使用Docker基礎設施,管理員須要對系統管理的各個方面有一個全面的理解,包括Linux管理、編排及配置工具好比Puppet、Chef以及Salt。這些工具生來就基於命令行以及腳本。
LXC所實現的隔離性主要是來自kernel的namespace, 其中pid, net, ipc, mnt, uts 等namespace將container的進程, 網絡, 消息, 文件系統和hostname 隔離開。
pid namespace
以前提到用戶的進程是lxc-start進程的子進程, 不一樣用戶的進程就是經過pidnamespace隔離開的,且不一樣 namespace 中能夠有相同PID。具備如下特徵:
-
每一個namespace中的pid是有本身的pid=1的進程(相似/sbin/init進程)
-
每一個namespace中的進程只能影響本身的同一個namespace或子namespace中的進程
-
由於/proc包含正在運行的進程,所以在container中的pseudo-filesystem的/proc目錄只能看到本身namespace中的進程
-
由於namespace容許嵌套,父namespace能夠影響子namespace的進程,因此子namespace的進程能夠在父namespace中看到,可是具備不一樣的pid
正是由於以上的特徵,全部的LXC進程在docker中的父進程爲docker進程,每一個lxc進程具備不一樣的namespace。同時因爲容許嵌套,所以能夠很方便的實現 LXC in LXC
net namespace
有了 pid namespace, 每一個namespace中的pid可以相互隔離,可是網絡端口仍是共享host的端口。網絡隔離是經過netnamespace實現的,
每一個net namespace有獨立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。這樣每一個container的網絡就能隔離開來。
LXC在此基礎上有5種網絡類型,docker默認採用veth的方式將container中的虛擬網卡同host上的一個docker bridge鏈接在一塊兒。
ipc namespace
container中進程交互仍是採用linux常見的進程間交互方法(interprocess communication - IPC), 包括常見的信號量、消息隊列和共享內存。然而同VM不一樣,container 的進程間交互實際上仍是host上具備相同pid namespace中的進程間交互,所以須要在IPC資源申請時加入namespace信息 - 每一個IPC資源有一個惟一的 32bit ID。
mnt namespace
相似chroot,將一個進程放到一個特定的目錄執行。mnt namespace容許不一樣namespace的進程看到的文件結構不一樣,這樣每一個 namespace 中的進程所看到的文件目錄就被隔離開了。同chroot不一樣,每一個namespace中的container在/proc/mounts的信息只包含所在namespace的mount point。
uts namespace
UTS(「UNIX Time-sharing System」) namespace容許每一個container擁有獨立的hostname和domain name,
使其在網絡上能夠被視做一個獨立的節點而非Host上的一個進程。
user namespace
每一個container能夠有不一樣的 user 和 group id, 也就是說能夠以container內部的用戶在container內部執行程序而非Host上的用戶。
有了以上6種namespace從進程、網絡、IPC、文件系統、UTS和用戶角度的隔離,一個container就能夠對外展示出一個獨立計算機的能力,而且不一樣container從OS層面實現了隔離。
然而不一樣namespace之間資源仍是相互競爭的,仍然須要相似ulimit來管理每一個container所能使用的資源 - LXC 採用的是cgroup。
Control Groups
cgroups 實現了對資源的配額和度量。 cgroups 的使用很是簡單,提供相似文件的接口,在 /cgroup目錄下新建一個文件夾便可新建一個group,在此文件夾中新建task文件,並將pid寫入該文件,便可實現對該進程的資源控制。具體的資源配置選項能夠在該文件夾中新建子 subsystem ,{子系統前綴}.{資源項} 是典型的配置方法,
如memory.usage_in_bytes 就定義了該group 在subsystem memory中的一個內存限制選項。
另外,cgroups中的 subsystem能夠隨意組合,一個subsystem能夠在不一樣的group中,也能夠一個group包含多個subsystem - 也就是說一個 subsystem。
關於術語定義
A *cgroup* associates a set of tasks with a set of parameters for one
or more subsystems.
A *subsystem* is a module that makes use of the task grouping
facilities provided by cgroups to treat groups of tasks in
particular ways. A subsystem is typically a "resource controller" that
schedules a resource or applies per-cgroup limits, but it may be
anything that wants to act on a group of processes, e.g. a
virtualization subsystem.
咱們主要關心cgroups能夠限制哪些資源,即有哪些subsystem是咱們關心。
cpu : 在cgroup中,並不能像硬件虛擬化方案同樣可以定義CPU能力,可是可以定義CPU輪轉的優先級,所以具備較高CPU優先級的進程會更可能獲得CPU運算。
經過將參數寫入cpu.shares,便可定義改cgroup的CPU優先級 - 這裏是一個相對權重,而非絕對值。固然在cpu這個subsystem中還有其餘可配置項,手冊中有詳細說明。
cpusets : cpusets 定義了有幾個CPU能夠被這個group使用,或者哪幾個CPU能夠供這個group使用。在某些場景下,單CPU綁定能夠防止多核間緩存切換,從而提升效率
memory : 內存相關的限制
blkio : block IO相關的統計和限制,byte/operation統計和限制(IOPS等),讀寫速度限制等,可是這裏主要統計的都是同步IO
net_cls, cpuacct , devices , freezer 等其餘可管理項。
藉助於namespace的隔離機制和cgroup限額功能,
LXC提供了一套統一的API和工具來創建和管理container, LXC利用了以下 kernel 的features:
-
Kernel namespaces (ipc, uts, mount, pid, network and user)
-
Apparmor and SELinux profiles
-
Seccomp policies
-
Chroots (using pivot_root)
-
Kernel capabilities
-
Control groups (cgroups)
LXC 向用戶屏蔽了以上 kernel 接口的細節, 提供了以下的組件大大簡化了用戶的開發和使用工做:
LXC 旨在提供一個共享kernel的 OS 級虛擬化方法,在執行時不用重複加載Kernel, 且container的kernel與host共享,所以能夠大大加快container的 啓動過程,並顯著減小內存消耗。在實際測試中,基於LXC的虛擬化方法的IO和CPU性能幾乎接近 baremetal 的性能
[9] , 大多數數據有相比 Xen具備優點。固然對於KVM這種也是經過Kernel進行隔離的方式, 性能優點或許不是那麼明顯, 主要仍是內存消耗和啓動時間上的差別。在參考文獻 [10] 中提到了利用iozone進行 Disk IO吞吐量測試KVM反而比LXC要快,並且筆者在device mapping driver下重現一樣case的實驗中也確實能獲得如此結論。參考文獻從網絡虛擬化中虛擬路由的場景(網絡IO和CPU角度)比較了KVM和LXC, 獲得結論是KVM在性能和隔離性的平衡上比LXC更優秀 - KVM在吞吐量上略差於LXC, 但CPU的隔離可管理項比LXC更明確。
關於CPU, DiskIO, network IO 和 memory 在KVM和LXC中的比較仍是須要更多的實驗才能得出可信服的結論。
Docker推出的一個名爲
Docker Content Trust(DCT)的新功能,
它可幫助IT專業人士確保Docker的安全性。DCT使用了
一個公共密鑰基礎設施(PKI)的方法,它提供了
兩個不一樣的密鑰:一個離線(root)密鑰和一個標記(每次入庫)密鑰,當第一次發佈者推出鏡像時它可建立和存儲客戶端。
此舉有助於彌補正在使用惡意容器這一最大的漏洞。DCT還生成了一個時間戳密鑰,它可保護系統免受重放攻擊,即運行過時的標記內容。這解決了上面說起容器具備不一樣安全補丁等級的問題。
爲了解決針對容器安全性的問題,包括Docker在內的衆多公司都爲Docker發佈了安全基準。這套標準爲確保Docker容器的安全性提供了指導。全篇118頁的文檔囊括了部署Docker容器的84個最佳實踐以及一個涉及全部內容的檢查清單。
那麼,若是你決定自行負責確保Docker容器的安全性,但又不知道從何入手,咱們在這裏爲你提供了一些建議:
閱讀上面說起的Docker安全基準文件。重點關注與如何部署基於容器的應用程序相關的建議和最佳實踐。這真的是有助於緩解你的財務壓力,認真考慮大部分因糟糕設計而致使的Docker安全性問題。
考慮你的特定安全性需求。這將促使你選擇正確的工具和方法。不少使用容器技術的企業對於他們基於容器的應用程序要麼安全措施不足,要麼安全措施過足。
儘量多地進行測試。容器技術是新技術,所以咱們須要搞清楚哪些是可以發揮做用,哪些是無用的,而要作到這一點的惟一方法就是進行安全性方面的測試,例如滲透測試。
容器安全性的發展趨勢可能會與虛擬化安全性同樣。雖然安全性從第一臺虛擬機部署開始就是一個問題,可是多年以來積累下來的良好安全性實踐、架構和工具都證實了其有效性。咱們相信,Docker容器安全性的問題也一樣可以獲得較好解決。