>> 什麼是數據卷
Data Volume 數據卷:是可以存放在一個或多個容器內的特定的目錄,提供獨立於容器之外的持久化存儲;是經過特殊設計的目錄,可以繞過聯合文件系統(UFS),爲一個或多個容器提供訪問;
不使用volume的時候,對容器進行的改動是不會被保存的,使用volume可以實現持久化存儲;比如運行一個數據庫的操作,數據庫的一個容器,數據庫的數據應該被持久化存儲的,volume就可以實現這個,並且volume可以提供容器與容器之間的共享的數據;
Docker的理念之一:就是將其應用與其運行的環境打包,因此,通常Docker容器的生存週期,都是與在容器中運行的程序相一致的,而我們對數據的要求通常是持久化的;另一方面,docker容器之間也需要有一個共享數據的渠道,而這些需求就催生出了docker數據卷的產生;
數據卷的設計的目的:在於數據的永久化,它完全獨立於容器的生存週期,因此,Docker不會在容器刪除時刪除其掛載的數據卷,也不會存在類似垃圾收集機制,對容器引用的數據捲進行處理了;
數據卷特點:
- 1、Docker數據卷是獨立於Docker的存在,它存在於Docker host(宿主機)中,因此,它與容器的生存週期是分離的;
- 2、Docker數據卷本質上是存在於Docker宿主機的本地文件系統中;
- 3、Docker數據卷可以是目錄也可以是文件;
- 4、Docker容器可以利用數據卷的技術與宿主機進行數據共享;
- 5、同一個目錄或者文件,可以支持多個容器進行訪問,這樣其實實現了容器間的數據的共享和交換;
- 6、數據卷是在容器啓動時進行初始化的,那麼如果容器使用的鏡像包含了的數據也會在容器啓動時拷貝到容器的數據卷中;
- 7、
數據卷可以在容器之間共享和重用
; - 8、
對數據卷的修改會立馬生效
;容器可以對數據卷裏的內容直接進行修改;容器對數據捲進行的修改是及時進行的,所有的修改都會直接體現在數據卷中; - 9、
對數據卷的更新不會影響鏡像
;因爲文件不會寫到鏡像中去,數據卷是獨立於聯合文件系統的,而鏡像本身基於聯合文件系統,so鏡像與數據卷之間不會有相互影響的情況; - 10、
數據卷會一直存在,即使掛載數據卷的容器已經被刪除
;因爲數據卷本質上是宿主機上的一個目錄,同時爲了提供數據的永久化,它的生存週期與容器是完全隔離的;
Docker容器中的數據操作是經過了UFS的,UFS會再在宿主機中寫一次文件,這個文件在宿主機上是臨時的,這時候就出現了重複寫的情況,會影響系統的性能;此外,刪除容器的時候,就沒有人能夠通過UFS再訪問到宿主機中的文件了;
容器卷可以繞過UFS直接操作宿主機上的文件,當容器刪除的時候,宿主機上的文件還在,就在指定的目錄下,再重新創建容器的時候,可以指定容器繼續去讀取宿主機上的文件;
>> 使用Docker run命令爲容器添加數據卷
docker run -v ~/datavolume:data[:ro] -i -t imagesName
: 爲容器創建數據卷;
-
-v:指定數據卷本機文件系統中的目錄,和在容器中映射的目錄名,ro設置文件權限爲只讀;這個命令執行完時候會自動進入容器路徑下;
-
datavolume本機文件系統中的一個目錄,若不存在,則執行完run命令之後會自動在本機文件系統中創建該目錄;
-
data指定在容器中訪問的目錄名字;
-
ro設置容器中的文件權限爲只讀;在指定目錄映射後,再指定文件權限;數據卷設置爲只讀之後,不能再在數據卷目錄中創建文件了,數據卷中已經存在的文件可以讀取,不能改;
-
ls -l
:查看容器文件系統中的目錄結構; -
touch /data/c1
:使用touch命令在容器的文件系統中的data目錄下創建名叫c1的文件; -
echo "i am in container" > /data/c1
:使用echo命令輸出一個字符串; -
exit
:退出容器,回到本機文件系統 -
ls -l
:在本機上查看本機文件系統,可以看到datavolume文件夾; -
ls -l datacolumn
:查看文件夾的內容,可以看到剛纔在容器中創建的c1這個文件已經存在; -
vi datavolume/c1
:使用編輯器打開這個文件,可以看到剛纔輸出的字符也已經存在了; -
docker ps -l 、docker inspect imagesId
:使用inspect命令查看剛纔創建的鏡像,在輸出的位置可以看到剛纔創建的數據卷的信息;也就是說可以通過inspect命令來查看一個容器是否掛載了數據卷、以及容器中數據卷的讀寫權限;
>> 使用Dockerfile構建一個包含數據卷的鏡像
與在docker run命令中創建的數據卷不同:在dockerfile中創建的數據卷是不能映射到已經存在的本地文件的目錄中的;在鏡像構建時指定的數據卷,會在容器啓動時創建指定名字的數據卷,並且運行同樣鏡像的不同容器所創建的數據卷也是不一樣的;
-
vi Dockerfile
:使用vi文本編輯器進入Dockerfile文件中添加volume指令; -
volume["/data","/data2", ...]
:使用Dockerfile構建一個包含數據卷的鏡像,並通過使用這個鏡像來創建包含數據卷的容器; -
docker build -t imagesName .
:構建鏡像; -
docker run --name containerName1 -it imagesName
:運行一個容器containerName1 ;在容器中添加了數據卷的指令之後,容器啓動時就可以不再使用-v得參數了; -
ls
:run命令後直接進入到容器目錄下;查看容器的文件系統,可以看到,新創建的容器中已經掛載了在鏡像中指定的兩個目錄; -
exit、docker inspect containerName
:查看剛剛創建的容器,可以看到在volumes裏包含了兩個數據卷,而這兩個數據卷指定的本地的文件路徑也是Docker自動創建的; -
docker run --name containerName2 -it imagesName
:若這時以同樣的鏡像再創建一個容器containerName2,再使用inspect命令查看新容器的數據卷地址,可以看到容器containerName2的數據卷地址與containerName1 的兩個數據卷的地址是不一樣的; -
也就是說,在容器啓動時,我們在鏡像中指定的數據卷都會進行一次完整的初始化,那麼,根據鏡像指定數據卷 來創建的容器所使用的數據卷就無法共享,那麼,當我們不能訪問到本地目錄時,怎麼樣在容器之間共享數據呢?通過數據卷容器;
>> 數據卷容器
如果用戶需要在容器之間共享一些持續更新的數據,最簡單的方式是使用數據卷容器,數據卷容器其實是一個普通的容器,專門用來提供數據卷供其它容器掛載;
- 數據卷容器,與容器的數據卷的不同:
- 數據卷容器掛載了一個本地文件系統的目錄,其它容器通過掛載這個數據卷容器來實現容器間的數據的共享;
>> 掛載數據卷容器的方法
-
創建一個數據卷容器dbdata,並在其中創建一個數據卷掛載到/dbdata:
docker run -it -v /home/zxj/Documents/test/datavolumn:/dbdata --name dbdata ubuntu:18.04
-
ls
:可以看到這個容器dbdata 的文件系統中已經包含了在鏡像中指定的數據卷dbdata; -
創建容器,使用
--volumes-from
命令來掛載dbdata容器中的數據卷,--volumes-from
選項的值就是已經掛載了數據卷的容器的容器名字:
docker run -it --volumes-from dbdata --name db1 ubuntu:18.04
docker run -it --volumes-from dbdata --name db2 ubuntu:18.04
此時容器db1和db2都掛載同一個數據捲到相同的/dbdata目錄,三個容器任何一方在該目錄下的寫入,其他容器都可以看到; -
touch /dbdata/c1
:在數據卷容器中,使用touch命令往數據卷中寫入一個文件c1; -
ls /dbdata
:查看這個文件c1已經創建成功; -
exit
,在db1容器中ls查看,可以看到在dbdata容器中創建的文件c1; -
使用數據卷容器,就能很容易的在不同容器之間共享數據;同時,並不需要使用者確切的連接到已知的Docker宿主機的文件目錄;這一點在多租戶的環境下很重要,因爲在這種情況下,並不想暴露服務器的實際目錄;
-
docker inspect --format="{{.volumes}}" db1
:使用inspect命令來查看新建容器的信息;使用inspect的format選項簡化inspect返回的信息:指定只查看volumes的數據;
可以看到 :使用數據卷容器來掛載數據卷時,在inspect信息中,並不會直接反應數據卷容器的信息,而是直接返回了數據卷容器所掛載的數據卷的目錄;db1和db2中數據卷信息是一樣的;因此可以實現容器間的數據的共享; -
docker rm [-v] dbdata
:刪除用來提供數據卷的數據卷容器;若加上-v參數,就是告訴容器在刪除時,也刪除其掛載的數據卷;但是在掛載了數據卷容器的db1、db2容器中,依然可以訪問dbdata容器中掛載的數據卷;這是因爲在Docker中,若一個數據卷還在被容器使用,那麼它就會一直存在,同時也驗證了一句話:通過數據卷容器來掛載數據卷,容器在這之間的作用,僅僅是將數據卷的掛載配置傳遞到掛載了數據卷容器的新容器中; -
docker restart db2
:重啓容器2; -
docker attach db2
:使用attach命令來附加到容器上; -
ls
:看到db2中,數據卷的目錄名還存在; -
touch dbdata/c3
:在db2中的dbdata中創建一個新文件c3; -
ls dbdata
:可以看到c1、c2、c3都存在;即使已經刪除了數據卷容器,掛載了這個數據卷容器的容器仍然可以訪問數據卷容器掛載的目錄; 也就是說:通過數據卷容器來掛載數據卷,容器在這之間的作用,僅僅是一個數據卷配置信息的傳遞;
>> Docker 數據卷的備份和還原
docker run --name newContainerName
--volumes-from [containerName]
-v $(pwd):/backup:wr
ubantu
tar cvf /backup/backup.tar [container data volume]
-
--volumes-from [containerName]
:這個命令來指定需要備份的容器的名字;(數據卷容器的名字) -
-v $(pwd):/backup:權限
:使用-v命令來指定希望備份文件存放的位置;本地存放目錄:容器存放目錄:讀寫權限;(默認權限是讀寫) -
tar cvf /backup/backup.tar [container data volume]
:tar表示執行備份的操作是:壓縮文件的命令; /backup/backup.tar是文件存放的地址, [container data volume]指定需要備份的目錄; -
tar cvf 壓縮;tar xvf解壓縮;
在這個命令中包含了兩掛載方式:
- 使用
--volumes-from
指令掛載了我們需要備份數據的容器名,–volumes-from實際上是將當前創建的容器指向參數中容器的掛載目錄; -v
參數指定了我們要保存數據的路徑,也可以是當前本機的一個路徑;tar
:在容器運行過程中執行的是一個壓縮文件tar命令,它將要備份的容器中的目錄壓縮到指定的目錄下;
上面的命令就是Docker容器中“執行備份命令容器”所執行的操作:它將需要備份的數據容器與備份數據存放目錄同時掛載在“執行備份命令的容器”上,而需要備份數據的“數據容器”它的數據實際上也是存放在掛載在本機的目錄上的數據卷;數據卷容器實際上就是將本地的一個數據卷掛載到引用到數據卷容器的容器中;
實際關係是這樣的:虛線的部分是實際上是通過前面命令中的–volumes-from指令實現的真實的掛載情況;
最後的結果是:“執行備份命令容器”既掛載了一個需要備份的數據卷,同時也掛載了一個備份數據存放的數據卷,那麼在這個容器中,無論是執行copy操作,還是壓縮操作,都能實現數據的轉移;
-
docker restart db2
:重啓container2容器; -
docker attach db2
:附加到container2容器上; -
ls
:查看db2的目錄; -
ls dbdata
:數據卷中包含之前創建的c123三個文件;
現在要備份這個目錄:
-
exit
:退出容器db2; -
docker run --name db3 --volumes-from db2 -v ~/backup:/backup:wr tar cvf /backup/db3.tar /dbdata
:啓動一個新的容器,用來執行備份命令; 取個名字是db3; 使用–vloumes-from這個命令來指定需要備份的容器的名字db2; 使用-v命令來指定希望備份文件存放的位置,這裏存放在本地的backup目錄下,在容器中指定目錄也是backup,文件的權限是讀寫; 執行備份的操作是:壓縮文件的命令,/backup/db3.tar是文件存放的地址, /dbdata指定需要備份的目錄; -
ls backup
:訪問本地的backup目錄可以訪問到壓縮文件:db2的壓縮包;
到這裏就已經將包含數據卷的容器中的數據,通過一個容器,執行一個壓縮命令tar cvf
,從而經數據備份出來;
使用同樣的技術,通過解壓縮命令tar xvf
來實現備份數據的還原;