Docker 的體系結構
docker 使用 C/S 架構叁怪,docker daemon 作為 server 端接受 client 的請求蕊连,并處理(創(chuàng)建、運行祝闻、分發(fā)容器)占卧,他們可以運行在一個機器上,也通過 socket 或者 RESTful API 通信
Docker daemon 一般在宿主主機后臺運行联喘。
Docker client 以系統(tǒng)命令的形式存在华蜒,用戶用 docker 命令來跟 docker daemon 交互。
Docker 守護進程(Docker daemon)
如上圖所示豁遭,Docker 守護進程運行在一臺主機上叭喜。用戶并不直接和守護進程進行交互,而是通過 Docker 客戶端間接和其通信蓖谢。
Docker 客戶端(Docker client)
Docker 客戶端捂蕴,實際上是 docker 的二進制程序,是用戶與 Docker 交互方式闪幽。它接收用戶指令并且與背后的 Docker 守護進程通信啥辨。
Docker 內(nèi)部:
要理解 Docker 內(nèi)部構建,需要理解以下三大核心概念:
Docker 鏡像 - Docker images
Docker 倉庫 - Docker repository
Docker 容器 - Docker containers
只有理解了這三個核心概念盯腌,才能順利地理解 Docker 容器的整個生命周期溉知。
Docker 鏡像
Docker 鏡像是 Docker 容器運行時的只讀模板,鏡像可以用來創(chuàng)建 Docker 容器。每一個鏡像由一系列的層 (layers) 組成着倾。Docker 使用 UnionFS(聯(lián)合文件系統(tǒng))來將這些層聯(lián)合到單獨的鏡像中。UnionFS 允許獨立文件系統(tǒng)中的文件和文件夾(稱之為分支)被透明覆蓋燕少,形成一個單獨連貫的文件系統(tǒng)卡者。正因為有了這些層的存在,Docker 是如此的輕量客们。當你改變了一個 Docker 鏡像崇决,比如升級到某個程序到新的版本,一個新的層會被創(chuàng)建底挫。因此恒傻,不用替換整個原先的鏡像或者重新建立(在使用虛擬機的時候你可能會這么做),只是一個新的層被添加或升級了〗ǖ耍現(xiàn)在你不用重新發(fā)布整個鏡像盈厘,只需要升級,層使得分發(fā)Docker 鏡像變得簡單和快速官边。
例如:centos 鏡像中安裝 nginx沸手,就成了“nginx 鏡像”,其實在此時 Docker 鏡像的層級概念就體現(xiàn)出來了注簿。底層一個 centos 操作系統(tǒng)鏡像契吉,上面疊加一個 nginx 層,就完成了一個 nginx 鏡像的構建诡渴。層級概念就不難理解捐晶,此時我們一般 centos 操作系統(tǒng)鏡像稱為nginx 鏡像層的父鏡像俺驶。
鏡像是創(chuàng)建 Docker 容器的基礎奸鬓。通過版本管理和增量的文件系統(tǒng)练般,Docker 提供了一套十分簡單的機制來創(chuàng)建和更新現(xiàn)有的鏡像叼丑,用戶甚至可以從網(wǎng)上下載一個已經(jīng)做好的應用鏡像昔案,并直接使用瓶堕。
Docker 倉庫Docker 倉庫類似于代碼倉庫颠印,它是 Docker 集中存放鏡像文件的場所昧诱。
不要將 Docker 倉庫和倉庫注冊服務器(Registry)混為一談畔塔。實際上潭辈,倉庫注冊服務器是存放倉庫的地方,其上往往存放著多個倉庫澈吨。每個倉庫集中存放某一類鏡像把敢,往往包括多個鏡像文件,通過不同的標簽(tag)來進行區(qū)分谅辣。例如存放 Ubuntu 操作系統(tǒng)鏡像的庫稱為 Ubuntu 倉庫修赞,其中可能包括 14.04、12.04 等不同版本的鏡像。倉庫注冊服務器的示例如圖所示柏副。
根據(jù)所存儲的鏡像公開分享與否勾邦,Docker 倉庫可以分為公開倉庫(Public)和私有倉庫(Private)兩種形式。目前割择,最大的公開倉庫是官方提供的 Docker Hub眷篇,其中存放了數(shù)量龐大的鏡像供用戶下載。國內(nèi)不少云服務提供商(如時速云荔泳、阿里云等)也提供了倉庫的本地源蕉饼,可以提供穩(wěn)定的國內(nèi)訪問。當然玛歌,用戶如果不希望公開分享自己的鏡像文件昧港,Docker 也支持用戶在本地網(wǎng)絡內(nèi)創(chuàng)建一個只能自己訪問的私有倉庫。
當用戶創(chuàng)建了自己的鏡像之后就可以使用 push 命令將它上傳到指定的公有或者私有倉庫支子。這樣用戶下次在另外一臺機器上使用該鏡像時创肥,只需要將其從倉庫上 pull 下來就可以了。
可以看出译荞,Docker 利用倉庫管理鏡像的設計理念與 Git 非常相似瓤的,實際上在理念設計上借鑒了 Git 的很多優(yōu)秀思想。
Docker 容器
Docker 利用容器來運行應用吞歼,一個 Docker 容器包含了所有的某個應用運行所需要的環(huán)境圈膏。每一個 Docker 容器都是從 Docker 鏡像創(chuàng)建的,是通過鏡像創(chuàng)建的運行實例篙骡。Docker 容器可以運行稽坤、開始、停止糯俗、移動和刪除尿褪。每一個 Docker 容器都是獨立和安全的應用平臺,彼此相互隔離得湘、互不可見杖玲。
可以把容器看做是一個簡易版的 Linux 環(huán)境(包括 root 用戶權限、進程空間淘正、用戶空間和網(wǎng)絡空間等)和運行在其中的應用程序摆马。
鏡像是只讀的,容器在啟動的時候創(chuàng)建一層可寫層作為最上層鸿吆。
與虛擬機相比囤采,容器有一個很大的差異,它們被設計用來運行"單進程"惩淳,無法很好地模擬一個完整的環(huán)境蕉毯。Docker 設計者極力推崇“一個容器一個進程的方式”,如果你要選擇在一個容器中運行多個進程,那唯一情況是:出于調試目的代虾。容器是設計來運行一個應用的进肯,而非一臺機器。你可能會把容器當虛擬機用棉磨,但你將失去很多的靈活性坷澡,因為Docker 提供了用于分離應用與數(shù)據(jù)的工具,使得你可以快捷地更新運行中的代碼/系統(tǒng)含蓉,而不影響數(shù)據(jù)项郊。
Docker 從 0.9 版本開始使用 libcontainer 替代lxc馅扣,libcontainer 和 Linux 系統(tǒng)的交互圖如下:
Docker 底層技術
docker 底層的 2 個核心技術分別是 Namespaces
和Control groups
Namespaces 用來隔離各個容器
1) pid namespace
不同用戶的進程就是通過 pid namespace 隔離開的,且不同 namespace 中可以有相同 pid着降。所有的 LXC 進程在 docker 中的父進程為 docker 進程差油,每個 lxc 進程具有不同的
namespace 。
2) net namespace
有了 pid namespace, 每個 namespace 中的 pid 能夠相互隔離任洞,但是網(wǎng)絡端口還是共享host 的端口蓄喇。網(wǎng)絡隔離是通過 net namespace 實現(xiàn)的,每個 net namespace 有獨立的network devices, IP addresses, IP routing tables, /proc/net 目錄交掏。這樣每個container 的網(wǎng)絡就能隔離開來妆偏。docker 默認采用 veth 的方式將 container 中的虛擬網(wǎng)卡同 host 上的一個 docker bridge: docker0 連接在一起。
3) ipc namespace
container 中 進 程 交 互 還 是 采 用 linux 常 見 的 進 程 間 交 互 方 法 (interprocesscommunication - IPC),包括常見的信號量盅弛、消息隊列和共享內(nèi)存钱骂。container 的進程間交互實際上還是 host 上具有相同pidnamespace 中的進程間交互。
4) mnt namespace
類似 chroot挪鹏,將一個進程放到一個特定的目錄執(zhí)行见秽。mnt namespace 允許不同 namespace的進程看到的文件結構不同,這樣每個namespace 中的進程所看到的文件目錄就被隔離開了讨盒。在 container 里頭解取,看到的文件系統(tǒng),就是一個完整的 linux 系統(tǒng)返顺,有/etc禀苦、/lib等,通過 chroot 實現(xiàn)创南。
5) uts namespace
UTS("UNIX Time-sharing System") namespace 允許每個 container 擁有獨立的 hostname和 domain name, 使其在網(wǎng)絡上可以被視作一個獨立的節(jié)點而非 Host 上的一個進程伦忠。
6) user namespace
每個 container 可以有不同的 user 和 group id,也就是說可以在 container 內(nèi)部用container 內(nèi)部的用戶執(zhí)行程序而非 Host 上的用戶稿辙。
有了以上 6 種 namespace 從進程昆码、網(wǎng)絡、IPC、文件系統(tǒng)赋咽、UTS 和用戶角度的隔離旧噪,一個 container 就可以對外展現(xiàn)出一個獨立計算機的能力,并且不同 container 從 OS 層面實現(xiàn)了隔離脓匿。然而不同 namespace 之間資源還是相互競爭的淘钟,仍然需要類似 ulimit 來管理每個 container 所能使用的資源--cgroup。
cgroups (l Control groups )實現(xiàn)了對資源的配額和度量陪毡。
cgroups(Control Groups)最初叫 Process Container米母,由 Google 工程師(PaulMenage 和 Rohit Seth)于 2006 年提出,后來因為 Container 有多重含義容易引起誤解毡琉,就在 2007 年更名為 Control Groups铁瞒,并被整合進 Linux 內(nèi)核。顧名思義就是把進程放到一個組里面統(tǒng)一加以控制桅滋。官方的定義如下:cgroups 是 Linux 內(nèi)核提供的一種機制慧耍,這種機制可以根據(jù)特定的行為,把一系列系統(tǒng)任務及其子任務整合(或分隔)到按資源劃分等級的不同組內(nèi)丐谋,從而為系統(tǒng)資源管理提供一個統(tǒng)一的框架芍碧。
通俗的來說,cgroups 可以限制号俐、記錄泌豆、隔離進程組所使用的物理資源(包括:CPU、memory吏饿、IO 等)践美,為容器實現(xiàn)虛擬化提供了基本保證,是構建 Docker 等一系列虛擬化管理工具的基石找岖。
實現(xiàn) cgroups 的主要目的是為不同用戶層面的資源管理陨倡,提供一個統(tǒng)一化的接口。從
###單個進程的資源控制到操作系統(tǒng)層面的虛擬化许布。Cgroups 提供了以下四大功能: