鏡像是由一些只讀而且描繪文件系統區別的層組成的.它們一層一層堆疊起來,組成了鏡像的基礎文件系統.這些層都是隻讀的. 下圖是由4層構成的ubuntu鏡像:docker
而docker存儲驅動的職責就是將這些層堆疊起來.並提供一個統一的視圖.讓咱們以爲跟普通文件系統沒什麼區別.ubuntu
當你建立了一個容器時.會在鏡像的層上再添加一層叫作"容器層(container layer)",全部在運行中的容器中所作的修改操做,都是影響的這一層. 看下圖centos
docker 1.10 開始,介紹了一種全新的尋址鏡像和層上數據的存儲模型.以前的鏡像和層上數據的存放,都是經過隨機UUID存放.新模型採用一種安全的內容hash來存放. 新模型特色包括提升了安全性.防止了id衝突,保證了pull,push,load,save操做後的數據一致性.而且更好的提供了層之間的共享問題.安全
參考圖片:bash
容器層仍是random uuid 對於新的模型,原先舊模型的鏡像數據須要從新計算id來遷移.這些操做會在你運行新版本docker進程後自動執行. 鏡像較多的話會比較耗資源.如需手工遷移請參考官方文檔.app
容器和鏡像主要區別就在於容器多了最上層的容器層.全部在容器中的修改操做,都是影響的容器各自的容器層.底下鏡像的層都是隻讀不變的.dom
下圖展現了多個容器共享同一個鏡像,可是擁有各自的容器層.互相不受影響.ide
docker的存儲驅動器的做用就是管理這些層.不一樣的驅動實現方式也不一樣.主要兩個關鍵點是如何堆疊這些層並提供統一的視圖,還有就是數據修改copy-on-write (CoW).性能
全部鏡像層和容器層,都存儲在主機的存儲區域,而後經過存儲驅動來管理.一般是'/var/lib/docker/'目錄ui
[root@srv00 ~]# docker pull ubuntu Using default tag: latest latest: Pulling from library/ubuntu 6d28225f8d96: Pull complete 166102ec41af: Pull complete d09bfba2bd6a: Pull complete c80dad39a6c0: Pull complete a3ed95caeb02: Pull complete Digest: sha256:5718d664299eb1db14d87db7bfa6945b28879a67b74f36da3e34f5914866b71c Status: Downloaded newer image for ubuntu:latest
咱們拉取一個ubuntu鏡像,能夠看到由5層組成,在docker1.10前的版本.鏡像層存放目錄就是id.1.10以後就不一樣了.
[root@srv00 layerdb]# docker inspect ubuntu ... "RootFS": { "Type": "layers", "Layers": [ "sha256:7aae4540b42d10456f8fdc316317b7e0cf3194ba743d69f82e1e8b10198be63c", "sha256:3ce512daaf78307e3a2c5adef7741d9ce9d61449a9a642cafd9f474a50e8c5d0", "sha256:7f18b442972bf737eadfff445088375d38f0f455f25ea94277b70050de3ae4b1", "sha256:a3b5c80a4ebaf7a0a1b92219b3dfb7109a14b38bebd6b55870a3aec90743a263", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" ] } ... [root@srv00 ~]# ll /var/lib/docker/image/devicemapper/layerdb/sha256 ... ``` > '1.10'版本先後儘管管理方式不一樣.docker 仍是會處理好層的共享問題. 咱們製做個鏡像,看看鏡像間的層共享.
[root@srv00 ~]# mkdir test-ubuntu [root@srv00 ~]# cd test-ubuntu/ [root@srv00 test-ubuntu]# cat Dockerfile FROM ubuntu:latest RUN echo "Hello world" > /tmp/newfile [root@srv00 test-ubuntu]# docker build -t test-ubuntu . Sending build context to Docker daemon 2.048 kB Step 1 : FROM ubuntu:latest ---> c5f1cf30c96b Step 2 : RUN echo "Hello world" > /tmp/newfile ---> Running in 2ae7ab3a167b ---> 21c10e6721e0 Removing intermediate container 2ae7ab3a167b Successfully built 21c10e6721e0
> 咱們建立了一個新的鏡像,鏡像ID是`21c10e6721e0`.
[root@srv00 test-ubuntu]# docker history 21c10e6721e0 IMAGE CREATED CREATED BY SIZE COMMENT 21c10e6721e0 About a minute ago /bin/sh -c echo "Hello world" > /tmp/newfile 12 B
c5f1cf30c96b 3 weeks ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0 B
<missing> 3 weeks ago /bin/sh -c sed -i 's/^#\s*(deb.universe)$/ 1.895 kB
<missing> 3 weeks ago /bin/sh -c rm -rf /var/lib/apt/lists/ 0 B
<missing> 3 weeks ago /bin/sh -c set -xe && echo '#!/bin/sh' > /u 701 B
<missing> 3 weeks ago /bin/sh -c #(nop) ADD file:ffc85cfdb5e66a5b4f 120.7 MB
[root@srv00 test-ubuntu]# docker inspect test-ubuntu ...... "RootFS": { "Type": "layers", "Layers": [ "sha256:7aae4540b42d10456f8fdc316317b7e0cf3194ba743d69f82e1e8b10198be63c", "sha256:3ce512daaf78307e3a2c5adef7741d9ce9d61449a9a642cafd9f474a50e8c5d0", "sha256:7f18b442972bf737eadfff445088375d38f0f455f25ea94277b70050de3ae4b1", "sha256:a3b5c80a4ebaf7a0a1b92219b3dfb7109a14b38bebd6b55870a3aec90743a263", "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef", "sha256:bf8dd5e3aefb6c212ecfbc1fc72f014d9f93c30ca78546b78079423c4b4e7665" ] } ...
> `21c10e6721e0`鏡像層堆疊在ubuntu鏡像之上.`inspect`的結果也是5層的id相同.多了一層. > 新的模型因爲歷史數據再也不存在每層的配置文件中.而是以文本形式存放在整個鏡像級別的配置文件中.因此以上的鏡像層`<missing>`是正常的. 官方的圖: ![saving-space](https://docs.docker.com/engine/userguide/storagedriver/images/saving-space.jpg) > 新模型的存儲方式極大的節省了空間. ### 容器中的cow 以前也提到了.多個容器如何共享底層的鏡像層.可是擁有各自可寫的容器層. 當容器中須要修改數據時,就會進行cow操做.可是不一樣的存儲驅動.工做方式會有所不一樣. `AUFS`和`OverlayFS`存儲驅動的cow操做方式: - 從最上層依次往下層查找須要修改的數據. - 一旦找到,就將數據副本copy到容器層. - 在容器層進行修改操做. > Btrfs, ZFS, 等工做方式有些區別..centos 默認使用`devicemapper`,使用`docker info`查看. > 因此說若是對容器有大量的寫操做.會極大增長容器體積.官方推薦使用數據卷. 這種操做方式會致使性能方面的影響.各個存儲驅動的影響各不相同. 大文件的修改,大量的鏡像層.很深的目錄樹.影響更甚.(因此官方推薦寫dockerfile時要縮減指令.多個指令合併). 咱們看看運行同一個鏡像的多個容器,產生的容器層
[root@srv00 ~]# docker run -itd test-ubuntu /bin/bash 76233b0ee89b2a55a449ac4778bf1f1146e77b928ab3474ee030895c247d257d [root@srv00 ~]# docker run -itd test-ubuntu /bin/bash 2bacfc63c3941d0c817b5f02e55d526344b1a769a3443b35110021c3bcfc9978 [root@srv00 ~]# docker run -itd test-ubuntu /bin/bash 65447ded6aa8fe4b965f30d370d9707301f069be8416f704b6d3de57de5ece58 [root@srv00 ~]# ll /var/lib/docker/containers/ total 20 drwx------ 3 root root 4096 May 25 14:46 2bacfc63c3941d0c817b5f02e55d526344b1a769a3443b35110021c3bcfc9978 drwx------ 3 root root 4096 May 25 14:46 65447ded6aa8fe4b965f30d370d9707301f069be8416f704b6d3de57de5ece58 drwx------ 3 root root 4096 May 25 14:46 76233b0ee89b2a55a449ac4778bf1f1146e77b928ab3474ee030895c247d257d
> 容器一旦建立.docker會分配一個容器層.而後分配一個UUID. > docker經過cow的方式一樣也加快了容器的啓動速度.只需簡單建立一個很小的容器層. ### 數據卷和存儲驅動. 當容器被刪除,全部容器內的修改都會隨着容器一塊兒刪除..因此若是須要持久化的數據,要使用數據卷.而且數據卷也能夠在多個容器中共享... 數據卷是繞過docker的存儲驅動的. 關於數據卷不少內容在上篇blog中已說過. ## 詳細參考: [Understand images, containers, and storage drivers](https://docs.docker.com/engine/userguide/storagedriver/imagesandcontainers/) //END