理解Docker(7):Docker 存儲 - AUFS


(1)Docker 安裝及基本用法

(2)Docker 鏡像

(3)Docker 容器的隔離性 - 使用 Linux namespace 隔離容器的運行環境

(4)Docker 容器的隔離性 - 使用 cgroups 限制容器使用的資源

(5)Docker 網絡

(6)若干企業生產環境中的容器網絡方案

(7)Docker 存儲 - AUFS

 

  Docker 存儲可以分為分層文件系統和卷,本文將介紹 AUFS 分層文件系統。

1. 基礎知識

1.1 Linux 的 rootfs 和 bootfs

  一個典型的 Linux 系統要能運行的話,它至少需要兩個文件系統:

  • boot file system (bootfs):包含 boot loader 和 kernel。用戶不會修改這個文件系統。實際上,在啟動(boot)過程完成后,整個內核都會被加載進內存,此時 bootfs 會被卸載掉從而釋放出所占用的內存。同時也可以看出,對於同樣內核版本的不同的 Linux 發行版的 bootfs 都是一致的。
  • root file system (rootfs):包含典型的目錄結構,包括 /dev, /proc, /bin, /etc, /lib, /usr, and /tmp 等再加上要運行用戶應用所需要的所有配置文件,二進制文件和庫文件。這個文件系統在不同的Linux 發行版中是不同的。而且用戶可以對這個文件進行修改。

Linux 系統在啟動時,roofs 首先會被掛載為只讀模式,然后在啟動完成后被修改為讀寫模式,隨后它們就可以被修改了。

1.2 AUFS

 AUFS 是一種 Union File System(聯合文件系統),又叫 Another UnionFS,后來叫Alternative UnionFS,再后來叫成高大上的 Advance UnionFS。所謂 UnionFS,就是把不同物理位置的目錄合並mount到同一個目錄中。UnionFS的一個最主要的應用是,把一張CD/DVD和一個硬盤目錄給聯合 mount在一起,然后,你就可以對這個只讀的CD/DVD上的文件進行修改(當然,修改的文件存於硬盤上的目錄里)。

  舉個例子,在 Ubuntu 14.04 系統上現有如下目錄結構:

$ tree
.
├── fruits
│   ├── apple
│   └── tomato
└── vegetables
    ├── carrots
    └── tomato

輸入以下幾個命令:

# 創建一個mount目錄
$ mkdir mnt
 
# 把水果目錄和蔬菜目錄union mount到 ./mnt目錄中
$ sudo mount -t aufs -o dirs=./fruits:./vegetables none ./mnt
 
#  查看./mnt目錄
$ tree ./mnt
./mnt
├── apple
├── carrots
└── tomato

我們可以看到在./mnt目錄下有三個文件,蘋果apple、胡蘿卜carrots和蕃茄tomato。水果和蔬菜的目錄被union到了./mnt目錄下了。

我們來修改一下其中的文件內容:

$ echo mnt > ./mnt/apple
$ cat ./mnt/apple
mnt
$ cat ./fruits/apple
mnt

上面的示例,我們可以看到./mnt/apple的內容改了,./fruits/apple的內容也改了。

$ echo mnt_carrots > ./mnt/carrots
$ cat ./vegetables/carrots
 
$ cat ./fruits/carrots
mnt_carrots

關於 AUFS 的幾個特點:

  • AUFS 是一種聯合文件系統,它把若干目錄按照順序和權限 mount 為一個目錄並呈現出來
  • 默認情況下,只有第一層(第一個目錄)是可寫的,其余層是只讀的。
  • 增加文件:默認情況下,新增的文件都會被放在最上面的可寫層中。
  • 刪除文件:因為底下各層都是只讀的,當需要刪除這些層中的文件時,AUFS 使用 whiteout 機制,它的實現是通過在上層的可寫的目錄下建立對應的whiteout隱藏文件來實現的。
  • 修改文件:AUFS 利用其 CoW (copy-on-write)特性來修改只讀層中的文件。AUFS 工作在文件層面,因此,只要有對只讀層中的文件做修改,不管修改數據的量的多少,在第一次修改時,文件都會被拷貝到可寫層然后再被修改。
  • 節省空間:AUFS 的 CoW 特性能夠允許在多個容器之間共享分層,從而減少物理空間占用。
  • 查找文件:AUFS 的查找性能在層數非常多時會出現下降,層數越多,查找性能越低,因此,在制作 Docker 鏡像時要注意層數不要太多。
  • 性能:AUFS 的 CoW 特性在寫入大型文件時第一次會出現延遲。

本部分內容主要應用自 Docker基礎技術:AUFS。 

2. Docker 文件系統

2.1 Docker 鏡像的 rootfs

  前面基礎知識部分談到過,同一個內核版本的所有 Linux 系統的 bootfs 是相同的,而 rootfs 則是不同的。在 Docker 中,基礎鏡像中的 roofs 會一直保持只讀模式,Docker 會利用 union mount 來在這個 rootfs 上增加更多的只讀文件系統,最后它們看起來就像一個文件系統即容器的 rootfs。

 (圖片來源

可見在一個Linux 系統之中,

  • 所有 Docker 容器都共享主機系統的 bootfs 即 Linux 內核
  • 每個容器有自己的 rootfs,它來自不同的 Linux 發行版的基礎鏡像,包括 Ubuntu,Debian 和 SUSE 等
  • 所有基於一種基礎鏡像的容器都共享這種 rootfs

以 training/webapp 鏡像為例,

root@docker1:/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa# docker history training/webapp
IMAGE               CREATED             CREATED BY                                      SIZE                COMMENT
6fae60ef3446        16 months ago       /bin/sh -c #(nop) CMD ["python" "app.py"]       0 B
<missing>           16 months ago       /bin/sh -c #(nop) EXPOSE 5000/tcp               0 B
<missing>           16 months ago       /bin/sh -c #(nop) WORKDIR /opt/webapp           0 B
<missing>           16 months ago       /bin/sh -c #(nop) ADD dir:9b2a69f6f30d18b02b5   703 B
<missing>           16 months ago       /bin/sh -c pip install -qr /tmp/requirements.   4.363 MB
<missing>           16 months ago       /bin/sh -c #(nop) ADD file:c59059439864153904   41 B
<missing>           16 months ago       /bin/sh -c DEBIAN_FRONTEND=noninteractive apt   135.3 MB
<missing>           16 months ago       /bin/sh -c apt-get update                       20.8 MB
<missing>           16 months ago       /bin/sh -c #(nop) MAINTAINER Docker Education   0 B
<missing>           17 months ago       /bin/sh -c #(nop) CMD ["/bin/bash"]             0 B
<missing>           17 months ago       /bin/sh -c sed -i 's/^#\s*\(deb.*universe\)$/   1.895 kB
<missing>           17 months ago       /bin/sh -c echo '#!/bin/sh' > /usr/sbin/polic   194.5 kB
<missing>           17 months ago       /bin/sh -c #(nop) ADD file:f4d7b4b3402b5c53f2   188.1 MB

它是基於 Ubuntu Docker 基礎鏡像。在基礎鏡像層中,我們能看到完整的 Ubuntu rootfs:

root@docker1:/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa# ls -l
total 76
drwxr-xr-x  2 root root 4096 Apr 27  2015 bin
drwxr-xr-x  2 root root 4096 Apr 11  2014 boot
drwxr-xr-x  3 root root 4096 Apr 27  2015 dev
drwxr-xr-x 61 root root 4096 Apr 27  2015 etc
drwxr-xr-x  2 root root 4096 Apr 11  2014 home
drwxr-xr-x 12 root root 4096 Apr 27  2015 lib
drwxr-xr-x  2 root root 4096 Apr 27  2015 lib64
drwxr-xr-x  2 root root 4096 Apr 27  2015 media
drwxr-xr-x  2 root root 4096 Apr 11  2014 mnt
drwxr-xr-x  2 root root 4096 Apr 27  2015 opt
drwxr-xr-x  2 root root 4096 Apr 11  2014 proc
drwx------  2 root root 4096 Apr 27  2015 root
drwxr-xr-x  7 root root 4096 Apr 27  2015 run
drwxr-xr-x  2 root root 4096 Apr 27  2015 sbin
drwxr-xr-x  2 root root 4096 Apr 27  2015 srv
drwxr-xr-x  2 root root 4096 Mar 13  2014 sys
drwxrwxrwt  2 root root 4096 Apr 27  2015 tmp
drwxr-xr-x 10 root root 4096 Apr 27  2015 usr
drwxr-xr-x 11 root root 4096 Apr 27  2015 var

我們來看兩種典型的文件:

(1)bin 目錄中的文件會被直接使用

root@docker1:/var/lib/docker/aufs/diff# find -iname mountpoint
./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/bin/mountpoint

(2)在基礎鏡像層中 proc 目錄為空,也就是說容器中看到的 proc 目錄中的文件是后來生成的。

2.2 Docker 使用的 AUFS 文件系統

  關於 Docker的分層鏡像,除了 aufs,docker還支持btrfs, devicemapper和vfs,你可以使用 -s 或 –storage-driver= 選項來指定相關的鏡像存儲。在Ubuntu 14.04下,Docker 默認 Ubuntu的 AUFS。因為 AUFS 還沒有進入Linux 內核主干的原因,RedHat 上使用的是 devicemapper。

  我們可以在 docker info 命令的輸出中查看所使用的存儲驅動:

Storage Driver: aufs
 Root Dir: /var/lib/docker/aufs
 Backing Filesystem: extfs
 Dirs: 19
 Dirperm1 Supported: false

以一個正在運行着的 Docker 容器為例,其鏡像有13層:

"RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:1154ba695078d29ea6c4e1adb55c463959cd77509adf09710e2315827d66271a",
                "sha256:528c8710fd95f61d40b8bb8a549fa8dfa737d9b9c7c7b2ae55f745c972dddacd",
                "sha256:37ee47034d9b78f10f0c5ce3a25e6b6e58997fcadaf5f896c603a10c5f35fb31",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:b75c0703b86b8ccbdc1f1b28b4982774768861ac250f83bdb940b1e90291f302",
                "sha256:5c121779bb29172c628a21087ea8ced766959da2f223c8b6bd4ffe943ace43d8",
                "sha256:3ee91c5cb95b01496b4afdc721ba7fd3c22e0e5e2f3e9e70d3f8579b5082d4f3",
                "sha256:6bbb1d0f845289217e20b66697fa7d651394d89983b0f5a89b88f037194476fe",
                "sha256:b44b0832d4c6bf33122ce3aa896b133df88275e6d20663a9bf2d941f764ac1fd",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
            ]
        }

從 AUFS 的角度,可以看到有一個可寫的容器層和14個只讀的鏡像層:

root@docker1:/sys/fs/aufs/si_ab487e40195df24f# cat *
/var/lib/docker/aufs/diff/2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab=rw           #可寫的容器層
/var/lib/docker/aufs/diff/2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab-init=ro+wh   #本層及以下是只讀的鏡像層
/var/lib/docker/aufs/diff/5472f8388f9a61f6bd84498201a5ad71a2ec88cda16c42a3a1da7c30da45f102=ro+wh
/var/lib/docker/aufs/diff/61dcf0881e790bf52ec555727b58641791adeefadcc7abc2a77fd228bde1371a=ro+wh
/var/lib/docker/aufs/diff/f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e=ro+wh
/var/lib/docker/aufs/diff/45818d286499870412357d66eb6af951699f89db785c7c6a242d2e1ac99734f9=ro+wh
/var/lib/docker/aufs/diff/b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa=ro+wh
/var/lib/docker/aufs/diff/85cb840562788e1b458e68265e62fd2da9d0d7e737256500e8a276bcb237183c=ro+wh
/var/lib/docker/aufs/diff/c18ba8efcb455e97f6aabe3985b147f6a37b8f5ad090373e88ddd326b4f90896=ro+wh
/var/lib/docker/aufs/diff/25de7dcc3a06f0caa3c701d4ed6c62f03e0757f6d477cc822db6e884bb366441=ro+wh
/var/lib/docker/aufs/diff/ad9e831217594cdfecd5e824690b0e52f2e16d6e2bb39b7143e66d467150cfe8=ro+wh
/var/lib/docker/aufs/diff/56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0=ro+wh
/var/lib/docker/aufs/diff/31bc6290457af4e560a3103020c85fbb5dfcfb201b0662a33165260529f87c07=ro+wh
/var/lib/docker/aufs/diff/e104672666119006648d0b82988c49527e52c64629750c5c9adde88acc790682=ro+wh
/var/lib/docker/aufs/diff/7a085e415855435121fb7837c26a5e951f622bc69364d9228d409a4929b627e1=ro+wh

根據上面 AUFS 的定義,容器的文件系統是從 14 個只讀鏡像層和1個可寫容器層通過 AUFS mount 出來的。示意圖如下:

圖片來源

這種分層文件系統可以通過官網的圖來清晰的展示出來:

做一些實驗:

(1)在容器中創建一個文件,該文件會被創建在可寫的容器層中

root@docker1:/var/lib/docker/aufs/diff# find -iname createdbysammy
./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/opt/webapp/createdbysammy
root@docker1:/var/lib/docker/aufs/diff# ls -lt
total 60
drwxr-xr-x  9 root root 4096 Oct  4 22:37 2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab
drwxr-xr-x  6 root root 4096 Oct  1 11:56 2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab-init

(2)修改一個鏡像層中的文件

修改前,文件 /etc/apt/sources.list 出現在兩個層中:

root@docker1:/var/lib/docker/aufs/diff# find -iname sources.list
./f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e/etc/apt/sources.list
./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/etc/apt/sources.list

在容器中對它進行修改后,它被拷貝到了容器層然后被修改了:

root@docker1:/var/lib/docker/aufs/diff# find -iname sources.list
./f68672aaf17dd158aabc635b2d8d459d79db1cd5ff38bf3834fe8f9c7a05235e/etc/apt/sources.list
./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/etc/apt/sources.list
./b2188d5c09cfe24acd6da5ce67720f81138f0c605a25efc592f1f55b3fd3dffa/etc/apt/sources.list

而另外兩個層中的文件保持了不變。這說明了 AUFS 的 CoW 特性。

(3)刪除容器層中的文件

容器中的文件 ./usr/local/lib/python2.7/dist-packages/itsdangerous.py 位於 56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0 層中,這是一個只讀層。

在容器內刪除它:

root@fa385836d5b9:/# find -iname itsdangerous.py
./usr/local/lib/python2.7/dist-packages/itsdangerous.py
root@fa385836d5b9:/# rm ./usr/local/lib/python2.7/dist-packages/itsdangerous.py
root@fa385836d5b9:/# find -iname itsdangerous.py

然后,容器層中出現了一個 .wh 文件,而鏡像層中的文件保持不變:

root@docker1:/var/lib/docker/aufs/diff# find -iname *itsdangerous.py
./56d37c8eecd8be9ba13e07e1486e7a6ac2f0aa01f8e865ee6136137369d8d8a0/usr/local/lib/python2.7/dist-packages/itsdangerous.py
./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/usr/local/lib/python2.7/dist-packages/.wh.itsdangerous.py

在手工將 .wh 文件刪除后,文件就會再次回到容器中。

 rm ./2ee58d81e4ac6811bbc78beb4b46bf213c79c9e2dc7e441741afc8c4349c6bab/usr/local/lib/python2.7/dist-packages/.wh.itsdangerous.py
root@fa385836d5b9:/# find -iname itsdangerous.py
./usr/local/lib/python2.7/dist-packages/itsdangerous.py

 

參考鏈接:

 


免責聲明!

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



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