到目前為止,我們已經(jīng)介紹了docker的一些基本概念,了解了如何使用docker鏡像,以及容器之間如何通過(guò)網(wǎng)絡(luò)連接。本節(jié),我們來(lái)討論如何管理容器和容器間的共享數(shù)據(jù)。
接下來(lái),我們將主要介紹Docker管理數(shù)據(jù)的兩種主要的方法:
數(shù)據(jù)卷是指在存在于一個(gè)或多個(gè)容器中的特定目錄,此目錄能夠繞過(guò)Union File System提供一些用于持續(xù)存儲(chǔ)或共享數(shù)據(jù)的特性。
你可以在docker run命令中使用-v標(biāo)識(shí)來(lái)給容器內(nèi)添加一個(gè)數(shù)據(jù)卷,你也可以在一次docker run命令中多次使用-v標(biāo)識(shí)掛載多個(gè)數(shù)據(jù)卷。現(xiàn)在我們?cè)趙eb容器應(yīng)用中創(chuàng)建單個(gè)數(shù)據(jù)卷。
$ sudo docker run -d -P --name web -v /webapp training/webapp python app.py
這會(huì)在容器內(nèi)部創(chuàng)建一個(gè)新的卷/webapp
注:類似的,你可以在
Dockerfile中使用VOLUME指令來(lái)給創(chuàng)建的鏡像添加一個(gè)或多個(gè)數(shù)據(jù)卷。
使用-v,除了可以創(chuàng)建一個(gè)數(shù)據(jù)卷,還可以掛載本地主機(jī)目錄到容器中:
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
這將會(huì)把本地目錄/src/webapp掛載到容器的/opt/webapp目錄。這在做測(cè)試時(shí)是非常有用的,例如我們可以掛載宿主機(jī)的源代碼到容器內(nèi)部,這樣我們就可以看到改變?cè)创a時(shí)的應(yīng)用時(shí)如何工作的。宿主機(jī)上的目錄必須是絕對(duì)路徑,如果目錄不存在docker會(huì)自動(dòng)創(chuàng)建它。
注:出于可移植和分享的考慮,這種方法不能夠直接在
Dockerfile中實(shí)現(xiàn)。作為宿主機(jī)目錄——其性質(zhì)——是依賴于特定宿主機(jī)的,并不能夠保證在所有的宿主機(jī)上都存在這樣的特定目錄。
docker默認(rèn)情況下是對(duì)數(shù)據(jù)卷有讀寫權(quán)限,但是我們通過(guò)這樣的方式讓數(shù)據(jù)卷只讀:
$ sudo docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py
這里我們同樣掛載了/src/webapp目錄,只是添加了ro選項(xiàng)來(lái)限制它只讀。
除了能掛載目錄外,-v標(biāo)識(shí)還可以將宿主機(jī)的一個(gè)特定文件掛載為數(shù)據(jù)卷:
$ sudo docker run --rm -it -v ~/.bash_history:/.bash_history ubuntu /bin/bash
上述命令會(huì)在容器中運(yùn)行一個(gè)bash shell,當(dāng)你退出此容器時(shí)在主機(jī)上也能夠看到容器中bash的命令歷史。
注:很多文件編輯工具如
vi和sed --in-place會(huì)導(dǎo)致inode change。Docker v1.1.0之后的版本,會(huì)產(chǎn)生一個(gè)錯(cuò)誤:“sed cannot rename ./sedKdJ9Dy: Device or resource busy”。這種情況下如果想要更改掛載的文件,最好是直接掛載它的父目錄。
如果你想要容器之間數(shù)據(jù)共享,或者從非持久化容器中使用一些持久化數(shù)據(jù),最好創(chuàng)建一個(gè)指定名稱的數(shù)據(jù)卷容器,然后用它來(lái)掛載數(shù)據(jù)。
讓我們創(chuàng)建一個(gè)指定名稱的數(shù)據(jù)卷容器:
$ sudo docker run -d -v /dbdata --name dbdata training/postgres echo Data-only container for postgres
你可以在另外一個(gè)容器使用--volumes-from標(biāo)識(shí),通過(guò)剛剛創(chuàng)建的數(shù)據(jù)卷容器來(lái)掛載對(duì)應(yīng)的數(shù)據(jù)卷。
$ sudo docker run -d --volumes-from dbdata --name db1 training/postgres
可以將對(duì)應(yīng)的數(shù)據(jù)卷掛載到更多的容器中:
$ sudo docker run -d --volumes-from dbdata --name db2 training/postgres
當(dāng)然,您也可以對(duì)一個(gè)容器使用多個(gè)--volumes-from標(biāo)識(shí),來(lái)將多個(gè)數(shù)據(jù)卷橋接到這個(gè)容器中。
數(shù)據(jù)卷容器是可以進(jìn)行鏈?zhǔn)綌U(kuò)展的,之前的dbdata數(shù)據(jù)卷依次掛載到了dbdata 、db1和db2容器,我們還可以使用這樣的方式來(lái)將數(shù)據(jù)卷掛載到新的容器db3:
$ sudo docker run -d --name db3 --volumes-from db1 training/postgres
即使你刪除所有de 掛載了數(shù)據(jù)卷dbdata的容器(包括最初的dbdata容器和后續(xù)的db1和db2),數(shù)據(jù)卷本身也不會(huì)被刪除。要?jiǎng)h在磁盤上刪除這個(gè)數(shù)據(jù)卷,只能針對(duì)最后一個(gè)掛載了數(shù)據(jù)卷的容器顯式地調(diào)用docker rm -v命令。這種方式可使你在容器之間方便的更新和遷移數(shù)據(jù)。
數(shù)據(jù)卷還可以用來(lái)備份、恢復(fù)或遷移數(shù)據(jù)。為此我們使用--volumes-from參數(shù)來(lái)創(chuàng)建一個(gè)掛載數(shù)據(jù)卷的容器,像這樣:
$ sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
這里我們啟動(dòng)了一個(gè)掛載dbdata卷的新容器,并且掛載了一個(gè)本地目錄作為/backup卷。最后,我們通過(guò)使用tar命令將dbdata卷的內(nèi)容備份到容器中的/backup目錄下的backup.tar文件中。當(dāng)命令完成或者容器停止,我們會(huì)留下我們的dbdata卷的備份。
然后,你可以在同一容器或在另外的容器中恢復(fù)此數(shù)據(jù)。創(chuàng)建一個(gè)新的容器
$ sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后在新的容器中的數(shù)據(jù)卷里un-tar此備份文件。
$ sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
你可以對(duì)熟悉的目錄應(yīng)用此技術(shù),來(lái)測(cè)試自動(dòng)備份、遷移和恢復(fù)。