Docker-原理解析


容器!

Linux容器是與系統其他部分隔離開的一系列進程,從另一個鏡像運行,並由該鏡像提供支持進程所需的全部文件。容器提供的鏡像包含了應用的所有依賴項,因而在從開發到測試再到生產的整個過程中,它都具有可移植性和一致性。

 

虛擬化和容器的區別

虛擬化使得許多操作系統可同時在單個系統上運行。

容器則可共享同一個操作系統內核,將應用進程與系統其他部分隔離開

 

 

 

首先,讓多個操作系統在單個虛擬機監控程序上運行以實現虛擬化,並不能達成和使用容器同等的輕量級效果。事實上,在僅擁有容量有限的有限資源時,您需要能夠可以進行密集部署的輕量級應用。Linux 容器可從單個操作系統運行,在所有容器中共享該操作系統,因此應用和服務能夠保持輕量級,並行快速運行。

比較

 

 

Docker!

Docker 是一個開源的應用容器引擎,可以輕松的為任何應用創建一個輕量級的、可移植的、自給自足的容器。開發者在本地編譯測試通過的容器可以批量地在生產環境中部署,包括VMs(虛擬機)、bare metal、OpenStack 集群和其他的基礎應用平台。Docker平台就是一個軟件集裝箱化平台,這就意味着我們自己可以構建應用程序,將其依賴關系一起打包到一個容器中,然后這容器就很容易運送到其他的機器上進行運行,而且非常易於裝載、復制、移除,非常適合軟件彈性架構。

 

Docker 基本概念

鏡像——特殊的文件系統

操作系統分為內核和用戶空間。對於 Linux 而言,內核啟動后,會掛載 root 文件系統為其提供用戶空間支持。而 Docker 鏡像(Image),就相當於是一個 root 文件系統。
Docker 鏡像是一個特殊的文件系統,除了提供容器運行時所需的程序、庫、資源、配置等文件外,還包含了一些為運行時准備的一些配置參數(如匿名卷、環境變量、用戶等)。
鏡像不包含任何動態數據,其內容在構建之后也不會被改變。
Docker 設計時,就充分利用 Union FS 的技術,將其設計為分層存儲的架構。 鏡像實際是由多層文件系統聯合組成。
鏡像構建時,會一層層構建,前一層是后一層的基礎。每一層構建完就不會再發生改變,后一層上的任何改變只發生在自己這一層。
比如,刪除前一層文件的操作,實際不是真的刪除前一層的文件,而是僅在當前層標記為該文件已刪除。
在最終容器運行的時候,雖然不會看到這個文件,但是實際上該文件會一直跟隨鏡像。
因此,在構建鏡像的時候,需要額外小心,每一層盡量只包含該層需要添加的東西,任何額外的東西應該在該層構建結束前清理掉。
分層存儲的特征還使得鏡像的復用、定制變的更為容易。甚至可以用之前構建好的鏡像作為基礎層,然后進一步添加新的層,以定制自己所需的內容,構建新的鏡像。

補充知識,

UnionFS
聯合文件系統(Union File System):2004年由紐約州立大學石溪分校開發,它可以把多個目錄(也叫分支)內容聯合掛載到同一個目錄下,而目錄的物理位置是分開的。
UnionFS允許只讀和可讀寫目錄並存,就是說可同時刪除和增加內容。UnionFS應用的地方很多,比如在多個磁盤分區上合並不同文件系統的主目錄,或把幾張CD光盤合並成
一個統一的光盤目錄(歸檔)。另外,具有寫時復制(copy
-on-write)功能UnionFS可以把只讀和可讀寫文件系統合並在一起,虛擬上允許只讀文件系統的修改可以保存到可
寫文件系統當中。

容器:鏡像運行的實例

鏡像(Image)和容器(Container)的關系,就像是面向對象程序設計中的類和實例一樣,鏡像是靜態的定義,容器是鏡像運行時的實體。
容器可以被創建、啟動、停止、刪除、暫停等 。 容器的實質是進程,但與直接在宿主執行的進程不同,容器進程運行於屬於自己的獨立的命名空間。前面講過鏡像使用的是分層存儲,容器也是如此。 容器存儲層的生存周期和容器一樣,容器消亡時,容器存儲層也隨之消亡。因此,任何保存於容器存儲層的信息都會隨容器刪除而丟失。 按照 Docker 最佳實踐的要求,容器不應該向其存儲層內寫入任何數據 ,容器存儲層要保持無狀態化。 所有的文件寫入操作,都應該使用數據卷(Volume)、或者綁定宿主目錄,在這些位置的讀寫會跳過容器存儲層,直接對宿主(或網絡存儲)發生讀寫,其性能和穩定性更高。 數據卷的生存周期獨立於容器,容器消亡,數據卷不會消亡。因此, 使用數據卷后,容器可以隨意刪除、重新 run,數據卻不會丟失

 

倉庫:集中存放鏡像文件的地方

鏡像構建完成后,可以很容易的在當前宿主上運行,但是, 如果需要在其他服務器上使用這個鏡像,我們就需要一個集中的存儲、分發鏡像的服務,Docker Registry 就是這樣的服務
一個 Docker Registry 中可以包含多個倉庫(Repository);每個倉庫可以包含多個標簽(Tag);每個標簽對應一個鏡像。

通常,一個倉庫會包含同一個軟件不同版本的鏡像,而標簽就常用於對應該軟件的各個版本 。
我們可以通過<倉庫名>:<標簽>的格式來指定具體是這個軟件哪個版本的鏡像。如果不給出標簽,將以 latest 作為默認標簽。

 

命名空間「Namespaces」

pid namespace

pid namespace
不同用戶的進程就是通過 pid namespace 隔離開的,且不同 namespace 中可以有相同 PID。具有以下特征:

每個 namespace 中的 pid 是有自己的 pid=1 的進程(類似 /sbin/init 進程)
每個 namespace 中的進程只能影響自己的同一個 namespace 或子 namespace 中的進程
因為 /proc 包含正在運行的進程,因此在 container 中的 pseudo-filesystem 的 /proc 目錄只能看到自己 namespace 中的進程
因為 namespace 允許嵌套,父 namespace 可以影響子 namespace 的進程,所以子 namespace 的進程可以在父 namespace 中看到,但是具有不同的 pid

 

mnt namespace

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

net namespace

網絡隔離是通過 net namespace 實現的, 每個 net namespace 有獨立的 network devices, IP addresses, IP routing tables, /proc/net 目錄。
這樣每個 container 的網絡就能隔離開來。 docker 默認采用 veth 的方式將 container 中的虛擬網卡同 host 上的一個 docker bridge 連接在一起。

 

uts namespace

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

 

ipc namespace

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

 

user namespace

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

 

有了以上 6 種 namespace 從進程、網絡、IPC、文件系統、UTS 和用戶角度的隔離,一個 container 就可以對外展現出一個獨立計算機的能力,並且不同 container 從 OS 層面實現了隔離。

然而不同 namespace 之間資源還是相互競爭的,仍然需要類似 ulimit 來管理每個 container 所能使用的資源 - cgroup。

資源配額「cgroups」

cgroups 實現了對資源的配額和度量。 cgroups 的使用非常簡單,提供類似文件的接口,在 /cgroup 目錄下新建一個文件夾即可新建一個 group,
在此文件夾中新建 task 文件,並將 pid 寫入該文件,即可實現對該進程的資源控制。具體的資源配置選項可以在該文件夾中新建子 subsystem ,
{子系統前綴}.{資源項} 是典型的配置方法, 如 memory.usageinbytes 就定義了該 group 在 subsystem memory 中的一個內存限制選項。
另外,cgroups 中的 subsystem 可以隨意組合,一個 subsystem 可以在不同的 group 中,也可以一個 group 包含多個 subsystem -
也就是說一個 subsystem。

 

 

 

 

Docker實際應用

簡化配置!

容器鏡像打包完成后,它就是個獨立的個體了,丟到哪里都能跑,而無需針對各個平台去獨立配置。

 

代碼流水線(code pipeline)管理

代碼從開發者的機器到最終在生產環境上的部署,需要經過很多的中間環境。而每一個中間環境都有自己微小的差別,Docker給應用提供了一個從開發到上線均一致的環境,讓代碼的流水線變得簡單

 

提高開發效率

 一般的情況下搭建多個生成服務應用。一台一般配置服務器或開發機也能輕松的跑起多個Docker應用,而無需額外增加機器配置。因為Docker有個非常NB的特性,擁有虛擬化的特性

而幾乎沒有額外的開銷。

 

隔離應用

一台服務器上運行多個不同的應用,經常需要考慮三點,一是因為要降低成本而進行服務器整合,二是將一個整體式的應用拆分成松耦合的單個服務(比如微服務架構)

三是還需要考慮應用之間的兼容性。而對於Docker來說,支持起來就非常簡單了。同一台機器,我可以同時運行N個Docker web應用,托管到不同的Web服務器(Kestrel、Ngnix、Tomcat)

 

整合服務器

ocker隔離應用的能力使得Docker可以整合多個服務器以降低成本。由於沒有多個操作系統的內存占用,以及能在多個實例之間共享沒有使用的內存,Docker可以比虛擬機提供更好的服務器整合解決方案。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM