1.什么是數(shù)據(jù)卷volume 為了了解什么是Docker Volume,,首先我們需要明確Docker內(nèi)的文件系統(tǒng)是如何工作的。Docker鏡像被存儲(chǔ)在一系列的只讀層,。當(dāng)我們開啟一個(gè)容器,,Docker讀取只讀鏡像并添加一個(gè)讀寫層在頂部。如果正在運(yùn)行的容器修改了現(xiàn)有的文件,,該文件將被拷貝出底層的只讀層到最頂層的讀寫層,。在讀寫層中的舊版本文件隱藏于該文件之下,但并沒有被不破壞 - 它仍然存在于鏡像以下,。當(dāng)Docker的容器被刪除,,然后重新啟動(dòng)鏡像時(shí),將開啟一個(gè)沒有任何更改的新的容器
- 這些更改會(huì)丟失,。此只讀層及在頂部的讀寫層的組合被Docker稱為Union File System(聯(lián)合文件系統(tǒng)),。 2.為什么使用數(shù)據(jù)卷volumeDocker的鏡像是由一系列的只讀層組合而來,,當(dāng)啟動(dòng)一個(gè)容器的時(shí)候,,Docker加載鏡像的所有只讀層,并在最上層加入一個(gè)讀寫層,。這個(gè)設(shè)計(jì)使得Docker可以提高鏡像構(gòu)建,、存儲(chǔ)和分發(fā)的效率,節(jié)省了時(shí)間和存儲(chǔ)空間,,然而也存在如下問題,。 (1)容器中的文件在宿主機(jī)上存在形式復(fù)雜,不能在宿主機(jī)上很方便的對(duì)容器中的文件進(jìn)行訪問 (2)多個(gè)容器之間的數(shù)據(jù)無法共享 (3)當(dāng)刪除容器時(shí),,容器產(chǎn)生的數(shù)據(jù)將丟失 為了解決這些問題,,Docker引入了數(shù)據(jù)卷(volume)機(jī)制。volume是存在一個(gè)或多個(gè)容器中的特定文件或文件夾,,這個(gè)目錄能夠獨(dú)立于聯(lián)合文件系統(tǒng)的形式在宿主機(jī)中存在,,并為數(shù)據(jù)的共享與持久提供一下便利。 (1)volume在容器創(chuàng)建時(shí)就初始化,,在容器運(yùn)行時(shí)就可以使用其中的文件 (2)volume能在不同的容器之間共享和重用 (3)對(duì)volume中的數(shù)據(jù)的操作會(huì)馬上生效 (4)對(duì)volume中數(shù)據(jù)操作不會(huì)影響到鏡像本身 (5)volume的生存周期獨(dú)立于容器的生存周期,,即使刪除容器,volume仍然會(huì)存在,,沒有任何容器使用的volume也不會(huì)被Docker刪除 3.如何使用數(shù)據(jù)卷3.1 從容器掛載volume(-v /path)在使用docker run創(chuàng)建新容器的時(shí)候,,可以使用-v 標(biāo)簽為容器添加數(shù)據(jù)卷volume,以下用法是從容器中的某個(gè)文件夾創(chuàng)建volume,,如果容器中指定的文件夾不存在,,會(huì)自動(dòng)生成
在上面的概念中,有說道,,宿主機(jī)應(yīng)該會(huì)有一個(gè)文件夾綁定掛載到容器中的volume掛載點(diǎn),,那默認(rèn)的宿主機(jī)上的文件夾在哪呢,使用docker inspect命令,,查看下容器詳情(CRT令起一個(gè)SSH終端) 注意看Mounts節(jié)點(diǎn)(Docker的版本用的是1.10.3),數(shù)據(jù)卷的使用,,類似于 Linux 下對(duì)目錄或文件進(jìn)行 mount。
當(dāng)我們?cè)谌萜鞯膙olume上操作時(shí),,宿主機(jī)上對(duì)應(yīng)的文件是否也會(huì)跟著變動(dòng)呢,?測(cè)試一下,在容器的volume上創(chuàng)建一個(gè)文件test.txt,,然后查看宿主機(jī)是不是也會(huì)同步存在
經(jīng)測(cè)試,,當(dāng)容器上的volume有變動(dòng)時(shí),宿主機(jī)也會(huì)跟著變動(dòng),,那反過來呢,?經(jīng)測(cè)試也是一樣的,。不管是容器掛載點(diǎn)發(fā)生變動(dòng)還是宿主機(jī)對(duì)掛載目錄進(jìn)行操作,令一方都會(huì)跟著變動(dòng),。 利用docker commit生成新鏡像,,然后docker run -it 運(yùn)行新鏡像,發(fā)現(xiàn)容器掛載目錄下沒有任何文件了,。說明生成新鏡像時(shí),,是不保存掛載文件的。 3.2從宿主機(jī)掛載volume(-v /host-path:/container-path) 將主機(jī)的文件或文件夾作為volume掛載時(shí),,可以用多個(gè) -v標(biāo)簽為容器添加多個(gè)volume,,還可以使用:ro指定該volume為只讀。注意:如果容器中指定的掛載目錄存在相同的文件時(shí),,會(huì)被宿主機(jī)覆蓋掉
在宿主機(jī)上建立了/opt/vol-01和/opt/vol-02掛載點(diǎn),,分別和容器中的/opt/vol-test-1和/opt/vol-test-2對(duì)應(yīng),前者權(quán)限默認(rèn)讀寫,,后者只能讀,用docker inspect
當(dāng)在容器的vol-test-2上新建操作時(shí),,會(huì)提示只讀.在宿主機(jī)上,2個(gè)掛載點(diǎn)新增,,修改,,刪除操作都OK,但是在容器中居然2個(gè)都不行,,按理說應(yīng)用是第二個(gè)vol-test-2不行才對(duì),,不知是哪里出問題了。 利用docker commit生成新鏡像,,然后docker run -it 運(yùn)行新鏡像,發(fā)現(xiàn)容器掛載目錄下沒有任何文件了,。說明生成新鏡像時(shí),,是不保存掛載文件的。 3.3使用Dockerfile添加volume使用VOLUME指令向容器添加volume VOLUME /data 多個(gè)時(shí)VOLUME ['/data1','/data2'] 這種情況和第一個(gè)中情況docker run -v /data是一樣的,。注意,,dockerfile中使用volume是不能和第二種方法那樣掛載宿主機(jī)中指定的文件夾。這時(shí)為了保證Dockerfile的可移植性,,因?yàn)椴荒鼙WC所有的宿主機(jī)都有對(duì)應(yīng)的文件夾,。 需要注意的是,在Dockerfile中使用VOLUME指令后,,如果嘗試對(duì)這個(gè)volume進(jìn)行修改,,這些修改指令都不會(huì)生效,比如下面例子,,嘗試添加一個(gè)文件,,并修改文件并改變文件所有權(quán)限 FROM test/mycent:v1.0
RUN useradd foo
VOLUME /data
RUN touch /data/x
RUN chown -R foo:foo /data
通過該Dockerfile創(chuàng)建鏡像并啟動(dòng)容器后,,該容器中存在用戶foo,并且能看到在/data掛載的volume,,但是/data文件夾的所有者并沒有被改變?yōu)閒oo,,而且/data下也沒有/data/x文件。但是如果順序反過來,,先建文件,,先授權(quán),再掛載volume,,那就得到期待的結(jié)果,。 4.共享volume/數(shù)據(jù)卷容器(--volumes-from) 如果你有一些持續(xù)更新的數(shù)據(jù)需要在容器之間共享,最好創(chuàng)建數(shù)據(jù)卷容器,。數(shù)據(jù)卷容器,,其實(shí)就是一個(gè)正常的容器,專門用來提供數(shù)據(jù)卷供其它容器掛載的,。 先創(chuàng)建一個(gè)名為dbdata的數(shù)據(jù)卷容器,,專門共其他容器掛載。
在/opt/dbdata下創(chuàng)建了一個(gè)文件db.properties,。 再啟動(dòng)2個(gè)容器,,a,b都a--volumes-from dbdata,b --volumes-from a.
可以看到vol_a,vol_b容器的/opt/dbdata下都有db.properties文件,。在vol_b的/opt/dbdata下創(chuàng)建文件vol_b.txt時(shí),,容器dbdata,vol_a也都同時(shí)同步了。 對(duì)dbdata,vol_a,vol_b使用命令docker inspect時(shí),,發(fā)現(xiàn)他們的Mounts下的Source都是一樣的,,說明它們都綁定到宿主機(jī)的同一個(gè)目錄,所以當(dāng)某個(gè)容器的掛載修改時(shí),,其他容器也看到了同樣的效果
如果掛載源有多個(gè)時(shí),,可以使用多個(gè)--volumes-from,如 docker run -it --name vol_use --volumes-from vol_a --volumes-from vol_b test/mycentos:v1.0 /bin/bash. 如果一個(gè)容器掛在了volume,,即使容器停止了運(yùn)行,,該volume仍然存在,其他容器仍然可以繼續(xù)--volumes-from它,。
5.刪除volume如果創(chuàng)建容器時(shí)掛載了volume,,在/var/lib/docker/volumes/04b003b21b873157433deffbaf08bb0c89d234d3ec3c6576fdd7b61f5d41163e/_data下會(huì)生成相應(yīng)的文件(路徑,不同版本,,不同操作系統(tǒng)會(huì)有所不同,,具體可以用docker inspect查看容器具體信息),當(dāng)刪除容器時(shí),,宿主機(jī)上的掛載目錄時(shí)不會(huì)刪除的,,并且目錄名稱是隨機(jī)字符,,不知意義,所以在刪除容器時(shí),,需要妥善處理容器的volume,。刪除容器時(shí)一并刪除volume有2中方法 (1)docker rm -v 刪除容器。就是刪除容器時(shí),,加上-v (2)docker run --rm .就是啟動(dòng)容器的時(shí)候加上--rm,,那么當(dāng)容器運(yùn)行停止時(shí)會(huì)自動(dòng)刪除容器以及容器所掛載的volume 上面創(chuàng)建了容器dbdata,vol_a,vol_b,vol_c,現(xiàn)在使用docker rm -v看看有什么效果。
vol_c是--volumes-from dbdata的,,刪除vol_c時(shí),,宿主機(jī)的掛載目錄仍存在,沒刪掉,,猜測(cè)那是因?yàn)檫€有其他容器在連著或者說是dbdata -v的時(shí)候創(chuàng)建的,。那現(xiàn)在刪除dbdata容器試試看(vol_a是--volumes-from dbdata的,vol_a還沒刪除,,驗(yàn)證下能否刪除dbdata),。
發(fā)現(xiàn)dbdata刪除時(shí),宿主機(jī)那目錄仍然存在,,同時(shí)也說明哪怕vol_a是--volumes-from dbdata的,,vol_a還沒刪除,那也沒影響,。同時(shí)也說明只要還有一個(gè)容器在掛載這宿主機(jī)的目錄,,那宿主機(jī)的目錄就不會(huì)刪除。那接下來,,把所有容器都刪除,,再看結(jié)果。
可以看到,,當(dāng)最后一個(gè)容器刪除后,,宿主機(jī)那volume目錄終于刪除了. 6.備份、恢復(fù)或遷移volume上面有測(cè)試過,,當(dāng)使用docker commit等手段生成新鏡像,然后再啟動(dòng)鏡像生成新容器時(shí),,原先volume目錄下的文件不見了,,可以生成新鏡像時(shí),并沒有把volume下的文件一起打包生成鏡像,。 volume作為數(shù)據(jù)的載體,,在很多情況下需要對(duì)其中的數(shù)據(jù)進(jìn)行備份、遷移,,或是從已有數(shù)據(jù)恢復(fù),。一個(gè)很容易想到的方法就是用docker inspect命令查找到volume對(duì)應(yīng)宿主機(jī)上對(duì)應(yīng)的那個(gè)目錄位置,,然后復(fù)制其中內(nèi)容或使用tar打包。當(dāng)這些笨拙的做法并不值得推薦,,因?yàn)椴檎抑鳈C(jī)上文件夾后再操作容易出錯(cuò),,也不適合腳本的自動(dòng)化執(zhí)行。 備份volume可以使用以下方法 docker run --rm --volumes-from dbdata -v $(pwd):/backup test/mycentos:v1.0 tar cvf /back/data.tar /data 這行指令啟動(dòng)了一個(gè)臨時(shí)的容器,,這個(gè)容器掛載了兩個(gè)volume,,第一個(gè)volume與要備份的volume共享,第二個(gè)volume將宿主機(jī)的當(dāng)前目錄(也可以絕對(duì)路徑)掛載到容器的/backup下,。容器運(yùn)行后將要備份的容器(/data)備份到/backup/data.tar,,然后刪除容器,備份后的data.tar就留在了當(dāng)前目錄,。操作驗(yàn)證一下
居然報(bào)錯(cuò)了,,說沒有權(quán)限。進(jìn)入容器-it時(shí),,是docker隨機(jī)生成一個(gè)用戶的,,至于怎樣給該用戶授權(quán),以后再研究吧,。 |
|