您好,登錄后才能下訂單哦!
這篇文章主要講解了“Docker目錄掛載及文件共享的方法”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“Docker目錄掛載及文件共享的方法”吧!
Docker中的數(shù)據(jù)可以存儲(chǔ)在類似于虛擬機(jī)磁盤的介質(zhì)中,在Docker中稱為數(shù)據(jù)卷(Data Volume)。數(shù)據(jù)卷可以用來(lái)存儲(chǔ)Docker應(yīng)用的數(shù)據(jù),也可以用來(lái)在Docker容器間進(jìn)行數(shù)據(jù)共享。數(shù)據(jù)卷呈現(xiàn)給Docker容器的形式就是一個(gè)目錄,支持多個(gè)容器間共享,修改也不會(huì)影響鏡像。使用Docker的數(shù)據(jù)卷,類似在系統(tǒng)中使用 mount 掛載一個(gè)文件系統(tǒng)。
想要了解Docker Volume,首先我們需要知道Docker的文件系統(tǒng)是如何工作的。Docker鏡像是由多個(gè)文件系統(tǒng)(只讀層)疊加而成。當(dāng)我們啟動(dòng)一個(gè)容器的時(shí)候,Docker會(huì)加載只讀鏡像層并在其上(鏡像棧頂部)添加一個(gè)讀寫層。如果運(yùn)行中的容器修改了現(xiàn)有的一個(gè)已經(jīng)存在的文件,那該文件將會(huì)從讀寫層下面的只讀層復(fù)制到讀寫層,該文件的只讀版本仍然存在,只是已經(jīng)被讀寫層中該文件的副本所隱藏。當(dāng)刪除Docker容器,并通過(guò)該鏡像重新啟動(dòng)時(shí),之前的更改將會(huì)丟失。在Docker中,只讀層及在頂部的讀寫層的組合被稱為Union File System(聯(lián)合文件系統(tǒng))。
為了能夠保存(持久化)數(shù)據(jù)以及共享容器間的數(shù)據(jù),Docker提出了Volume的概念。簡(jiǎn)單來(lái)說(shuō),Volume就是目錄或者文件,它可以繞過(guò)默認(rèn)的聯(lián)合文件系統(tǒng),而以正常的文件或者目錄的形式存在于宿主機(jī)上。
最常用的其實(shí)就是目錄掛載和文件共享的使用。
Docker容器啟動(dòng)的時(shí)候,如果要掛載宿主機(jī)的一個(gè)目錄,可以用-v參數(shù)指定,這個(gè)其實(shí)也是創(chuàng)建一個(gè)數(shù)據(jù)卷,只不過(guò)是把一個(gè)本地主機(jī)的目錄當(dāng)做數(shù)據(jù)卷掛載在容器上。
譬如我要啟動(dòng)一個(gè) CentOS 容器,宿主機(jī)的 /hostTest 目錄掛載到容器的 /conainterTest 目錄,可通過(guò)以下方式指定:
1 | docker run -it -v /hostTest:/conainterTest --name centos-demo-1 centos |
這樣在容器啟動(dòng)后,容器內(nèi)會(huì)自動(dòng)創(chuàng)建 /conainterTest 的目錄。通過(guò)這種方式,我們可以明確一點(diǎn),即-v參數(shù)中,冒號(hào)”:”前面的目錄是宿主機(jī)目錄,后面的目錄是容器內(nèi)目錄。
下面我們來(lái)驗(yàn)證一下: 我服務(wù)器上的docker 版本都是 18.09.2
1 2 3 | [root@VM_156_200_centos ~]# docker version Client: Version: 18.09.2 |
首先執(zhí)行命令:
1 2 3 4 5 6 7 | [root@VM_156_200_centos /]# docker run -it -v /hostTest:/conainterTest --name centos-demo-1 centos [root@a8e50a72519e /]# cd conainterTest/ [root@a8e50a72519e conainterTest]# echo "123" > 123 [root@a8e50a72519e conainterTest]# ls 123 [root@a8e50a72519e conainterTest]# exit exit |
run 一個(gè) centos 的鏡像,如果本地沒(méi)有的話,會(huì)去執(zhí)行docker pull centos下載,并生成一個(gè) centos-demo-1 的容器,并進(jìn)入交互模式
這時(shí)候就可以看到容器里面已經(jīng)有生成/conainterTest這個(gè)目錄了,接下來(lái)我們?cè)谶@個(gè)目錄下創(chuàng)建了一個(gè) 123 的文件,然后退出容器。
回到宿主機(jī)之后,可以看到宿主機(jī)對(duì)應(yīng)的目錄已經(jīng)有/hostTest這個(gè)目錄了,并且也有 123 這個(gè)文件。
1 2 3 4 5 6 | [root@VM_156_200_centos /]# cd /hostTest/ [root@VM_156_200_centos hostTest]# ls 123 [root@VM_156_200_centos hostTest]# echo "456" > 456 [root@VM_156_200_centos hostTest]# ls 123 456 |
而且我們還再新建了一個(gè) 456 文件,看看會(huì)不會(huì)同步到容器中,接下來(lái)啟動(dòng)容器查看一下:
1 2 3 4 5 6 | [root@VM_156_200_centos hostTest]# docker start -ai centos-demo-1 [root@a8e50a72519e /]# cd conainterTest/ [root@a8e50a72519e conainterTest]# ls 123 456 [root@a8e50a72519e conainterTest]# cat 456 456 |
可以看到這個(gè)是有的,所以這兩個(gè)目錄其實(shí)就是共享的。接下來(lái)具體分析一下這個(gè)命令的幾種情況。
具體指令如下:
1 2 3 | [root@VM_156_200_centos /]# docker run -it -v /hostTest:conainterTest --name centos-demo-1 centos docker: Error response from daemon: invalid volume specification: '/hostTest:conainterTest': invalid mount config for type "bind": invalid mount path: 'conainterTest' mount path must be absolute. See 'docker run --help'. |
直接報(bào)錯(cuò),提示 conainterTest 不是一個(gè)絕對(duì)路徑,所謂的絕對(duì)路徑,必須以下斜線“/”開頭。
先把宿主機(jī)的目錄刪掉:然后在run容器:
ps: 因?yàn)橛袨槿萜髅?,但是因?yàn)橄嗤值娜萜鲃?chuàng)建會(huì)報(bào)錯(cuò),所以這邊我有一個(gè)隱形操作,就是每次操作,都會(huì)先執(zhí)行:
1 2 | [root@VM_156_200_centos /]# docker rm centos-demo-1 centos-demo-1 |
當(dāng)然這個(gè)不是重點(diǎn),所以后面我不會(huì)再把這個(gè)操作再說(shuō)明,默認(rèn)每次run的時(shí)候,如果名字相同,那么我就會(huì)先刪掉同名的容器。
1 2 3 4 | [root@VM_156_200_centos /]# rm -rf hostTest [root@VM_156_200_centos /]# docker run -it -v /hostTest:/conainterTest --name centos-demo-1 centos [root@e57a25c8f8e5 /]# ls anaconda-post.log bin conainterTest dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var |
查看宿主機(jī),發(fā)現(xiàn)新增了 /hostTest 這個(gè)目錄
1 2 3 | [root@VM_156_200_centos /]# cd hostTest/ [root@VM_156_200_centos hostTest]# pwd /hostTest |
這次,我們換個(gè)目錄名 hostTest1 試試:
1 | [root@VM_156_200_centos /]# docker run -it -v hostTest1:/conainterTest --name centos-demo-1 centos |
接下來(lái)去 / 查找有沒(méi)有增加 hostTest1 目錄:
1 | [root@VM_156_200_centos /]# ll / | grep 'hostTest1' |
發(fā)現(xiàn)找不到?? 那么 hostTest1 在哪里創(chuàng)建呢? 通過(guò)docker inspect命令,查看容器“Mounts”那一部分,我們可以得到這個(gè)問(wèn)題的答案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@VM_156_200_centos hostTest]# docker inspect centos-demo-1 [ { ... "Mounts": [ { "Type": "volume", "Name": "hostTest1", "Source": "/var/lib/docker/volumes/hostTest1/_data", "Destination": "/conainterTest", "Driver": "local", "Mode": "z", "RW": true, "Propagation": "" } ], ... } ] |
可以看出,容器內(nèi)的 /conainterTest 目錄掛載的是宿主機(jī)上的 /var/lib/docker/volumes/hostTest1/_data 目錄。
原來(lái),所謂的相對(duì)路徑指的是 /var/lib/docker/volumes/ ,與宿主機(jī)的當(dāng)前目錄無(wú)關(guān)。
先啟動(dòng)一個(gè)容器:
1 2 3 | [root@VM_156_200_centos volumes]# docker run -it -v /test2 --name centos-demo-1 centos [root@64e9d535b48c /]# ls anaconda-post.log bin dev etc home lib lib64 media mnt opt proc root run sbin srv sys test2 tmp usr var |
發(fā)現(xiàn) /test2 在容器中有存在,那么宿主機(jī)的目錄在哪里呢?? 用 docker inspect 查看一下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@VM_156_200_centos hostTest]# docker inspect centos-demo-1 [ { ... "Mounts": [ { "Type": "volume", "Name": "43c602bf16cf87452499988cd4dbfad834e40e2f01e93d960ec01a557f40bc58", "Source": "/var/lib/docker/volumes/43c602bf16cf87452499988cd4dbfad834e40e2f01e93d960ec01a557f40bc58/_data", "Destination": "/test2", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ... } ] |
可以看出,同上例中的結(jié)果類似,只不過(guò),它不是相對(duì)路徑的目錄名,而是隨機(jī)生成的一個(gè)目錄名。
首先開啟一個(gè)容器,并查看容器內(nèi) /conainterTest/ 的屬性
1 2 3 | [root@VM_156_200_centos volumes]# docker run -it -v /hostTest:/conainterTest --name centos-demo-1 centos [root@25d6613bcb81 /]# ll -d /conainterTest/ drwxr-xr-x 2 root root 4096 Feb 26 03:24 /conainterTest/ |
接下來(lái)查看宿主機(jī)內(nèi) /hostTest 目錄的屬性:
1 2 | [root@VM_156_200_centos volumes]# ll -d /hostTest/ drwxr-xr-x 2 root root 4096 Feb 26 11:24 /hostTest/ |
可以看到都是 root。接下來(lái)我們?cè)谌萜鲀?nèi)新建用戶,修改 /conainterTest 的屬主和屬組:
1 2 3 4 5 | [root@VM_156_200_centos volumes]# docker start -ai centos-demo-1 [root@25d6613bcb81 /]# useradd kbz [root@25d6613bcb81 /]# chown -R kbz.kbz /conainterTest/ [root@25d6613bcb81 /]# ll -d /conainterTest/ drwxr-xr-x 2 kbz kbz 4096 Feb 26 03:24 /conainterTest/ |
可以看到已經(jīng)將屬主和屬組都變成 kbz 了。接下來(lái)查看宿主機(jī) /hostTest 的屬主和屬組是否會(huì)改變??
1 2 | [root@VM_156_200_centos volumes]# ll -d /hostTest/ drwxr-xr-x 2 privoxy privoxy 4096 Feb 26 11:24 /hostTest/ |
發(fā)現(xiàn)改變了,但是并不是 kbz,而是一個(gè) privoxy ??
原來(lái),這個(gè)與UID有關(guān)系,UID,即“用戶標(biāo)識(shí)號(hào)”,是一個(gè)整數(shù),系統(tǒng)內(nèi)部用它來(lái)標(biāo)識(shí)用戶。一般情況下它與用戶名是一一對(duì)應(yīng)的。首先查看容器內(nèi)victor對(duì)應(yīng)的UID是多少:
1 2 3 | [root@VM_156_200_centos volumes]# docker start -ai centos-demo-1 [root@25d6613bcb81 /]# cat /etc/passwd | grep kbz kbz:x:1000:1000::/home/kbz:/bin/bash |
kbz 的 UID 為 1000,那么宿主機(jī)內(nèi) 1000 對(duì)應(yīng)的用戶是誰(shuí)呢?
1 2 | [root@VM_156_200_centos volumes]# cat /etc/passwd | grep 1000 privoxy:x:1000:1000::/home/privoxy:/bin/bash |
果然是 privoxy, 那么就說(shuō)的通了。
在這里,主要驗(yàn)證兩種情況:
指定了宿主機(jī)目錄,即 -v /hostTest:/conainterTest。
沒(méi)有指定宿主機(jī)目錄,即 -v /conainterTest
首先的第一種情況:
1 2 3 4 5 6 7 8 9 | [root@VM_156_200_centos /]# rm -rf /hostTest/ [root@VM_156_200_centos /]# ll | grep hostTest [root@VM_156_200_centos /]# docker run -it -v /hostTest:/conainterTest --name centos-demo-1 centos [root@a225da0f4576 /]# exit exit [root@VM_156_200_centos /]# docker rm centos-demo-1 centos-demo-1 [root@VM_156_200_centos /]# ll | grep hostTest drwxr-xr-x 2 root root 4096 Feb 26 14:10 hostTest |
我們先把宿主機(jī)的 hostTest 目錄刪掉,然后進(jìn)行掛載,再把容器刪掉,最后發(fā)現(xiàn)掛載時(shí)候建的 hostTest 還存在。
可以看出,即便容器銷毀了,新建的掛載目錄不會(huì)消失。進(jìn)一步也可驗(yàn)證,如果宿主機(jī)目錄的屬主和屬組發(fā)生了變化,容器銷毀后,宿主機(jī)目錄的屬主和屬組不會(huì)恢復(fù)到掛載之前的狀態(tài)。
第二種情況:
通過(guò)上面的驗(yàn)證知道,如果沒(méi)有指定宿主機(jī)的目錄,則容器會(huì)在 /var/lib/docker/volumes/ 隨機(jī)配置一個(gè)目錄,那么我們看看這種情況下的容器銷毀是否會(huì)導(dǎo)致相應(yīng)目錄的刪除:
首先啟動(dòng)容器:
1 | [root@VM_156_200_centos /]# docker run -it -v conainterTest --name centos-demo-1 centos |
然后通過(guò) docker inspect 來(lái)查看掛載的宿主機(jī)的目錄:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@VM_156_200_centos ~]# docker inspect centos-demo-1 [ { ... "Mounts": [ { "Type": "volume", "Name": "225e07eb178cc49ee6a4bd95d82430fdf77af717fc4924cb0d201a3f2f162683", "Source": "/var/lib/docker/volumes/225e07eb178cc49ee6a4bd95d82430fdf77af717fc4924cb0d201a3f2f162683/_data", "Destination": "conainterTest", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ... } ] |
對(duì)應(yīng)的是/var/lib/docker/volumes/22…83/_data目錄, 去查看一下這個(gè)目錄是否存在:
1 2 3 | [root@VM_156_200_centos /]# ll /var/lib/docker/volumes/225e07eb178cc49ee6a4bd95d82430fdf77af717fc4924cb0d201a3f2f162683/ total 4 drwxr-xr-x 2 root root 4096 Feb 26 14:14 _data |
發(fā)現(xiàn)該目錄依然存在。而且即使重啟了docker服務(wù),該目錄依舊存在。
可通過(guò)兩種方式解決:
關(guān)閉selinux。
臨時(shí)關(guān)閉:# setenforce 0
永久關(guān)閉:修改/etc/sysconfig/selinux文件,將SELINUX的值設(shè)置為disabled。
以特權(quán)方式啟動(dòng)容器
指定–privileged參數(shù)
1 | docker run -it --privileged=true -v /test:/soft centos /bin/bash |
掛載的路徑權(quán)限默認(rèn)為讀寫。如果指定為只讀可以用:ro
1 2 3 4 | [root@VM_156_200_centos /]# docker run -it -v /hostTest:/conainterTest:ro --name centos-demo-1 centos [root@c9c2a58bbfef /]# cd conainterTest/ [root@c9c2a58bbfef conainterTest]# echo "12" > 12 bash: 12: Read-only file system |
這時(shí)候,如果在容器的掛載目錄下進(jìn)行讀寫操作的話,就會(huì)報(bào)錯(cuò)。
不僅可以掛載目錄,還可以掛載文件。如果掛載目錄可以理解為系統(tǒng)的目錄映射的話,那么掛載文件,也可以理解為文件映射。
語(yǔ)法跟掛載目錄差不多。不過(guò)有一點(diǎn)要注意的是,掛載宿主機(jī)文件的時(shí)候,該文件一定要存在,如果該文件不存在,就會(huì)跟上面例子說(shuō)的一樣,docker會(huì)自動(dòng)幫你創(chuàng)建,但是這時(shí)候它創(chuàng)建的時(shí)候,就是目錄了,而不是文件了。
接下來(lái)嘗試一下:
1 2 3 4 | [root@VM_156_200_centos ~]# vim web.list [root@VM_156_200_centos ~]# cat web.list 1111111111 2222222222 |
我創(chuàng)建了一個(gè) web.list 的文件,并且寫入了兩行,這時(shí)候就開始掛載這個(gè)文件了:
1 2 3 4 5 6 7 8 9 10 11 | [root@VM_156_200_centos ~]# docker run -it -v /root/web.list:/root/web.list --name centos-demo-1 centos [root@6c91b4f6b765 /]# cat /root/web.list 1111111111 2222222222 [root@6c91b4f6b765 /]# echo "333333" >> /root/web.list [root@6c91b4f6b765 /]# cat /root/web.list 1111111111 2222222222 333333 [root@6c91b4f6b765 /]# exit exit |
可以看到掛載成功了,并且在容器內(nèi)又在 web.list 寫入新的一行,并退出容器
1 2 3 4 5 6 7 8 9 10 11 | [root@VM_156_200_centos ~]# cat /root/web.list 1111111111 2222222222 333333 [root@VM_156_200_centos ~]# echo "444444" >> /root/web.list [root@VM_156_200_centos ~]# docker start -ai centos-demo-1 [root@6c91b4f6b765 /]# cat /root/web.list 1111111111 2222222222 333333 444444 |
可以看到在宿主機(jī),之前容器新寫的一行也同步過(guò)來(lái)了,而且之后宿主機(jī)也新加了一行,之后進(jìn)入容器也一樣有。
掛載文件跟上述掛載目錄一樣,也是默認(rèn)為讀寫的,如果設(shè)置為只讀的話,那么在容器里面就不能修改了,只能在宿主機(jī)修改:
1 2 3 4 5 6 7 8 9 10 11 12 | [root@VM_156_200_centos ~]# docker run -it -v /root/web.list:/root/web.list:ro --name centos-demo-1 centos [root@2a7e3a4ed710 /]# echo "5555" >> /root/web.list bash: /root/web.list: Read-only file system [root@2a7e3a4ed710 /]# exit exit [root@VM_156_200_centos ~]# echo "666" >> /root/web.list [root@VM_156_200_centos ~]# cat web.list 1111111111 2222222222 333333 444444 666 |
可以看到在容器內(nèi)編輯是會(huì)報(bào)錯(cuò)的,而在宿主機(jī)內(nèi)就不會(huì)。
上述的掛載目錄和掛載文件,只是 Docker Volume 的使用方式。
而我們用的方式就是在docker run命令后面跟上-v參數(shù)即可創(chuàng)建一個(gè)數(shù)據(jù)卷,然后把本地目錄或者文件當(dāng)做數(shù)據(jù)卷掛載到容器中。當(dāng)然也可以跟多個(gè)-v參數(shù)來(lái)創(chuàng)建多個(gè)數(shù)據(jù)卷。
因此我們完全可以創(chuàng)建一個(gè)數(shù)據(jù)卷的容器,后面專門用來(lái)提供其他容器來(lái)掛載。
首先先創(chuàng)建一個(gè)專門用來(lái)提供數(shù)據(jù)的本地目錄,然后掛載到一個(gè)普通的容器,而這個(gè)容器就是其他容器要掛載的數(shù)據(jù)卷容器,這種方式主要就是用來(lái)做多個(gè)容器的共享數(shù)據(jù)存在的。
1 2 3 4 | [root@VM_156_200_centos ~]# mkdir go-data [root@VM_156_200_centos go-data]# cp -r /root/go/src/goworker/ ./ [root@VM_156_200_centos go-data]# ls goworker |
go-data 這個(gè)目錄存放一些 golang 語(yǔ)言的項(xiàng)目,然后我們把它做成一個(gè)數(shù)據(jù)卷容器,并指向容器的 /go/src 目錄:
1 2 3 4 5 6 | [root@VM_156_200_centos go-data]# docker run -it -v /root/go-data/:/go/src/ --name centos-go-data centos [root@10d5c4f11e77 /]# cd /go/src [root@10d5c4f11e77 src]# ls goworker [root@10d5c4f11e77 src]# exit exit |
這樣這個(gè)就生成了一個(gè)名為 centos-go-data 的數(shù)據(jù)卷容器了,容器里面 /go/src 目錄含有一個(gè)叫做 goworker 的 go 程序。剛好我服務(wù)器上之前有一個(gè) go-1.10 環(huán)境的鏡像。
接下來(lái)我們將這個(gè)鏡像 run 起來(lái),并且掛載 centos-go-data 這個(gè)數(shù)據(jù)卷容器(通過(guò) –volumes-from 可以掛載數(shù)據(jù)卷容器),看看原來(lái) /go/src 里面應(yīng)該為空的目錄,會(huì)不會(huì)有這個(gè)數(shù)據(jù)卷容器里面的go程序代碼?
1 2 3 4 5 6 7 | [root@VM_156_200_centos go-data]# docker run -it --volumes-from centos-go-data --name golang-volume-demo kbz/golang-1.10 root@412ab80da79e:/app# cd /go/src root@412ab80da79e:/go/src# ls goworker root@412ab80da79e:/go/src# cd goworker/ root@412ab80da79e:/go/src/goworker# ls hello_worker.go worker worker.go |
可以看到原本應(yīng)該有空的 src 目錄,竟然有代碼目錄存在了,說(shuō)明這個(gè)數(shù)據(jù)卷掛載成功了。接下來(lái)將這個(gè) goworker 添加一個(gè)文件,看會(huì)不會(huì)同步到掛載的那個(gè)本地目錄:
1 2 3 4 5 6 7 8 | root@412ab80da79e:/go/src/goworker# echo "123" > 123 root@412ab80da79e:/go/src/goworker# ls 123 hello_worker.go worker worker.go root@412ab80da79e:/go/src/goworker# exit exit [root@VM_156_200_centos go-data]# cd /root/go-data/goworker/ [root@VM_156_200_centos goworker]# ls 123 hello_worker.go worker worker.go |
發(fā)現(xiàn)本地目錄也出現(xiàn)剛才在容器中出現(xiàn)的 123 文件了,說(shuō)明還是共享成功了。 這時(shí)候我們?cè)?run 一個(gè)新的 golang 環(huán)境的容器,然后也掛載這個(gè)數(shù)據(jù)卷看看數(shù)據(jù)會(huì)不會(huì)也有這個(gè) 123 文件?
1 2 3 4 | [root@VM_156_200_centos goworker]# docker run -it --volumes-from centos-go-data --name golang-volume-demo-2 kbz/golang-1.10 root@25d7a8fd5da1:/app# cd /go/src/goworker/ root@25d7a8fd5da1:/go/src/goworker# ls 123 hello_worker.go worker worker.go |
發(fā)現(xiàn)新的容器也有這個(gè) 123 文件。
其實(shí)很多時(shí)候這種數(shù)據(jù)卷容器都是用來(lái)做持久化的,舉個(gè)例子,比如我有一些golang的測(cè)試代碼,做成了一個(gè)數(shù)據(jù)卷容器,然后我本地有好幾個(gè)不同go環(huán)境的容器,每一個(gè)容器在 run 的時(shí)候,都會(huì)掛載這個(gè)數(shù)據(jù)卷容器。但是我們不希望在go環(huán)境的容器里面去修改這個(gè)數(shù)據(jù)卷容器里面的數(shù)據(jù)。所以剛開始我們?cè)谏蛇@個(gè)數(shù)據(jù)卷容器的時(shí)候,就要把權(quán)限設(shè)置為只讀才行,這樣這個(gè)數(shù)據(jù)卷就變成一個(gè)公共的掛載數(shù)據(jù)卷,別的容器只能掛載使用里面的數(shù)據(jù),但是卻不能做修改:
1 2 3 4 5 6 7 8 9 10 11 | [root@VM_156_200_centos goworker]# docker rm centos-go-data centos-go-data [root@VM_156_200_centos goworker]# docker run -it -v /root/go-data/:/go/src/:ro --name centos-go-data centos [root@851a09a40cb8 /]# exit exit [root@VM_156_200_centos goworker]# docker run -it --volumes-from centos-go-data --name golang-volume-demo-3 kbz/golang-1.10 root@c986955f5ee0:/app# cd /go/src/goworker/ root@c986955f5ee0:/go/src/goworker# ls 123 hello_worker.go worker worker.go root@c986955f5ee0:/go/src/goworker# echo "456" > 456 bash: 456: Read-only file system |
一旦進(jìn)行修改,就會(huì)報(bào)錯(cuò)。
而且這種數(shù)據(jù)卷容器可以掛好幾個(gè)的,就跟用 -v 掛載多個(gè)本地目錄一樣:
1 | docker run --name data -v /opt/data1:/var/www/data1 -v /opt/data2:/var/www/data2:ro -it docker.io/ubuntu |
這邊稍微說(shuō)一下,沒(méi)有加-t和-i參數(shù),所以這個(gè)容器創(chuàng)建好之后是沒(méi)有進(jìn)行交互模式的。其中 -i 表示以“交互模式”運(yùn)行容器。 -t 表示打開一個(gè)連接到容器的終端。
1 2 3 4 5 | [root@VM_156_200_centos js-data]# docker run -it --volumes-from centos-go-data --volumes-from centos-js-data --name golang-volume-demo-4 kbz/golang-1.10 root@94e9d5868711:/app# cd /go/src/ && ls goworker root@94e9d5868711:/go/src# cd /js && ls test.js |
這樣就掛載了兩個(gè)數(shù)據(jù)卷容器。
使用數(shù)據(jù)容器的兩個(gè)注意點(diǎn):
不要運(yùn)行數(shù)據(jù)容器,這純粹是在浪費(fèi)資源。
不要為了數(shù)據(jù)容器而使用“最小的鏡像”,如busybox或scratch,只使用數(shù)據(jù)庫(kù)鏡像本身就可以了。你已經(jīng)擁有該鏡像,所以并不需要占用額外的空間。
除了以上用 -v 來(lái)創(chuàng)建掛載數(shù)據(jù)卷之外,docker 還可以用以下方式來(lái)創(chuàng)建數(shù)據(jù)卷:
Docker 新版本中引入了 docker volume 命令來(lái)管理 Docker volume:
比如我創(chuàng)建一個(gè)名為 js-data 的數(shù)據(jù)卷:
1 2 | [root@VM_156_200_centos js-data]# docker volume create --name js-data js-data |
這樣就創(chuàng)建成功了,可以通過(guò) docker volume ls 來(lái)查看當(dāng)前的數(shù)據(jù)卷:
1 2 3 4 5 | [root@VM_156_200_centos js-data]# docker volume ls DRIVER VOLUME NAME local 0e01f8abe89c9956609eed063c623536112525fb32cf4c0363255a953aa2d35d ... local js-data |
然后我們可以通過(guò)docker volume inspect xxx來(lái)查看這個(gè)數(shù)據(jù)卷所對(duì)應(yīng)的本地目錄是哪個(gè)?
1 2 3 4 5 6 7 8 9 10 11 12 | [root@VM_156_200_centos js-data]# docker volume inspect js-data [ { "CreatedAt": "2019-02-26T16:12:28+08:00", "Driver": "local", "Labels": {}, "Mountpoint": "/var/lib/docker/volumes/js-data/_data", "Name": "js-data", "Options": {}, "Scope": "local" } ] |
可以看到對(duì)應(yīng)的本地目錄就是 /var/lib/docker/volumes/js-data/_data 這個(gè)目錄。當(dāng)然目前這個(gè)目錄是空的:
1 2 | [root@VM_156_200_centos js-data]# ll /var/lib/docker/volumes/js-data/_data total 0 |
接下來(lái)就可以將這個(gè)數(shù)據(jù)卷掛載上去:
1 2 3 4 5 6 7 8 | [root@VM_156_200_centos js-data]# docker run -it -v js-data:/js --name golang-volume-demo-3 kbz/golang-1.10 root@c55671066dec:/app# cd /js root@c55671066dec:/js# ls root@c55671066dec:/js# echo "123" > 123 root@c55671066dec:/js# ls 123 root@c55671066dec:/js# exit exit |
語(yǔ)法差不了多少,也是 -v 來(lái)指定,不過(guò)這時(shí)候“:”前面已經(jīng)不是宿主機(jī)的目錄了,而是換成 js-data 這個(gè)數(shù)據(jù)卷了,當(dāng)然這個(gè)目錄是空的。
然后我們給他添加了一個(gè)新的文件 123,看看宿主機(jī)目錄會(huì)不會(huì)也有?
1 2 3 4 5 | [root@VM_156_200_centos js-data]# ll /var/lib/docker/volumes/js-data/_data total 4 -rw-r--r-- 1 root root 4 Feb 26 16:29 123 [root@VM_156_200_centos js-data]# cat /var/lib/docker/volumes/js-data/_data/123 123 |
事實(shí)上肯定是有的。 而且這種方式其實(shí)就是上面那種當(dāng)宿主機(jī)的目錄是相對(duì)目錄的處理方式,其實(shí)在docker處理過(guò)程中,如果宿主機(jī)目錄是相對(duì)的,這時(shí)候就會(huì)去判斷本地是否存在這個(gè)volume,如果不存在就創(chuàng)建一個(gè)(所以其實(shí)我們不太需要去顯示的創(chuàng)建一個(gè) volume),所以我們還可以看到文章前面當(dāng)當(dāng)宿主機(jī)的目錄是相對(duì)目錄的處理方式那時(shí)候的相對(duì)目錄的 hostTest1,其實(shí)已經(jīng)是一個(gè) volume了:
1 2 3 4 5 6 7 8 9 10 11 12 | [root@VM_156_200_centos js-data]# docker volume inspect hostTest1 [ { "CreatedAt": "2019-02-26T11:30:34+08:00", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/hostTest1/_data", "Name": "hostTest1", "Options": null, "Scope": "local" } ] |
但是有一點(diǎn)要注意的話,如果要指定具體的宿主機(jī)目錄的話,那就不能用這種方式,“:” 前面的宿主機(jī)目錄路徑還是得用絕對(duì)路徑。
除了用docker volume命令顯示或者用 -v 宿主機(jī)相對(duì)目錄隱示的創(chuàng)建數(shù)據(jù)卷之外,還可以在dockerfile設(shè)置volume數(shù)據(jù)卷。
ps: 注意上述[5 掛載數(shù)據(jù)卷容器]創(chuàng)建的數(shù)據(jù)卷容器,其實(shí)本質(zhì)上是一個(gè)容器,即 Docker Container,而不是 Docker Volume。 Container 是可以在 docker ps -a 可以找到,而在 docker volume ls 這里面是找不到的:
1 2 3 4 | [root@VM_156_200_centos js-data]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a559685d18ae centos "/bin/bash" About an hour ago Exited (0) About an hour ago centos-js-data 851a09a40cb8 centos "/bin/bash" About an hour ago Exited (0) About an hour ago centos-go-data |
在 dockerfile 設(shè)置 volume 數(shù)據(jù)卷,舉個(gè)例子:
1 2 3 4 5 6 | [root@VM_156_200_centos ~]# mkdir docker-volume-centos [root@VM_156_200_centos ~]# cd docker-volume-centos/ [root@VM_156_200_centos docker-volume-centos]# vim dockerfile [root@VM_156_200_centos docker-volume-centos]# cat dockerfile FROM centos VOLUME /js-data |
可以看到這個(gè) dockerfile 掛載了一個(gè)容器內(nèi)的 js-data。 接下來(lái) build 一下:
1 | [root@VM_156_200_centos docker-volume-centos]# docker build --rm -t volume-centos . |
然后 run 起來(lái):
1 2 3 4 5 6 7 8 | [root@VM_156_200_centos docker-volume-centos]# docker run -it --name volume-centos-demo volume-centos [root@eeb532993285 /]# cd /js-data [root@eeb532993285 js-data]# ls [root@eeb532993285 js-data]# echo "456" > 456 [root@eeb532993285 js-data]# ls 456 [root@eeb532993285 js-data]# exit exit |
可以看到跑起來(lái)之后,容器里面已經(jīng)有一個(gè) js-data, 但是這個(gè)目錄是空的,我們先在這個(gè)目錄創(chuàng)建一個(gè) 456 的文件。然后退出容器。
接下來(lái)我們看看這個(gè)共享目錄對(duì)應(yīng)的宿主機(jī)的目錄是哪個(gè):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@VM_156_200_centos docker-volume-centos]# docker inspect volume-centos-demo [ { ... "Mounts": [ { "Type": "volume", "Name": "b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304", "Source": "/var/lib/docker/volumes/b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304/_data", "Destination": "/js-data", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], ... } ] |
可以看到宿主目錄是這個(gè):/var/lib/docker/volumes/b07…304/_data,接下來(lái)看看這個(gè)目錄是否有 456 這個(gè)文件:
1 2 3 4 5 | [root@VM_156_200_centos docker-volume-centos]# ll /var/lib/docker/volumes/b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304/_data total 4 -rw-r--r-- 1 root root 4 Feb 26 16:56 456 [root@VM_156_200_centos docker-volume-centos]# cat /var/lib/docker/volumes/b07ab9cb039ffa90cc0ea7186716aa861cb9bcda11b1925bffca7a6539ee1304/_data/456 456 |
是有的。 通過(guò) dockerfile 設(shè)置 volume 也可以設(shè)置多個(gè),不過(guò)這種方式都是相對(duì)目錄的方式,而且文件名還隨機(jī),相當(dāng)于上述的-v 只指定一個(gè)的情況:
1 | [root@VM_156_200_centos volumes]# docker run -it -v /test2 --name centos-demo-1 centos |
如果是屬于 volume,那么直接調(diào)用docker volume rm xxx 就可以刪除了:
1 2 3 4 5 6 | [root@VM_156_200_centos docker-volume-centos]# docker volume ls DRIVER VOLUME NAME ... local js-data [root@VM_156_200_centos docker-volume-centos]# docker volume rm js-data js-data |
如果是掛載的數(shù)據(jù)卷容器,就調(diào)用docker rm xxx 當(dāng)做普通容器刪除即可:
1 2 | [root@VM_156_200_centos docker-volume-centos]# docker rm centos-js-data centos-js-data |
雖然容器刪除了,但是宿主機(jī)掛載的本地目錄的資料還是存在的。
這是個(gè)很有意思的現(xiàn)象,就是如果dockerfile里面的volume命令前后對(duì)共享目錄進(jìn)行操作的話,是會(huì)有差別的,舉個(gè)例子:
1 2 3 4 5 6 | [root@VM_156_200_centos docker-volume-centos]# cat dockerfile FROM centos RUN useradd foo VOLUME /data RUN touch /data/x RUN chown -R foo:foo /data |
這個(gè)是一個(gè)dockerfile,我們的預(yù)期目錄是,當(dāng)run起來(lái)之后,會(huì)有 /data/x 這個(gè)文件。 但是實(shí)際上沒(méi)有:
1 2 3 4 | [root@VM_156_200_centos docker-volume-centos]# docker build --rm -t kbz/volume-test . [root@VM_156_200_centos docker-volume-centos]# docker run -it --name volue-test-demo kbz/volume-test [root@3d037af9a5ca /]# cd /data [root@3d037af9a5ca data]# ls |
可以看到,雖然有 /data 這個(gè)目錄,但是在目錄里面并沒(méi)有 x 這個(gè)文件??? 這個(gè)是怎回事呢???
這個(gè)就涉及到dockerfile的運(yùn)行規(guī)則,在Dockerfile中的每個(gè)命令都會(huì)創(chuàng)建一個(gè)新的用于運(yùn)行指定命令的容器,并將容器提交到鏡像,每一步都是在前一步的基礎(chǔ)上構(gòu)建。
因此在Dockerfile中 ENV FOO=bar等同于:
1 2 | cid=$(docker run -e FOO=bar <image>) docker commit $cid |
那么針對(duì)我們本例的dockerfile,他的執(zhí)行順序應(yīng)該是(真實(shí)過(guò)程可能不是這樣的,但是應(yīng)該差不多):
1 2 3 4 5 6 7 8 | cid=$(docker run centos useradd foo) image_id=$(docker commit $cid) cid=$(docker run -v /data centos) image_id=$(docker commit $cid) cid=$(docker run $image_id touch /data/x) image_id=$(docker commit $cid) cid=$(docker run $image_id chown -R foo:foo /data) docker commit $(cid) volue-test-demo |
那這個(gè)過(guò)程就很明顯了,因?yàn)槊恳恍卸紩?huì)啟動(dòng)一個(gè)新的容器,因此每次都會(huì)有一個(gè)新的 volume,也就是每次run的新容器, /data 都是新的。
所以其實(shí)我們的這個(gè) touch 操作,就是在當(dāng)前的 volume 的 data 目錄下操作的,而不是實(shí)際的容器或鏡像的文件系統(tǒng)內(nèi)。所以當(dāng)我們重新再run的時(shí)候,這時(shí)候新的 volume 又是一個(gè)空的 data 目錄。
所以如果要改的話,應(yīng)該要把這個(gè) touch 的操作,先存在鏡像的文件系統(tǒng)之內(nèi),然后最后在掛載目錄:
1 2 3 4 5 6 7 | [root@VM_156_200_centos docker-volume-centos]# vim dockerfile [root@VM_156_200_centos docker-volume-centos]# cat dockerfile FROM centos RUN useradd foo RUN touch /data/x RUN chown -R foo:foo /data VOLUME /data |
這個(gè)是改完后的 dockerfile
1 2 3 4 5 | [root@VM_156_200_centos docker-volume-centos]# docker build --rm -t kbz/volume-test-2 . [root@VM_156_200_centos docker-volume-centos]# docker run -it --name volue-test-demo-2 kbz/volume-test-2 [root@2850978389ac /]# cd /data [root@2850978389ac data]# ls x |
這時(shí)候就有 x 文件了。 而且對(duì)應(yīng)的宿主目錄也有這個(gè) x 文件了:
1 2 3 | [root@VM_156_200_centos docker-volume-centos]# cd /var/lib/docker/volumes/d4c83377d137104a13893b31e42c57e3635e8e59c14027463361b814c86c6ad7/_data [root@VM_156_200_centos _data]# ls x |
感謝各位的閱讀,以上就是“Docker目錄掛載及文件共享的方法”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)Docker目錄掛載及文件共享的方法這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。