閱讀585 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Docker基礎之一: Docker架構

Docker的架構

Docker使用的是 C-S架構。Docker的客戶端同Docker Daemon進行交互,其中主要的工作是通過 daemon來完成,包括拉取鏡像,編譯鏡像,運行容器,發布容器等。Docker client和daemon可以運行在同一個係統上,也可以通過遠程方式進行訪問。Docker client和daemon之間是在 socket 上通過RESTful API來進行交互的。 

574478332a680c4ea8c3cf1a57fee4f5f6c217aa

Docker Daemon

如上圖所示,Docker daemon運行在一個主機之上,用戶並不是直接同daemon進行交互,而是通過Docker client來進行訪問。

Docker Client

在Docker那個方框中,是主要的用戶訪問Docker的渠道。用戶通過它對Docker Daemon進行訪問控製。

Docker Images

Docker Image是一個隻讀的模板。比如,一個Image可以包含一個Ubuntu操作係統,整個係統可以包括Apache和你的web應用。Image是用來創建容器的。Docker提供了一種簡單的方式來創建Image和更新已有的 Image, 你可以從網上下載Image,也可以自己編譯Image。

Docker Registry

Docker Registry 是存放Image的倉庫。我們可以使用公有的和私有的Registry來進行下載和上載。公共的Docker Registry位於Docker Hub,但是國內訪問比較慢。Docker Hub包含了大量已有的Image,供用戶使用。你可以基於之前的Image來創建自己的 Image。

Docker Containers

Docker容器就像一個文件夾。一個容器包含了應用程序運行所需的所有環境。每個容器都源於某一個Docker Image。Docker容器可以運行,開始,停止,移動並刪除。每個容器都是完全隔離的和安全的應用。

Docker 如何工作

通過之前的介紹,我們知道:

  1. 我們可以自己編譯Docker Image來打包應用
  2. 我們可以從Docker Image創建容器,並在其中運行應用程序
  3. 我們可以通過Docker Hub或私有的Registry來分享Docker Image 接下來,我們來看如何將之前的這些元素整合起來運行。

Docker Image 工作方式

我們已經看到Docker Image 是隻讀的模板,並隨容器一起啟動。每個Image包含了多個層。Docker Image使用的是Union File System來將這些層組合成一個Image。Union File System可以將文件和目錄(通常稱作Branch)進行透明的層疊組裝,然後形成一個單獨的文件係統。 Docker為什麼輕量,就是因為使用了這些層狀的文件係統。當用戶修改一個Docker Image的時候(比如更新應用程序)一個新的層就會被建立。因此,這是一種增量式的修改,而不是新建一個全新的Image,這也是區別於傳統虛擬機的一點。當你發布一個新的Image時,你隻需要發布差異的部分,因此速度就非常快。
每個Image都來自於一個最基礎的Image,如:ubuntu是一個基礎Image,fedora是一個基礎image。你也可以使用自己的Image作為基礎Image,比如你可以創建包含了一個Apache 服務器的Image,作為所有web應用的基礎Image。

注意:Docker通常從Docker Hub獲取基礎鏡像。

Docker的Image都是從這些基礎鏡像衍生而來的,在編譯Image是由一係列指令組成的,每個指令在我們的Image上創建一個新的曾。指令包括:

  • 執行一條命令
  • 添加文件或文件夾
  • 創建環境變量
  • 容器啟動時,運行什麼程序

Docker Registry 工作方式

Docker Registry是Image的倉庫,當你編譯完成一個Image時,你可以推送到公共的Registry,比如Docker Hub,也可以推送到你自己的私有Registry。 使用Docker Client,你可以搜索已經發布的Image,並從中拉取Image到本地,並在容器中運行。
Docker Hub提供了公有和私有的Registry。所有人都可以搜索和下載公共鏡像。私有倉庫隻有私有用戶能夠查詢和下載。

容器工作方式

一個容器由操作係統,用戶文件和元數據構成。如我們所見,每個容器都根據鏡像來生成。這個鏡像告訴Docker 容器包含什麼內容,運行什麼程序,以及其他配置信息。Docker Image是隻讀的,當一個容器運行一個Image的時候,容器會在union FS的頂層增加文件層。

假如我們運行下麵一條指令:

root@gctest:~# docker run -i -t ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
Digest: sha256:f91f9bab1fe6d0db0bfecc751d127a29d36e85483b1c68e69a246cf1df9b4251
Status: Downloaded newer image for ubuntu:latest
root@ea7ffc10c7e7:/#

我們來做一下拆解,Docker Client通過run命令告訴Daemon啟動一個新的容器。這個指令至少需要包括:

  • 需要運行什麼Image,這裏我們使用的是Ubuntu基礎鏡像
  • 需要在容器啟動時,運行什麼命令,這裏我們使用的是/bin/bash 是否需要進入應用程序,這裏我們指定的是-i -t,就是進入容器交互模式

那麼具體到內部的流程是怎麼樣的呢?

  • 拉取ubuntu鏡像:Docker檢查本地是否有ubuntu鏡像,如果不存在就自動從Docker Hub拉取。如果存在就進入下一步
  • 創建一個容器:一旦本地存在ubuntu 鏡像,Docker將通過它來創建容器
  • 分配文件係統並mount 一個RW層:容器是創建在文件係統中的,並且在其之上增加了一層讀寫層。由此可以看出容器,並不會改變原始的鏡像。
  • 分配網絡/橋接模式:創建一個橋接網絡接口,使容器可以和本地主機進行通信。
  • 設置一個IP地址:根據本地網絡情況,選取一個可用的IP掛載到容器之上
  • 啟動一個進程:這裏就是/bin/bash
  • 抓取應用程序的輸出:將程序的stdin, stdout和stderr,進行捕捉,這樣我們可以看到程序的運行情況。 至此,你就擁有了一個運行的容器。通過容器,你可以運行程序,並且進行交互,當程序執行完畢,你可以停止和刪除程序。

底層的技術

Docker是用Go編寫的,同時使用了多種內核的功能來實現我們現在所看到的功能。

Namespaces

Docker 使用了Namespace這項技術來隔離工作區,也就是我們所說的容器。當容器運行時,Docker創建了一係列的Namespace。 通過Namespaces,容器運行在它自己的獨立命名空間之中,而外層沒有訪問權限。目前,Docker使用了以下Namespace:

  • pid namespace: 用於進程的隔離(PID: Process ID)
  • net namespace: 用於管理網絡接口x(NET: Networking)
  • ipc namespace: 用於管理進程間通訊(IPC: Inter Process Communication)
  • mnt namespace: 用於管理Mount點(MNT: Mount)
  • uts namespace: 用於隔離內核和版本信息(UTS: Unix Timesharing System)

Control Groups

Docker也使用了cgroups這項內核技術,通過cgroups可以限製應用程序使用的資源,這項技術可以使用戶主機更好的運行多個容器而相互間不受影響。Cgroups可以限定容器使用的硬件資源,比如內存數量,CPU數量等。

Union File System

UnionFS用來對文件係統進行分層,通過分層可以使鏡像更加輕量級和快速。Docker可以使用多種不同的UnionFS,比如AUFS, btrfs, vfs, DeviceMapper等。

容器格式

Docker將上述的多項技術包裝在一起,形成了容器的格式。默認的容器格式是libcontainer , Docker也支持傳統的 LXC格式。在未來,Docker也許會支持其他的容器格式,比如BSD Jails 或Solaris Zones.


備注:對有興趣的朋友可以加我的微信ghostcloud2016,然後我把你加到我們的一個Docker愛好者群組裏麵。

最後更新:2017-04-01 13:38:50

  上一篇:go 熱門問題:MNS隊列消息計數實現難點淺析
  下一篇:go 最佳實踐:消息服務中如何多線程共享一個LongPolling