一、Docker分層結構
docker裏的鏡像絕大部分都是在別的鏡像的基礎上去進行創建的,也就是使用鏡像的分層結構。
比如說使用dockerfile去創建一個最簡單的hello鏡像。創建好對應的dockerfile之後去進行創建:
FROM alpine:latest
MAINTAINER sbb
CMD echo "hello world"
執行了上面的命令我們可以看到存在着兩個鏡像,其中hello_world是我剛剛創建好的鏡像。
[root@docker ~]# docker imgaes
alpine
hello_world
容器由最上面的一個可寫的容器層和若干只讀的鏡像層組成,容器的數據就存放在這些層中,這些分層結構的最大特性是Copy-on-Write:
新數據會存放在最上面的容器層;
修改現有數據會先從鏡像層複製到容器層,修改後的數據存放在容器層,鏡像層不變;
如果多個層中有名字相同的文件,用戶只能看到最上層的那個文件。
分層結構使鏡像和容器的創建、共享及分發變得非常高效,而這些都要歸功於Docker Storange driver,正是他實現了多層數據的堆疊併爲用戶提供了一個單一的合併之後的統一視圖。
Docker支持多種Storange driver,有AUFS,Device Mapper,Btrfs等,每個容器會使用自己的操作系統默認的Storange driver,比如Ubuntu是AUFS,CentOS是Device Mapper。
如何查看鏡像或容器的Storange driver?使用docker info可以查看:
二、Docker的數據卷
數據卷又叫DataVolume,實際上是宿主機上的目錄或文件,可以被掛載到容器中修改或使用,有以下特點:
是目錄或文件,而不是磁盤;
掛載後,容器可以讀寫數據卷中的數據;
即使容器刪除了,數據卷也依然存在於宿主機上。
在具體使用上,docker提供了兩種類型的Volume:bind mount和docker managed volume。
三、Volume之bind mount
bind mount是把宿主機上的文件或目錄掛載到容器,如果容器中有相同的目錄或文件,則會把容器中的文件隱藏起來,只顯示掛載的文件或目錄,命令格式爲:
host path:container path
比如,nginx的容器中,web文件index.html放在/usr/share/nginx/html/目錄中,訪問該頁面顯示爲:
現在我們新建一個index.html,頁面內容爲“宿主機上的index.html”,存放在宿主機的/data/nginx/html中,並掛載到新的nginx容器中:
[root@docker ~]# docker run --name volume-test -P -d \
-v /data/nginx/html/index.html:/usr/share/nginx/html/index.html \
docker.io/nginx
訪問頁面顯示爲(漢字亂碼了):
掛載成功且覆蓋了容器中的index.html。
這種方法是隻向容器中添加單個文件,即使覆蓋也只會影響到容器中的單個文件。如果直接掛載文件目錄,則會把容器中的整個文件目錄連同裏面的文件會全部覆蓋。
另外,bind mount還可以在掛載時指定數據的讀寫權限,默認是可讀可寫,也可以指定爲只讀,如:
[root@docker ~]# docker run --name nginx -d -P \
-v /data/nginx/html/index.html:/usr/share/nginx/html/index.html:ro \
docker.io/nginx
e19052f33d61ac3a7f7f8e0f9d40a7143e567264d5463e171578acfdb9edc45d
啓動容器後,目錄掛載完成,我們嘗試進入容器內修改一下index.html文件:
root@e19052f33d61:/# echo "hello world" > /usr/share/nginx/html/index.html
bash: /usr/share/nginx/html/index.html: Read-only file system
root@e19052f33d61:/#
因爲我們設置了ro只讀權限,所以無法修改。
四、Volume之docker managed volume:
docker managed volume 與 bind mount在使用上的最大區別就是前者不需要手動指定mount源,指明容器內的目的路徑就行了。以httpd容器爲例:
[root@docker ~]# docker run --name httpd -d -p 80:80 -v /usr/local/apache2/htdocs docker.io/httpd:latest
a4d223d35fe1a24256a08ba20574a42d3731076527ac363295c2b6083130e019
如上,我們的 -v參數後面只需要指明容器內的路徑,那麼這個源在哪兒呢?我們使用docker inspect container name 就可以看到了:
[root@docker ~]# docker inspect a4d223d35fe1a24256a08ba20574a42d3731076527ac363295c2b6083130e019
"Mounts": [
{
"Type": "volume",
"Name": "d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a",
"Source": "/var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data",
"Destination": "/usr/local/apache2/htdocs",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
從上面可以看出:
“Source”: “/var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data”
就是mount源。可以查看一下這個目錄裏是什麼文件:
[root@docker ~]# ls /var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data
index.html
目錄裏存放的文件爲index.html,和/usr/local/apache2/htdocs裏存放的文件一致。這是爲什麼呢?這是因爲:如果目的路徑指向的是容器內的已存在目錄,則目的路徑內的數據會被複制到源路徑中。必須要明確的是:此時的目的路徑不再是storange driver管理的層數據,他是一個data volume。我們可以和bind mount 一樣對數據進行操作,如:
[root@docker ~]# echo "Update for httpd container" > /var/lib/docker/volumes/d6366e7ac82498286cc5b51c7057c11d02eba620cf6c3974ee39914ac7f7e76a/_data/index.html
此時刷新網頁,發現內容已經變了:
回顧一下docker managed volume創建過程:
容器啓動時,告訴docker:我需要一個volume存放數據,掛載到/abc目錄;
docker在/var/lib/docker/volumes目錄中隨機生成一個目錄作爲mount源;
如果容器中/abc目錄已經存在,則把目錄中的數據複製到源中;
將源掛載到/abc目錄。
五、總結
上面學習了bind mount和docker managed volume這兩種data volume,下面來總結一下兩者的異同:
位置:bind mount源可以是宿主機上任意位置,而docker managed volume必須是/var/lib/docker/volumes目錄內,並且是docker在啓動容器時隨機指定volume目錄名稱;
文件類型:bind mount可以掛在文件或目錄,而docker managed volume只能是目錄;
對容器內數據的影響:bind mount 是把文件或目錄從宿主機複製到容器,並且隱藏容器內的同名文件,而後者是把容器內的文件複製到宿主機的volume中;
權限控制:前者可以設置爲只讀,默認爲讀寫都有的權限,而後者無法控制,默認爲讀寫權限。
可移植性:前者與宿主機的目錄綁定,可移植性差,後者無需指定宿主機目錄,可移植性強。
bind mount | docker managed volume | |
---|---|---|
volume 位置 | 可任意指定 | /var/lib/docker/volumes/… |
對已有mount point 影響 | 隱藏並替換爲 volume | 原有數據複製到 volume |
是否支持單個文件 | 支持 | 不支持,只能是目錄 |
權限控制 | 可設置爲只讀,默認爲讀寫權限 | 無控制,均爲讀寫權限 |
移植性 | 移植性弱,與 host path 綁定 | 移植性強,無需指定 host 目錄 |