docker系列(四):資料卷

奧辰發表於2019-06-20

1 引言

容器就相當於一個簡易的作業系統,我們在上面部署我們的環境,不可避免地產生一些資料,但是,可能由於斷電等等原因,容器退出了,那麼之前容器中的資料就不符存在,則往往不是我們想要的,更多的,我們是希望資料能夠持久儲存到硬碟中,這就需要用到資料卷。

資料卷是指一種目錄或者說檔案,其存在於一個或者多個容器中,由docker掛載到容器,但不屬於UFS(Union File System,聯合檔案系統),因此能夠繞開UFS提供一些用於持續儲存或共享資料的特性。

資料卷的設計目的就是為了實現資料的持久化,完全獨立於容器的生存週期,因此docker不會在容器刪除時刪除其掛載的資料卷。除此以外,資料卷還可以實現容器間的資料繼承和共享。在使用上,資料卷的特點:

 

  • 資料卷可以在容器之間共享或者重用資料
  • 資料卷中的更改可以直接生效
  • 資料卷中的更改不會包含在映象的更新中
  • 資料卷的生命週期一直持續到沒有容器使用它為止

 

下面就開始來研究一下新增資料卷。新增資料卷有兩種方法,第一種是通過命令直接新增,第二種是通過dockerfile新增。

2 資料卷

2.1 通過命令新增資料卷

在上一篇博文中,提到過docker run命令,docker run命令中有一個引數-v就是用來新增資料卷的,也就是說,在docker run命令中使用-v引數,可以在啟動容器時,為容器新增一個資料卷。命令格式如下:

docker run -it -v /宿主機絕對路徑目錄:/容器內絕對 映象名

主義,命令中使用的路徑最好使用絕對路徑,否則可能會報錯。另外,有的時候,可能會省略宿主機路徑,只寫容器內的資料卷路徑,這時候,docker會在/var/lib/docker/volumes/目錄下自行建立一個目錄最為主機資料卷目錄。

例如將宿主機的當前使用者目錄下名為suzu的目錄,與容器內根目錄下名為rongqi的目錄進行對映作為資料卷。

$ docker run -it -v ~/suzhu:/rongqi ubuntu

root@fd4af8e0b8b3:/#

啟動容器後,我們檢視一下容器內是否有容器這一目錄:

root@fd4af8e0b8b3:/# ll rongqi
total 8
drwxr-xr-x 2 root root 4096 Jun 15 02:36 ./
drwxr-xr-x 1 root root 4096 Jun 15 02:36 ../
發現存在rongqi目錄。繼續,我們在容器內建立一個名為123的檔案,看看宿主機內是否會同步這一檔案:
root@fd4af8e0b8b3:/# cd rongqi
root@fd4af8e0b8b3:/rongqi# touch 123
root@fd4af8e0b8b3:/rongqi# ll
total 8
drwxr-xr-x 2 root root 4096 Jun 15 02:40 ./
drwxr-xr-x 1 root root 4096 Jun 15 02:40 ../
-rw-r--r-- 1 root root 0 Jun 15 02:40 123
在宿主機啟動另一個終端,檢視是否同步:
$ cd ~/suzhu
~/suzhu$ ll
total 8
drwxr-xr-x 2 root root 4096 Jun 15 10:40 ./
drwxr-xr-x 16 chb chb 4096 Jun 15 10:41 ../
-rw-r--r-- 1 root root 0 Jun 15 10:40 123

看到了沒,宿主機rongqi目錄中也同步出現了123檔案。而且,無論是宿主機的容器目錄還是容器內的rongqi目錄都是由docker自動建立的。

再次,我們嘗試在宿主機中修改123檔案的內容,看容器內的123檔案是否會修改,注意一定要使用超級管理員許可權進行寫入才行,這時候主機只有只讀許可權。如下圖所示:

儲存後退出,再次回到容器內檢視123檔案內容:

root@fd4af8e0b8b3:/rongqi# tac 123
我是宿主機,我寫入了一行

證明宿主機與容器的同步是雙向的。

如果容器停止了,宿主機新增檔案,是否會在容器重新啟動後同步到呢?

我們先停止容器,然後在宿主機suzhu目錄下建立一個111.txt檔案:

root@fd4af8e0b8b3:/rongqi# exit
exit
$ cd ~/suzhu
$ touch 111.txt
$ sudo touch 111.txt

啟動剛剛的容器,看看是否出現111.txt檔案:

$ docker start fd4af8e0b8b3
fd4af8e0b8b3
$ docker attach fd4af8e0b8b3
root@fd4af8e0b8b3:/# cd rongqi
root@fd4af8e0b8b3:/rongqi# ll
total 12
drwxr-xr-x 2 root root 4096 Jun 15 03:07 ./
drwxr-xr-x 1 root root 4096 Jun 15 02:40 ../
-rw-r--r-- 1 root root 0 Jun 15 03:07 111.txt
-rw-r--r-- 1 root root 37 Jun 15 02:55 123

看到了嗎?在容器重啟後,在rongqi目錄下也出現了111.txt檔案。

一個容器可以有多個資料卷嗎?

答案是可以的。需要指定多個-v引數來實現。

$ docker run -it -v ~/suzhu:/rongqi -v ~/suzhu2:/rongqi2 ubuntu

繼續研究,一個目錄可以掛載多個資料卷嗎?

$ docker run -it -v ~/suzhu:/rongqi ubuntu
root@deb66cd44a57:/#

容器建立成功。我們繼續嘗試使用新建的容器,看看容器間的資料卷內檔案是否會同步:

root@deb66cd44a57:/# cd rongqi
root@deb66cd44a57:/rongqi# ll
total 12
drwxr-xr-x 2 root root 4096 Jun 15 03:07 ./
drwxr-xr-x 1 root root 4096 Jun 15 03:40 ../
-rw-r--r-- 1 root root 0 Jun 15 03:07 111.txt
-rw-r--r-- 1 root root 37 Jun 15 02:55 123
root@deb66cd44a57:/rongqi# touch 222.txt

去最初建立的容器中檢視:

$ docker attach fd4af8e0b8b3
root@fd4af8e0b8b3:/rongqi# ll
total 12
drwxr-xr-x 2 root root 4096 Jun 15 03:43 ./
drwxr-xr-x 1 root root 4096 Jun 15 02:40 ../
-rw-r--r-- 1 root root 0 Jun 15 03:07 111.txt
-rw-r--r-- 1 root root 37 Jun 15 02:55 123
-rw-r--r-- 1 root root 0 Jun 15 03:43 222.txt

檔案同步了。證明一個目錄可以被多個容器掛在為資料卷,從而實現容器間的資料同步和共享。

既然一個目錄可以被多個容器掛在為資料卷,就需要涉及許可權的問題了,例如有的容器需要有讀和寫的許可權,但是,有的容器,只需要有讀不能由寫入許可權,這該怎麼辦呢?其實只需要掛在目錄後面加入許可權引數就好了,引數中,rw表示有讀和寫許可權,ro表示只有du的許可權,在預設情況下,是rw就同時具有讀寫許可權。我們繼續建立一個容器,對suzhu目錄只有只讀許可權,然後嘗試在容器中建立檔案:

$ docker run -it -v ~/suzhu:/rongqi:ro ubuntu
root@6df9eaeb444a:/# cd rongqi
root@6df9eaeb444a:/rongqi# touch 333.txt
touch: cannot touch '333.txt': Read-only file system
建立檔案失敗,因為只有只讀的許可權。
總結一下在docker run命令中新增資料卷的內容:
  • 在docker run命令中新增-v 宿主機目錄:容器目錄引數形式進行新增資料卷
  • 如果目錄不存在,docker會自動建立
  • 同步是雙向的
  • 如果不對許可權進行制定,宿主機只有只讀許可權
  • 容器重啟並不影響同步
  • 通過多個-v引數,一個容器掛載多個資料卷
  • 一個目錄可以被多個容器掛載,從而實現容器間的資料共享同步。
  • 通過rw和ro引數,可以指定容器對資料卷的讀寫許可權。
  • 指定資料卷目錄時,最好使用絕對路徑,不要使用相對路徑(上面並沒有演示)

2.2 通過dockerfile新增資料卷

dockerfile內容在前面的博文中已經介紹過了。在dockerfile中有一個專門的命令VOLUME是用來新增資料卷的,VOLUME命令格式如下:

VOLUME ["資料卷目錄1", "資料卷目錄2"]

注意:資料卷目錄1和2都指的是容器內的目錄。在docker run中通過-v引數指定宿主機目錄:容器目錄的方式在dockerfile中是行不通的。這是因為dockerfile是以建立容器的模板作用而存在,可能會應用於不同的宿主機甚至不同的系統平臺,不同的平臺路徑格式也不相同。雖然不能指定宿主機中的目錄,不過,通過dockerfile建立愛你的資料卷都預設存在於/var/lib/docker/volumes/目錄下。下面我們使用dockerfile建立資料卷,首先建立一個目錄,然後進入該目錄,在目錄內建立一個名為dockerfile的檔案,寫入一下內容:

FROM ubuntu
VOLUME ["/dataVolume1","/dataVolume2"]
CMD echo "Success to build volume"
CMD /bin/bash

在命令列下使用docker build命令建立映象:

$ docker build -t docker_volume .
Sending build context to Docker daemon 2.048kB
Step 1/4 : FROM ubuntu
---> 7698f282e524
Step 2/4 : VOLUME ["/dataVolume1","/dataVolume2"]
---> Running in 42cee5bb0fc8
Removing intermediate container 42cee5bb0fc8
---> 96e9ce4e0eae
Step 3/4 : CMD echo "Success to build volume"
---> Running in 04fbe86e45cc
Removing intermediate container 04fbe86e45cc
---> f66a3493edc6
Step 4/4 : CMD /bin/bash
---> Running in 6f39c6dbb2d8
Removing intermediate container 6f39c6dbb2d8
---> 42bd7a7b12ff
Successfully built 42bd7a7b12ff
Successfully tagged docker_volume:latest

使用映象建立容器,然後進入容器檢視是否有資料卷:

$ docker run -it 42bd7a7b12ff
root@266fdc2a5ad7:/# ll
total 80
drwxr-xr-x 1 root root 4096 Jun 17 13:26 ./
drwxr-xr-x 1 root root 4096 Jun 17 13:26 ../
-rwxr-xr-x 1 root root 0 Jun 17 13:26 .dockerenv*
drwxr-xr-x 2 root root 4096 May 15 14:07 bin/
drwxr-xr-x 2 root root 4096 Apr 24 2018 boot/
drwxr-xr-x 2 root root 4096 Jun 17 13:26 dataVolume1/
drwxr-xr-x 2 root root 4096 Jun 17 13:26 dataVolume2/

可以看到,dataVolume1和dataVolume2兩個目錄果然是存在的。

我們可以使用docker inspect命令檢視詳細資訊:

$ docker inspect 266fdc2a5ad7
……
"Mounts": [
{
"Type": "volume",
"Name": "d2d2f7ee61c5f8db0b8ccc2ff08f121079c3f16c5e48cd99e1d65538ef44e389",
"Source": "/var/lib/docker/volumes/d2d2f7ee61c5f8db0b8ccc2ff08f121079c3f16c5e48cd99e1d65538ef44e389/_data",
"Destination": "/dataVolume1",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "eacb8887be7cee176c1901f0e61ab7d51998a11366cc5a4b5fd3313c79f6ba48",
"Source": "/var/lib/docker/volumes/eacb8887be7cee176c1901f0e61ab7d51998a11366cc5a4b5fd3313c79f6ba48/_data",
"Destination": "/dataVolume2",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
……

查詢出來的資訊太多,上面只貼出了資料卷的掛載資訊,Name是指資料卷的名稱,是自動生成的,Source是宿主機內的資料卷目錄,使用超級管理員許可權開啟/var/lib/docker/volumes/目錄可以檢視到,Destination是容器內的資料卷目錄。

dockerfile建立的資料卷性質與docker run -v命令列建立的是一樣的,這裡不再多說。

3 資料卷容器

有時候,我們有一些經常性發生變化的資料需要在多個容器之間進行共享,這時候,一個更好的選擇就是使用資料卷容器。所謂資料卷容器,從名字上也可以看出也是一個容器,不過,這個容器是專門用來為其他容器提供資料捲進行掛在的。

我們先建立一個帶資料卷的容器:

$ docker run -it -v /dbdata --name dbContainer ubuntu

然後用這個容器為其他容器提供資料卷。使用--volumes-from來掛載資料卷容器。如下所示:

~/docker_test$ docker run -it --volumes-from dbContainer --name c1 ubuntu
root@50ce83189ae3:/# ll
total 76
……
drwxr-xr-x 2 root root 4096 Jun 17 14:57 dbdata/
……

可以看到,容器內出現了dbdata目錄,這就是通過--volumes-from引數與dbContainer容器掛載而來的。

資料卷容器可以同時被多個容器掛載,甚至,已經掛載了資料卷的容器可以級聯掛載別的容器。

$ docker run -it --volumes-from c1 --name c2 ubuntu
root@97e7dae4a04b:/# ll
total 76
……
drwxr-xr-x 2 root root 4096 Jun 17 14:57 dbdata/
……

可見,dbContainer、c1、c2逐級掛載,這是沒有問題的,而且,--volumes-from引數所掛載的資料卷的容器並不需要保持執行狀態,也即是說dbContainer、c1、c2任意一個容器退出也不會影響其他兩個容器。

另外,刪除掛載的容器(dbContainer、c1、c2任意一個),資料卷並不會被自動刪除,如果要刪除資料卷,需要在刪除最後一個掛載著這個資料卷的時候顯式的使用docker rm -v引數來同時刪除容器。

 
 
 
 
 

相關文章