Docker 存儲引擎對於普通開發人員來講可能並不關心,主要是性能和穩定性上的綜合考慮,不過 Docker 存儲引擎的設計思想仍是很是值得學習的。python
Docker 存儲引擎的核心思想是「層」的概念,理解了這個層,就基本能夠理解它的設計思路。docker
當咱們拉取一個 Docker 鏡像的時候,每每看到以下界面。json
一個鏡像被分紅許多的「層」,每「層」包含了若干的文件,而一層層堆疊起來就組成了咱們的一個完整的鏡像。咱們鏡像中的文件就是全部「層」文件的並集。ubuntu
咱們構建 Docker 鏡像通常採用 Dockerfile 的方式,而 Dockerfile 的每行命令,其實就會生成一個「層」,即便什麼文件都沒有添加。緩存
FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py
複製代碼
Docker 的鏡像(image)是靜態的,因此當鏡像構建完成後,全部的層都是隻讀的,並會賦予一個惟一的 ID。而容器(container)是動態的,當容器啓動後,Docker 會給這個容器建立一個可讀寫「層」,位於全部鏡像「層」的最上面。咱們對容器的全部操做也就是在這個「層」裏完成,當咱們執行 docker commit
將容器生成鏡像的時候,就是把這個「層」給拍了個快照,添加了一個新的只讀層。bash
文件的建立是在讀寫層增長文件,那修改和刪除呢?服務器
這就要提一下 Docker 設計的 copy-on-write (CoW) 策略。併發
當咱們試圖讀取一個文件時,Docker 會從上到下一層層去找這個文件,找到的第一個就是咱們的文件。因此下面層相同的文件就被「覆蓋」了。而修改就是當咱們找到這個文件時,將它「複製」到讀寫層並修改,這樣讀寫層的文件就是咱們修改後的文件,而且「覆蓋」了鏡像中的文件了。而刪除就是建立了一個特殊的 whiteout
文件,這個 whiteout
文件覆蓋的文件即表示刪除了。app
這樣的設計有什麼好處嗎?高併發
顯而易見的就是減小了存儲空間,因爲鏡像被分紅了多個層,而各個層是靜態只讀的,是能夠共享的。當你從一個鏡像構建另外一個鏡像時,只須要添加新的層,原有的層不會被複制。
咱們能夠用 docker history
命令查看咱們建立的鏡像,相同的層將共享且只保存一份。
咱們能夠在系統的 /var/lib/docker/<存儲驅動>/
下看到咱們全部的層。
第二個好處是啓動容器就變得很是輕量和快速。由於咱們的容器只是添加了一個「空」的讀寫層,其餘的都是複用的只讀層,須要用時纔會去搜索。
所以,服務器上存儲了上百個鏡像,啓動了上千個容器,一點也不費力。
Docker 的存儲引擎設計思路是這樣,可是針對不一樣的文件系統,是由不一樣的存儲驅動去實現的。下面咱們來聊聊 Docker 的存儲驅動。
Docker 主要有一下幾類存儲驅動:
須要注意的是,overlay2,overlay,aufs 的層是基於文件的,當單文件的寫併發較高時須要大內存的支持,且讀寫層可能由於單個文件而變得很大。devicemapper,btrfs,zfs 的層是基於塊存儲的,所以對於單個文件的高併發影響不大。可是 btrfs 和 zfs 很是消耗內存。
有條件的狀況下,咱們仍是建議選擇 overlay2 的存儲驅動。
配置 Docker 存儲驅動很是簡單,只須要修改配置文件便可。
注意,若是你原先有不一樣存儲驅動的層數據,更換存儲驅動後將不可用,建議備份鏡像並清除 /var/lib/docker
下全部數據。
備份鏡像能夠用 docker save
導出鏡像,以後用 docker load
導入鏡像。
建立或修改文件 /etc/docker/daemon.json
並添加
{
"storage-driver": "overlay2"
}
複製代碼
而後重啓 Docker
systemctl restart docker
複製代碼
下面咱們重點講講 overlayFS(overlay2 和 overlay)。
overlayFS 是從 aufs 之上改進和簡化而來的,比 aufs 和 devicemapper 有更好的性能,大部分狀況下也比 btrfs 好。
它將文件簡化爲上、下兩層,上面的稱爲 upperdir
,可讀寫,下面的稱爲 lowerdir
,只讀,統一後暴露的視圖稱爲 merged
。
它有以下特性:
頁緩存:overlayFS 支持頁緩存分享,多個容器若是讀取相同層的同一個文件,能夠共享頁緩存,有效利用內存,使得它對於高併發讀場景十分高效。
層查找:因爲第一次修改只讀層文件時須要複製到讀寫層,因此對於大文件會有一些延遲。可是 overlayFS 仍是比 aufs 更快,由於在搜索和緩存方面作了很多優化。
重命名:overlayFS 不支持不一樣層文件的重命名操做,須要修改成複製而後刪除。