docker鏡像,容器和存儲驅動

鏡像和層

鏡像是由一些只讀而且描繪文件系統區別的層組成的.它們一層一層堆疊起來,組成了鏡像的基礎文件系統.這些層都是隻讀的. 下圖是由4層構成的ubuntu鏡像:docker

image

而docker存儲驅動的職責就是將這些層堆疊起來.並提供一個統一的視圖.讓咱們以爲跟普通文件系統沒什麼區別.ubuntu

當你建立了一個容器時.會在鏡像的層上再添加一層叫作"容器層(container layer)",全部在運行中的容器中所作的修改操做,都是影響的這一層. 看下圖centos

container

內容可尋址的存儲

docker 1.10 開始,介紹了一種全新的尋址鏡像和層上數據的存儲模型.以前的鏡像和層上數據的存放,都是經過隨機UUID存放.新模型採用一種安全的內容hash來存放. 新模型特色包括提升了安全性.防止了id衝突,保證了pull,push,load,save操做後的數據一致性.而且更好的提供了層之間的共享問題.安全

參考圖片:bash

新模型

容器層仍是random uuid 對於新的模型,原先舊模型的鏡像數據須要從新計算id來遷移.這些操做會在你運行新版本docker進程後自動執行. 鏡像較多的話會比較耗資源.如需手工遷移請參考官方文檔.app

容器和層

容器和鏡像主要區別就在於容器多了最上層的容器層.全部在容器中的修改操做,都是影響的容器各自的容器層.底下鏡像的層都是隻讀不變的.dom

下圖展現了多個容器共享同一個鏡像,可是擁有各自的容器層.互相不受影響.ide

sharing-layers

docker的存儲驅動器的做用就是管理這些層.不一樣的驅動實現方式也不一樣.主要兩個關鍵點是如何堆疊這些層並提供統一的視圖,還有就是數據修改copy-on-write (CoW).性能

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
相關文章
相關標籤/搜索