Docker筆記

AUFS是一種Union File System,所謂UnionFS就是把不一樣物理位置的目錄合併mount到同一個目錄中。UnionFS的一個最主要的應用是,把一張CD/DVD和一個硬盤目錄給聯合 mount在一塊兒,而後,你就能夠對這個只讀的CD/DVD上的文件進行修改(固然,修改的文件存於硬盤上的目錄裏)。html

AUFS又叫Another UnionFS,後來叫Alternative UnionFS,後來可能以爲不夠霸氣,叫成Advance UnionFS。是個叫Junjiro Okajima(岡島順治郎)在2006年開發的,AUFS徹底重寫了早期的UnionFS 1.x,其主要目的是爲了可靠性和性能,而且引入了一些新的功能,好比可寫分支的負載均衡。AUFS在使用上全兼容UnionFS,並且比以前的UnionFS在穩定性和性能上都要好不少,後來的UnionFS 2.x開始抄AUFS中的功能。可是他竟然沒有進到Linux主幹裏,就是由於Linus不讓,基本上是由於代碼量比較多,並且寫得爛(相對於只有3000行的union mount和10000行的UnionFS,以及其它平均下來只有6000行代碼左右的VFS,AUFS竟然有30000行代碼),因此,岡島不斷地改進代碼質量,不斷地提交,不斷地被Linus拒掉,因此,到今天AUFS都還進不了Linux主幹(今天你能夠看到AUFS的代碼其實還好了,比起OpenSSL好N倍,要麼就是Linus對代碼的質量要求很是高,要麼就是Linus就是不喜歡AUFS)。linux

不過,好在有不少發行版都用了AUFS,好比:Ubuntu 10.04,Debian6.0, Gentoo Live CD支持AUFS,因此,也OK了。docker

好了,扯完這些閒話,咱們仍是看一個示例吧(環境:Ubuntu 14.04)shell

$ tree.ubuntu

├── fruitsbash

│   ├── apple網絡

│   └── tomatoapp

└── vegetables負載均衡

    ├── carrotsoop

    └── 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

上面的示例,咱們能夠看到,咱們修改了./mnt/carrots的文件內容,./vegetables/carrots並無變化,反而是./fruits/carrots的目錄中出現了carrots文件,其內容是咱們在./mnt/carrots裏的內容。

也就是說,咱們在mount aufs命令中,咱們沒有指它vegetables和fruits的目錄權限,默認上來講,命令行上第一個(最左邊)的目錄是可讀可寫的,後面的全都是隻讀的。(通常來講,最前面的目錄應該是可寫的,然後面的都應該是隻讀的)

因此,若是咱們像下面這樣指定權限來mount aufs,你就會發現有不同的效果(記得先把上面./fruits/carrots的文件刪除了):

$ sudo mount -t aufs -o dirs=./fruits=rw:./vegetables=rw none ./mnt

$ echo "mnt_carrots" > ./mnt/carrots

$ cat ./vegetables/carrots

mnt_carrots

$ cat ./fruits/carrots

cat: ./fruits/carrots: No such file or directory

如今,在這狀況下,若是咱們要修改./mnt/tomato這個文件,那麼到底是哪一個文件會被改寫?

$ echo "mnt_tomato" > ./mnt/tomato

$ cat ./fruits/tomato

mnt_tomato

$ cat ./vegetables/tomato

I am a vegetable

可見,若是有重複的文件名,在mount命令行上,越往前的就優先級越高。

那麼,這種UnionFS有什麼用?

歷史上,有一個叫Knoppix的Linux發行版,其主要用於Linux演示、光盤教學、系統急救,以及商業產品的演示,不須要硬盤安裝,直接把CD/DVD上的image運行在一個可寫的存儲設備上(好比一個U盤上),其實,也就是把CD/DVD這個文件系統和USB這個可寫的系統給聯合mount起來,這樣你對CD/DVD上的image作的任何改動都會在被應用在U盤上,因而乎,你能夠對CD/DVD上的內容進行任意的修改,由於改動都在U盤上,因此你改不壞原來的東西。

咱們能夠再發揮一下想像力,你也能夠把一個目錄,好比你的源代碼,做爲一個只讀的template,和另外一個你的working directory給union在一塊兒,而後你就能夠作各類修改而不用懼怕會把源代碼改壞了。有點像一個ad hoc snapshot。

Docker把UnionFS的想像力發揮到了容器的鏡像。你是否還記得我在介紹Linux Namespace上篇中用mount namespace和chroot山寨了一鏡像。如今當你看過了這個UnionFS的技術後,你是否是就明白了,你徹底能夠用UnionFS這樣的技術作出分層的鏡像來。

下圖來自Docker的官方文檔Layer,其很好的展現了Docker用UnionFS搭建的分層鏡像。

關於docker的分層鏡像,除了aufs,docker還支持btrfs, devicemapper和vfs,你可使用 -s 或 –storage-driver= 選項來指定相關的鏡像存儲。在Ubuntu 14.04下,docker默認Ubuntu的 aufs(在CentOS7下,用的是devicemapper,關於devicemapper,我會以之後的文章中講解)你能夠在下面的目錄中查看相關的每一個層的鏡像:

/var/lib/docker/aufs/diff/<id>

在docker執行起來後(好比:docker run -it ubuntu /bin/bash ),你能夠從/sys/fs/aufs/si_[id]目錄下查看aufs的mount的狀況,下面是個示例:

#ls /sys/fs/aufs/si_b71b209f85ff8e75/

br0      br2      br4      br6      brid1    brid3    brid5    xi_path

br1      br3      br5      brid0    brid2    brid4    brid6

# cat /sys/fs/aufs/si_b71b209f85ff8e75/*

/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7=rw

/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7-init=ro+wh

/var/lib/docker/aufs/diff/d0955f21bf24f5bfffd32d2d0bb669d0564701c271bc3dfc64cfc5adfdec2d07=ro+wh

/var/lib/docker/aufs/diff/9fec74352904baf5ab5237caa39a84b0af5c593dc7cc08839e2ba65193024507=ro+wh

/var/lib/docker/aufs/diff/a1a958a248181c9aa6413848cd67646e5afb9797f1a3da5995c7a636f050f537=ro+wh

/var/lib/docker/aufs/diff/f3c84ac3a0533f691c9fea4cc2ceaaf43baec22bf8d6a479e069f6d814be9b86=ro+wh

/var/lib/docker/aufs/diff/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158=ro+wh

/run/shm/aufs.xino

你會看到只有最頂上的層(branch)是rw權限,其它的都是ro+wh權限只讀的。

關於docker的aufs的配置,你能夠在/var/lib/docker/repositories-aufs這個文件中看到。

AUFS的一些特性

AUFS有全部Union FS的特性,把多個目錄,合併成同一個目錄,並能夠爲每一個須要合併的目錄指定相應的權限,實時的添加、刪除、修改已經被mount好的目錄。並且,他還能在多個可寫的branch/dir間進行負載均衡。

上面的例子,咱們已經看到AUFS的mount的示例了。下面咱們來看一看被union的目錄(分支)的相關權限:

rw表示可寫可讀read-write。

ro表示read-only,若是你不指權限,那麼除了第一個外ro是默認值,對於ro分支,其永遠不會收到寫操做,也不會收到查找whiteout的操做。

rr表示real-read-only,與read-only不一樣的是,rr標記的是天生就是隻讀的分支,這樣,AUFS能夠提升性能,好比再也不設置inotify來檢查文件變更通知。

權限中,咱們看到了一個術語:whiteout,下面我來解釋一下這個術語。

通常來講ro的分支都會有wh的屬性,好比 「[dir]=ro+wh」。所謂whiteout的意思,若是在union中刪除的某個文件,其實是位於一個readonly的分支(目錄)上,那麼,在mount的union這個目錄中你將看不到這個文件,可是read-only這個層上咱們沒法作任何的修改,因此,咱們就須要對這個readonly目錄裏的文件做whiteout。AUFS的whiteout的實現是經過在上層的可寫的目錄下創建對應的whiteout隱藏文件來實現的。

相關術語

Branch – 就是各個要被union起來的目錄(就是我在上面使用的dirs的命令行參數)

Branch根據被union的順序造成一個stack,通常來講最上面的是可寫的,下面的都是隻讀的。

Branch的stack能夠在被mount後進行修改,好比:修改順序,加入新的branch,或是刪除其中的branch,或是直接修改branch的權限

Whiteout 和 Opaque

若是UnionFS中的某個目錄被刪除了,那麼就應該不可見了,就算是在底層的branch中還有這個目錄,那也應該不可見了。

Whiteout就是某個上層目錄覆蓋了下層的相同名字的目錄。用於隱藏低層分支的文件,也用於阻止readdir進入低層分支。

Opaque的意思就是不容許任何下層的某個目錄顯示出來。

在隱藏低層檔的狀況下,whiteout的名字是'.wh.<filename>’。

在阻止readdir的狀況下,名字是’.wh..wh..opq’或者 ’.wh.__dir_opaque’。

來自 <https://coolshell.cn/articles/17061.html>

同一個內核版本的全部Linux系統的bootfs是相同的,而rootfs則是不一樣的。在Docker 中,基礎鏡像中的roofs會一直保持只讀模式,Docker會利用union mount來在這個rootfs上增長更多的只讀文件系統,最後它們看起來就像一個文件系統即容器的rootfs。

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

 鏡像(image)是動態的容器的靜態表示(specification),包括容器所要運行的應用代碼以及運行時的配置。Docker 鏡像包括一個或者多個只讀層( read-only layers ),所以,鏡像一旦被建立就不再能被修改了。

一個運行着的Docker 容器是一個鏡像的實例( instantiation )。從同一個鏡像中運行的容器包含有相同的應用代碼和運行時依賴。可是不像鏡像是靜態的,每一個運行着的容器都有一個可寫層( writable layer ,也成爲容器層 container layer),它位於底下的若干只讀層之上。運行時的全部變化,包括對數據和文件的寫和更新,都會保存在這個層中。所以,從同一個鏡像運行的多個容器包含了不一樣的容器層。

四種單節點網絡模式

bridge 模式

Docker 容器默認使用 bridge 模式的網絡。其特色以下:

  • 使用一個 linux bridge,默認爲 docker0
  • 使用 veth 對,一頭在容器的網絡 namespace 中,一頭在 docker0 上
  • 該模式下Docker Container不具備一個公有IP,由於宿主機的IP地址與veth pair的 IP地址不在同一個網段內
  • Docker採用 NAT 方式,將容器內部的服務監聽的端口與宿主機的某一個端口port 進行「綁定」,使得宿主機之外的世界能夠主動將網絡報文發送至容器內部
  • 外界訪問容器內的服務時,須要訪問宿主機的 IP 以及宿主機的端口 port
  • NAT 模式因爲是在三層網絡上的實現手段,故確定會影響網絡的傳輸效率。
  • 容器擁有獨立、隔離的網絡棧;讓容器和宿主機之外的世界經過NAT創建通訊

iptables 的 SNTA 規則,使得從容器離開去外界的網絡包的源 IP 地址被轉換爲 Docker 主機的IP地址:

Chain POSTROUTING (policy ACCEPT)

target     prot opt source               destination

MASQUERADE  all  --  172.17.0.0/16        0.0.0.0/0

MASQUERADE  all  --  172.18.0.0/16        0.0.0.0/0

Host 模式

Host 模式並無爲容器建立一個隔離的網絡環境。而之因此稱之爲host模式,是由於該模式下的 Docker 容器會和 host 宿主機共享同一個網絡 namespace,故 Docker Container能夠和宿主機同樣,使用宿主機的eth0,實現和外界的通訊。換言之,Docker Container的 IP 地址即爲宿主機 eth0 的 IP 地址。其特色包括:

  • 這種模式下的容器沒有隔離的 network namespace
  • 容器的 IP 地址同 Docker host 的 IP 地址
  • 須要注意容器中服務的端口號不能與 Docker host 上已經使用的端口號相沖突
  • host 模式可以和其它模式共存

container 模式

Container 網絡模式是 Docker 中一種較爲特別的網絡的模式。處於這個模式下的 Docker 容器會共享其餘容器的網絡環境,所以,至少這兩個容器之間不存在網絡隔離,而這兩個容器又與宿主機以及除此以外其餘的容器存在網絡隔離。 

none 模式

 網絡模式爲 none,即不爲 Docker 容器構造任何網絡環境。一旦Docker 容器採用了none 網絡模式,那麼容器內部就只能使用loopback網絡設備,不會再有其餘的網絡資源。Docker Container的none網絡模式意味着不給該容器建立任何網絡環境,容器只能使用127.0.0.1的本機網絡。

 來自 <http://www.javashuo.com/article/p-ysxoebmc-m.html>

相關文章
相關標籤/搜索