1. 程式人生 > >Docker第七篇-Docker掛載Volume資料卷

Docker第七篇-Docker掛載Volume資料卷

文章目錄


docker容器提供volume資料卷的方式,可以將容器某個目錄或者檔案掛載到宿主機的某個目錄或者檔案。這種方式的好處就是可以將容器內的資料掛載到宿主機,比如mysql的資料,即使容器意外宕機或者被刪除的話,只要資料還在,我們就可以啟動一個新的mysql容器。

建立一個數據卷並掛載宿主機

這裡先初步舉個例子,用來理解什麼是資料卷,什麼是掛載,容器和宿主機又是如何進行關聯:

啟動redis容器,將名稱改為redis,併為容器新增一個數據卷,這個資料卷在容器裡的目錄是/opt/data
[[email protected] ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
redis               latest              0a153379a539        5 days ago          83.4MB

[
[email protected] ~]# docker run --name redis -v /opt/data -tid 0a153379a539 /bin/bash 145fe5a93a6deaa76fd6c408d2b88ef2d685af48b03db3d0f64dd4a768b709a8 [[email protected] ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 145fe5a93a6d 0a153379a539 "docker-entrypoint.s…"
14 seconds ago Up 13 seconds 6379/tcp redis 進入容器,在資料卷目錄下建立檔案 [[email protected] ~]# docker exec -it redis /bin/bash [email protected]:/data# cd /opt/data/ [email protected]:/opt/data# ls [email protected]:/opt/data# echo 123 > 123 [email protected]:/opt/data# echo 123123 > 123123 [email protected]:/opt/data# ls 123 123123 退出容器,在宿主機上檢視對應上面的那個資料卷的目錄路徑,並修改其中一個檔案 [email protected]:/opt/data# exit exit [[email protected] ~]# docker inspect redis|grep /var/lib/docker/volumes "Source": "/var/lib/docker/volumes/442f7aaf3f84b6b41d4cffc4e3e71a84ab1b89fe9dbe70b76e99f851ff1bf66e/_data", "Source": "/var/lib/docker/volumes/b11ec41d372b348ca953e6ba5eccfa88cd732d84f08524af8a3c40e1eb466362/_data", [[email protected] ~]# ls /var/lib/docker/volumes/442f7aaf3f84b6b41d4cffc4e3e71a84ab1b89fe9dbe70b76e99f851ff1bf66e/_data 123 123123 [[email protected] ~]# echo abcdef >> /var/lib/docker/volumes/442f7aaf3f84b6b41d4cffc4e3e71a84ab1b89fe9dbe70b76e99f851ff1bf66e/_data/123 進入容器,檢視修改是否同步 [[email protected] ~]# docker exec -it redis /bin/bash [email protected]:/data# ls /opt/data/ 123 123123 [email protected]:/data# cat /opt/data/123 123 abcdef

掛載宿主機檔案或目錄到容器資料卷

可以直接掛載宿主機檔案或目錄到容器裡,可以理解為目錄對映,這樣就可以讓所有的容器共享宿主機資料,從而只需要改變宿主機的資料來源就能夠影響到所有的容器資料,或者當容器意外刪除的時候,宿主機的資料仍然有一份,便於容災。
掛載命令:

-v hostFile:containerFile
  • hostFile表示宿主機的目錄或檔案,需要提前存在的
  • containerFile表示容器的目錄或檔案,執行容器時會自動建立
  • 容器資料卷的許可權預設是可讀可寫許可權,如果需要設定許可權,則使用命令 -v hostFile:containerFile:ro
  • 如果沒有指定hostFile,即命令如果為 -v containerFile 則宿主機的預設目錄為 /var/lib/docker/volumes/ 下,具體的對映關係可以使用命令檢視 docker inspect [容器名稱]|grep /var/lib/docker/volumes
  • 注意:目錄只能掛載目錄,檔案只能掛載檔案!

掛載宿主機檔案到容器檔案上

[[email protected] test]# pwd
/usr/local/test
[[email protected] test]# cat web.list 
192.168.0.1
192.168.0.2
192.168.0.3

執行容器,ro表示該檔案在容器內是隻讀的
[[email protected] test]# docker run -tid --name redis -v /usr/local/test/web.list:/usr/local/test/web.list:ro redis /bin/bash
038603af3e21e509a827f1f18ab749ffd9e3a31982ce1f58936a710aa0bcbe6e
[[email protected] test]# docker exec -it redis /bin/bash
[email protected]:/data# cat /usr/local/test/web.list 
192.168.0.1
192.168.0.2
192.168.0.3

容器內修改檔案,發現會提示該檔案是隻讀的
[email protected]:/data# echo '192.168.0.4' >> /usr/local/test/web.list
bash: /usr/local/test/web.list: Read-only file system

掛載宿主機目錄到容器目錄上

[[email protected] test]# mkdir -p /usr/local/dalomao
[[email protected] test]# echo 'test' > /usr/local/dalomao/test
[[email protected] test]# echo 'test1' > /usr/local/dalomao/test1
[[email protected] test]# docker run -tid --name redis -v /usr/local/dalomao:/usr/local/dalomao redis /bin/bash
ee4ea05150476c6da22512597028ed18b17a1737f7644ebdad896e4ade389e97

容器上檢視並修改
[[email protected] test]# docker exec -it redis /bin/bash
[email protected]:/data# cd /usr/local/dalomao/
[email protected]:/usr/local/dalomao# ls
test  test1
[email protected]:/usr/local/dalomao# cat test
test
[email protected]:/usr/local/dalomao# cat test1
test1
[email protected]:/usr/local/dalomao# echo '1234' >> test
[email protected]:/usr/local/dalomao# echo '4311' >> test1

宿主機上檢視
[email protected]:/usr/local/dalomao# exit
exit
[[email protected] test]# cat /usr/local/dalomao/test
test
1234
[[email protected] test]# cat /usr/local/dalomao/test1
test1
4311

掛載多個目錄

[[email protected] test]# mkdir -p /usr/local/dalomao/data1
[[email protected] test]# mkdir -p /usr/local/dalomao/data2
[[email protected] test]# echo '123456' > /usr/local/dalomao/data1/test1
[[email protected] test]# echo 'abcdef' > /usr/local/dalomao/data2/test2
[[email protected] test]# docker run -tid --name redis -v /usr/local/dalomao/data1:/usr/local/dalomao/data1 -v /usr/local/dalomao/data2:/usr/local/dalomao/data2 redis /bin/bash
ef4d028958386f09352275daf9964f1fad259264e10a5662de46114cef50a0ca

容器內檢視並修改
[[email protected] test]# docker exec -ti redis /bin/bash
[email protected]:/data# ls /usr/local/dalomao/data1
test1
[email protected]:/data# ls /usr/local/dalomao/data2
test2
[email protected]:/data# cat /usr/local/dalomao/data1
cat: /usr/local/dalomao/data1: Is a directory
[email protected]:/data# cat /usr/local/dalomao/data1/test1 
123456
[email protected]:/data# cat /usr/local/dalomao/data2/test2 
abcdef
[email protected]:/data# echo 'data1' >> /usr/local/dalomao/data1/test1
[email protected]:/data# echo 'data2' >> /usr/local/dalomao/data2/test2

容器間掛載

啟動一個名為container1容器,此容器包含兩個資料卷/var/volume1和/var/volume2,這兩個目錄是在容器裡的,執行容器時會自動建立

[[email protected] test]# docker run -tid --name container1 -v /var/volume1 -v/var/volume2 redis /bin/bash
61a8b7761e96c01798a0e77371bf5e74546e469a747b38f457d68011dbdf6486
[[email protected] test]# docker inspect container1|grep /var/lib/docker/volumes
                "Source": "/var/lib/docker/volumes/5bde8e911fe864a982a67800eca3313a92d116cfec7d5667cc09d5d44ff31196/_data",
                "Source": "/var/lib/docker/volumes/4323c7faa7eb1e2a29e52f9c65983e0016054b0dc23dd15faa41c30c7f0ad846/_data",
                "Source": "/var/lib/docker/volumes/fd74c2f2e44d7fba2e5c1257e99eec14009af96e0a1f1c09fb46f642c2b3ab83/_data",

建立container2容器,掛載container1容器中的資料卷

[[email protected] test]# docker run -tid --rm --volumes-from container1 --name container2 redis /bin/bash
4bb09861542a6bc2eb6a9e98049a5b54953a76c57f1ecc637468ca10b48dc0dd

登陸容器2檢視並修改內容
[[email protected] test]# docker exec -ti container2 /bin/bash
[email protected]:/data# ls /var/volume1
[email protected]:/data# ls /var/volume2
[email protected]:/data# echo 'this is volume1' > /var/volume1/test1
[email protected]:/data# echo 'this is volume2' > /var/volume2/test2

登陸容器1檢視修改後的內容
[email protected]:/data# exit
exit
[[email protected] test]# docker exec -ti container1 /bin/bash
[email protected]:/data# cat /var/volume1/test1 
this is volume1
[email protected]:/data# cat /var/volume2/test2 
this is volume2

再建立一個container3,掛載container2中從container1掛載的資料卷,當然也可以直接掛載初識的container1容器的資料卷

[[email protected] test]# docker run -tid --rm --volumes-from container2 --name container3 redis /bin/bash
63c57cd4bc183f7d41e18e86e3359e6a431eae3015b6c4056f0035e7e6ff3783
[[email protected] test]# docker exec -ti container3 /bin/bash
[email protected]:/data# cat /var/volume1/test1 
this is volume1
[email protected]:/data# cat /var/volume2/test2 
this is volume2
  • 即使刪除了初始的資料卷容器container1,或者是刪除了其他容器,但只要是有容器在使用該資料卷,那麼它裡面的資料就不會丟失
  • 命令中的rm表示當容器退出即停止的時候,會自動刪除該容器

備份資料卷

建立一個容器container1,包含兩個資料卷/var/volume1和/var/volume2(這兩個目錄是在容器裡的資料卷路徑)

[[email protected] test]# docker run -tid -v /var/volume1 -v /var/volume2 --name container1 redis /bin/bash
2a76939f65eac00110dfff3bc3e0dd99a33804e2175397133184449afb2af731
[[email protected] test]# docker exec -ti redis /bin/bash
[[email protected] test]# docker exec -ti container1 /bin/bash
[email protected]:/data# echo 'test1' > /var/volume1/test1
[email protected]:/data# echo 'test11' > /var/volume1/test11
[email protected]:/data# echo 'test2' > /var/volume2/test2
[email protected]:/data# echo 'test22' > /var/volume2/test22
[email protected]:/data# ls /var/volume1
test1  test11
[email protected]:/data# ls /var/volume2
test2  test22

接下來進行資料卷的備份操作

使用–volumes-from表姐來建立一個載入container1容器卷的容器,並從宿主機掛載當前所在目錄到容器的/backup目錄,容器內會tar壓縮/var/colume1目錄下的檔案到/backup/backup1.tar,因為宿主機當前目錄已經對映到/backup目錄了,因此會在宿主機當前目錄也存在該壓縮包。備份完畢後–rm自動刪除該建立的容器。

備份container1容器中的/var/volume1資料卷資料
-tid這個引數加不加都可以
--rm加上,備份後就會自動刪除這個容器,如果不加這個--rm引數,那麼備份後的容器就會保留,docker ps -a就會檢視到)
$(pwd)表示當前宿主機目錄
[[email protected] test]# pwd
/usr/local/test
[[email protected] test]# docker run -tid --rm --volumes-from container1 -v $(pwd):/backup redis tar cvf /backup/backup1.tar /var/volume1
67b1eda88b832c29db7d5e0850fe31955b83ad0c244b657ac30e2e3f18e416a3

本地目錄就會生成backup1.tar檔案
解壓後的目錄結構是:
--var
	--volume1
		--test1
		--test11
[[email protected] test]# ls
backup1.tar
備份container1容器中的/var/volume2資料卷資料
[[email protected] test]# pwd
/usr/local/test
[[email protected] test]# docker run -tid --rm --volumes-from container1 -v $(pwd):/backup redis tar cvf /backup/backup2.tar /var/volume2
896adf78f9b6a06d6543b72e4977d6d16cb623157ee09f22a7fc6a8367e72478
[[email protected] test]# ll
total 24
-rw-r--r--. 1 root root 10240 Oct 15 01:20 backup1.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:36 backup2.tar
備份container1容器中的/var/volume1和/var/volume2資料卷資料
[[email protected] test]# pwd
/usr/local/test
[[email protected] test]# docker run -tid --rm --volumes-from container1 -v $(pwd):/backup redis tar cvf /backup/backup.tar /var/volume1 /var/volume2
60c7b06e27708e98a1f8ddf48a8e287af152699e88026fa75b6133a4b2977be9
[[email protected] test]# ll
total 36
-rw-r--r--. 1 root root 10240 Oct 15 01:20 backup1.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:36 backup2.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:38 backup.tar

恢復和遷移資料卷

使用備份資料卷一章中的容器container1和備份資料卷backup.tar進行恢復操作

恢復資料給同一個容器

之前的資料卷是從container1中備份的,現在模擬container1資料卷丟失,然後直接用之前備份的backup.tar進行恢復

為了測試恢復,先刪除容器裡原先的資料(注意:資料卷目錄不能刪除,只能刪除其中的資料)
[email protected]:/data# ls /var/volume2
test2  test22
[email protected]:/data# rm -rf /var/volume1 /var/volume2
rm: cannot remove '/var/volume1': Device or resource busy
rm: cannot remove '/var/volume2': Device or resource busy
[email protected]:/data# ls /var/volume1
[email protected]:/data# ls /var/volume2

進行資料卷恢復,恢復資料卷中的所有資料
[email protected]:/data# exit
exit
[[email protected] test]# pwd
/usr/local/test
[[email protected] test]# ll
total 36
-rw-r--r--. 1 root root 10240 Oct 15 01:20 backup1.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:36 backup2.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:38 backup.tar

注意-C後面的路徑,表示將資料恢復到容器裡的路徑直接使用壓縮包中檔案的各個路徑。比如壓縮包中的結果如下:
--var
	--volume1
		--test1
		--test11
	--volume2
		--test22
		--test22	
則直接將檔案解壓到 /var/volume1和/var/volume2目錄		
[[email protected] test]# docker run --rm --volumes-from container1 -v $(pwd):/backup redis tar xvf /backup/backup.tar -C /
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume2/
var/volume2/test2
var/volume2/test22

登陸容器,檢視資料卷已經正確恢復
[[email protected] test]# docker exec -ti container1 /bin/bash
[email protected]:/data# ls /var/volume1
test1  test11
[email protected]:/data# ls /var/volume2
test2  test22

恢復資料給新的容器

新建一個容器container2
[[email protected] test]# docker run -tid -v /var/volume1 -v /var/volume2 --name container2 redis /bin/bash
75b28049c3823843fb2e0fd8bae87671f0cf4ea27b495a4f725821c4edb2883a
[[email protected] test]# docker exec -ti container2 /bin/bash
[email protected]:/data# ls /var/volume1
[email protected]:/data# ls /var/volume2

開始恢復
[email protected]:/data# exit
exit
[[email protected] test]# pwd
/usr/local/test
[[email protected] test]# ll
total 36
-rw-r--r--. 1 root root 10240 Oct 15 01:20 backup1.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:36 backup2.tar
-rw-r--r--. 1 root root 10240 Oct 15 01:38 backup.tar
[[email protected] test]# docker run --rm --volumes-from container2 -v $(pwd):/backup redis tar xvf /backup/backup.tar -C /
var/volume1/
var/volume1/test1
var/volume1/test11
var/volume2/
var/volume2/test2
var/volume2/test22

檢視確實已經恢復了
[[email protected] test]# docker exec -ti container2 /bin/bash
[email protected]:/data# ls /var/volume1
test1  test11
[email protected]:/data# ls /var/volume2
test2  test22

注意:

  • 新容器建立時掛載的資料卷路徑最好和之前備份的資料卷路徑一致
  • 新容器建立時,如果掛載的資料卷只是備份資料卷的一部分,那麼恢復的時候也只是恢復一部分資料。比如新建容器掛載資料卷為-v /var/voluem1,那麼使用backup.tar恢復時,只會恢復/var/volume1的資料,/var/volume2的資料是不會恢復的
  • 如果新容器建立時掛載的資料卷目錄和備份的資料卷目錄不一致,那麼資料恢復不了,除非修改 -C 後面的路徑,比如新建容器時指定資料卷目錄為 /var/volume,恢復時也是用 -C /var/volume,則是可以成功恢復的

刪除資料卷

Docker不會在容器被刪除後自動刪除資料卷,並且也不存在垃圾回收這樣的機制來處理沒有任何容器引用的資料卷。如果需要在刪除容器的同時移除資料卷,可以在刪除容器的時候使用 docker rm -v 這個命令。無主的資料卷可能會佔據很多空間,要清理會很麻煩

  • docker volume ls     列出所有的資料卷
  • docker volume ls --filter dangling=true     過濾不在使用的資料卷
  • docker volume rm [volume name]     刪除一個數據卷,容器正在使用的資料卷不能刪除,繫結掛載的資料卷無法刪除