Docker 底層實現

Docker底層實現(一些底層原理)

Docker底層的核心技術包括Linux上的命名空間(Namespace)、控制組(Control groups)、Union文件系統(Union file systems)和容器格式(Container format)。

傳統的虛擬機通過在宿主主機中運行hypervisor來模擬一整套完整的硬件環境系統提供給虛擬機的操作系統。虛擬機系統看到的環境是可限制的,也是彼此隔離的。這種直接的做法實現了對資源的完整封裝,但很多時候往往意味着系統資源的浪費。例如,Linux上運行Linux虛擬機,虛擬機中運行的應用其實可以利用宿主機系統中的運行環境。

可以通過Linux的命名空間實現大家雖然都共用一個內核和某些運行時環境(例如一些系統命名和系統庫),但是彼此卻看不到,都以爲系統中只有自己的存在。這種機制就是容器(Container),利用Namespace來做權限的隔離控制,利用cgroups來做資源分配。

 

基本架構

Docker採用了C/S架構,包括客戶端和服務端。Docker守護進程(Daemon)作爲服務端接收來自客戶端的請求,並處理這些請求(創建、運行、分發容器)。

客戶端和服務端既可以運行在一個機器上,也可以通過socket或者RESTful API來進行通信。

Docker守護進程一般在宿主主機後臺運行,等待接收客戶端的消息。Docker客戶端則爲用戶提供一系列可執行命令,用戶用這些命令實現跟Docker守護進程交互。

 

命名空間

每個容器都有自己的單獨命名空間,運行在其中的應用都像是在獨立的操作系統中運行一樣。命名空間保證了容器之間彼此互不影響。

常見的命名空間:

pid 隔離不同用戶進程;net 網絡隔離;ipc 進程間交互隔離;mnt 文件結構的隔離;

uts 獨立host name\domain name,使其在網絡上可以被視作一個獨立的節點而非主機上的一個進程。

User 每個容器可以有不同的用戶組id。

 

控制組(control groups)

cgroups是Linux內核的一個特性,主要用來對共享資源進行隔離、限制、審計、只有能控制分配到容器的資源,才能避免當多個容器同時運行時對系統資源的競爭。控制組可以提供對容器的內存、CPU、磁盤IO等資源的限制和審計管理(之後單獨整理一篇cgroups)。

 

聯合文件系統

UnionFS是一種分層、輕量級並且高性能的文件系統,它支持對文件系統的修改作爲一次提交來一層層的疊加,同時可以將不同目錄掛載到同一個虛擬文件系統下。

聯合文件系統是Docker鏡像的基礎,鏡像可以通過分層來進行繼承,基於基礎鏡像(沒有父鏡像),可以製作各種具體的應用鏡像。這樣的話,不同Docker容器就可以共享一些基礎的文件系統,同時再加上自己獨有的改動層,大大提高了存儲的效率。

Docker中使用的AUFS(AnotherUnionFS)就是一種聯合文件系統。AUFS支持爲每一個成員目錄設定readonly/readwrite/whiteout-able權限,同時AUFS裏有一個類似分層的概念,對只讀權權限的分支可以邏輯上進行增量地修改(不影響只讀部分)。

Docker目前支持的聯合文件系統包括 OverlayFS/AUFS/Btrfs/VFS/ZFS/Device Mapper。

 

Linux版本和Docker推薦存儲驅動

 

所以說,如果不考慮太多,默認overlay2 就可以,並且overlay2也是目前Docker默認的存儲驅動(以前是aufs)。

 

 

Docker網絡實現

Docker的網絡實現是用了Linux上的網絡命名空間和虛擬網絡設備(特別是veth pair)。

要實現網絡通信,機器需要至少一個網絡接口(物理接口或者虛擬接口)來收發數據包;此外,如果不同子網之間要進行通信,需要路由機制。Docker中的網絡接口默認是虛擬的接口。虛擬接口得優勢之一是轉發效率高。Linux通過在內核中進行數據複製來實現虛擬接口之間的數據轉發,發送接口得發送緩存中的數據包被直接複製到接收緩存中。對於本地系統和容器內系統看來就像是一個正常的以太網卡,只是它不需要真正同外部網絡設備通信,速度要快很多。Docker容器網絡就是利用這項技術,在本地主機和容器內分別創建一個虛擬接口,並讓他們彼此聯通(這樣的一對接口叫 veth pair)。

Docker創建一個容器的時候,網絡方面會執行如下操作:

  1. 創建一對虛擬接口,分別放在本地主機和新容器中;
  2. 本地主機一端橋接到默認的docker0或者指定網橋上,並且有一個唯一的名字,如veth0101。
  3. 容器一端放到新容器中,並修改名字作爲eth0,這個接口只在容器的命名空間中可見;
  4. 從網橋可用地址段中獲取一個空閒地址分配給容器的eth0,並配置默認路由到橋接網卡veth0101。

之後,容器就可以使用etch0虛擬網卡來連接其他容器和其他網絡。

可以在docker run 的時候通過 --net 參數來指定容器的網絡配置,有4個可選值:

--net=bridge 這個是默認值,連接到默認的網橋。

--net=host 不進行網絡隔離,即不要容器化容器內的網絡。此時容器使用本地主機的網絡,他擁有完全的本地主機接口訪問權限。容器進程可以跟主機其他root進程一樣可以打開地範圍端口等。甚至可以進一步使用 --privileged=true,容器會被允許直接配置主機的網絡堆棧。

--net=container:NAME or ID 讓Docker將新建容器的進程放到一個已存在容器的網絡棧中。

--net=none 讓Docker將新容器放到隔離的網絡棧中,但是不進行網絡配置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章