容器中的數(shù)據(jù)與Host相互獨(dú)立,隨著容器的釋放(刪除),這些數(shù)據(jù)也將丟失.
為了避免這個(gè)問(wèn)題,Docker提供了數(shù)據(jù)卷(Volume)這個(gè)數(shù)據(jù)持久化工具.
持久化后的數(shù)據(jù),不會(huì)隨著容易刪除而丟失.
概述
試想這樣一個(gè)場(chǎng)景,幾年前我創(chuàng)建了一個(gè)mysql5.5
的容器,幾年后由于業(yè)務(wù)變動(dòng),需要升級(jí)到mysql5.6
,這個(gè)時(shí)候需要登陸到容器里面,把mysql
的表文件復(fù)制下來(lái),再想辦法遷移到新的mysql
服務(wù)中.
這個(gè)手動(dòng)復(fù)制的過(guò)程很容易出現(xiàn)意外,萬(wàn)一不粗心大意,沒(méi)有復(fù)制data就刪除了容器,那差不多可以跑路了,否則就等著全村吃席吧.
好在Docker提供了bind mount
和volume
兩種方式來(lái)做數(shù)據(jù)持久化,先準(zhǔn)備個(gè)mysql
鏡像準(zhǔn)備演示.
docker pull mysql:5.6
bind mount
bind mount
是將host
上的一個(gè)目錄mount
到容器中,類似于一個(gè)共享文件夾.
要bind mount
一個(gè)目錄到容器,需要在創(chuàng)建容器時(shí)使用-v 本地目錄:容器目錄
參數(shù)指定
docker run -v /Users/zhangsan/opt:/opt ......
上述例子將本地/Users/zhangsan/opt
目錄掛在到容器的/opt
目錄. 登陸容器,
docker exec -it mysql_test_volume /bin/bash
echo Hello,World >> index.html
exit
此時(shí)本地的/Users/zhangsan/opt
目錄就會(huì)出現(xiàn)剛才創(chuàng)建index.html
.
反之,如果在本地新增文件index2.html
,容器內(nèi)也會(huì)出現(xiàn)這個(gè)文件.
使用bind mount
需要注意以下幾點(diǎn):
-
host
路徑必須為全路徑,否則回和volume
混淆 - 如果
host
目錄不存在,docker
會(huì)自動(dòng)創(chuàng)建該目錄 - 如果容器目錄不存在,
docker
會(huì)自動(dòng)創(chuàng)建該目錄 - 如果容器目錄已有數(shù)據(jù),那么
docker
會(huì)將其覆蓋掉
就上面那個(gè)場(chǎng)景,如果使用了 bind mount
,此時(shí)只需要新起一個(gè)5.6版本的容器,將目錄mount到新地址即可.
docker run -v /Users/zhangsan/opt:/opt --name mysql_test_volume -d -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:5.6
由于bind mount
本質(zhì)是個(gè)共享文件夾,因而依賴于系統(tǒng)文件系統(tǒng),不同系統(tǒng)間無(wú)法移植,
windows
的NTFS
文件系統(tǒng)就無(wú)法與linux
常用的ext3/4
兼容,windows
目錄為\Users\zhangsan\...
格式,
而ext4
文件系統(tǒng)目錄路徑為/usr/...
volume
volume
是容器上的一個(gè)或者多個(gè)目錄,此目錄可以繞過(guò)文件系統(tǒng),與宿主機(jī)上的某目錄綁定.
volume
于容器化初始化之時(shí)即會(huì)創(chuàng)建,可以在不同host上移植,卷中的數(shù)據(jù)會(huì)在build image
期間完成復(fù)制.
- 數(shù)據(jù)卷可以在容器之間共享和重用
- 對(duì)數(shù)據(jù)卷的更改是直接進(jìn)行的
- 更新鏡像時(shí),不包括對(duì)數(shù)據(jù)卷的更改
- 即使刪除容器本身,數(shù)據(jù)卷也會(huì)保持
使用docker volume create volume_name
來(lái)創(chuàng)建一個(gè)卷
docker volume create test
將test
掛在到容器上
docker run -v test:/opt --name mysql_test_volume -d -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 mysql:5.6
查看所有卷,使用
docker volume ls
查看一個(gè)卷信息,使用
docker volume inspect volume_name
刪除未使用的卷
docker volume prune
刪除一個(gè)卷
docker volume rm volume_name
與bind mount
不同的是,
- 如果
volume
是空的而容器中的目錄有內(nèi)容,那么docker
會(huì)將container
目錄中的內(nèi)容拷貝到volume中 - 但是如果
volume
中已經(jīng)有內(nèi)容,則會(huì)將container
中的目錄覆蓋 - Mac系統(tǒng)的
docker Desktop
實(shí)際上是構(gòu)建在虛擬機(jī)上的,其volume在虛擬機(jī)的var/lib/docker/volume中
,本機(jī)上不存在這個(gè)路徑.
volume遷移
最2的方式,登陸host
的/var/lib/docker/volume
目錄找到對(duì)應(yīng)的volume
,打包帶走,在新host
的volume
中解壓.
上面注部分提到過(guò)volume
的特點(diǎn),可以利用這點(diǎn)來(lái)進(jìn)行遷移,假設(shè)有一個(gè)卷test
需要遷移,步驟如下
1.下載一個(gè)鏡像,越小越好,比如(alpine)
2.通過(guò)這個(gè)鏡像創(chuàng)建容器A
,掛在test
,由于容器內(nèi)容為空,test
中的數(shù)據(jù)會(huì)被復(fù)制到容器目錄中
3.打包這個(gè)容器A
打包成鏡像image-A
,push
或者本地快照
4.新機(jī)器上新建同名volume
,然后pull
或者import
鏡像image-A
5.通過(guò)鏡像image-A
啟動(dòng)容器B
,掛載卷test
,由于test
是空的而容器目錄有內(nèi)容,docker
會(huì)將container
目錄中的內(nèi)容拷貝到volume中.
6.刪除鏡像image-A
,容器A
,容器B
,由于數(shù)據(jù)卷不會(huì)被刪除,因而就完成了遷移,可以給新的容器使用.
這樣volume
就隨著容器遷移到新的host上了