轉載/參考:
https://www.jianshu.com/p/ef0f24fd0674
Docker的數據持久化主要有兩種方式:
- bind mount
- docker managed volume
Docker的數據持久化即數據不隨着container的結束而結束,數據存在於host機器上——要么存在於host的某個指定目錄中(使用bind mount),要么使用docker自己管理的volume(/var/lib/docker/volumes下)。
1.bind mount
bind mount自docker早期便開始為人們使用了,用於將host機器的目錄mount到container中。但是bind mount在不同的宿主機系統時不可移植的,比如Windows和Linux的目錄結構是不一樣的,bind mount所指向的host目錄也不能一樣。這也是為什么bind mount不能出現在Dockerfile中的原因,因為這樣Dockerfile就不可移植了。
將host機器上當前目錄下的host-data目錄mount到container中的/container-data目錄:
docker run -it -v /home/host-dava:/container-data alpine sh
有幾點需要注意:
- host機器的目錄路徑必須為全路徑(准確的說需要以
/
或~/
開始的路徑),不然docker會將其當做volume而不是bind mount處理 - 如果host機器上的目錄不存在,docker會自動創建該目錄
- 如果container中的目錄不存在,docker會自動創建該目錄
- 如果container中的目錄已經有內容,那么docker會使用host上的目錄將其覆蓋掉
2.docker managed volume
2.1在docker run使用
volume也是繞過container的文件系統,直接將數據寫到host機器上,只是volume是被docker管理的,docker下所有的volume都在host機器上的指定目錄下/var/lib/docker/volumes。
將my-volume掛載到container中的/mydata目錄:
docker run -it -v my-volume:/mydata alpine sh
然后可以查看到給my-volume的volume:
docker volume inspect my-volume [ { "CreatedAt": "2018-03-28T14:52:49Z", "Driver": "local", "Labels": null, "Mountpoint": "/var/lib/docker/volumes/my-volume/_data", "Name": "my-volume", "Options": {}, "Scope": "local" } ]
可以看到,volume在host機器的目錄為/var/lib/docker/volumes/my-volume/_data
。此時,如果my-volume不存在,那么docker會自動創建my-volume,然后再掛載。
也可以不指定host上的volume:
docker run -it -v /mydata alpine sh
此時docker將自動創建一個匿名的volume,並將其掛載到container中的/mydata目錄。匿名volume在host機器上的目錄路徑類似於:/var/lib/docker/volumes/300c2264cd0acfe862507eedf156eb61c197720f69e7e9a053c87c2182b2e7d8/_data
。
除了讓docker幫我們自動創建volume,我們也可以自行創建:
docker volume create my-volume-2
查看所有volume
docker volume ls
然后將這個已有的my-volume-2掛載到container中:
docker run -it -v my-volume-2:/mydata alpine sh
需要注意的是,與bind mount不同的是,如果volume是空的而container中的目錄有內容,那么docker會將container目錄中的內容拷貝到volume中,但是如果volume中已經有內容,則會將container中的目錄覆蓋。
2.2.Dockerfile中的VOLUME
在Dockerfile中,我們也可以使用VOLUME指令來申明contaienr中的某個目錄需要映射到某個volume:
#Dockerfile
VOLUME /foo
這表示,在docker運行時,docker會創建一個匿名的volume,並將此volume綁定到container的/foo目錄中,如果container的/foo目錄下已經有內容,則會將內容拷貝的volume中。也即,Dockerfile中的VOLUME /foo
與docker run -v /foo alpine
的效果一樣。
Dockerfile中的VOLUME使每次運行一個新的container時,都會為其自動創建一個匿名的volume,如果需要在不同container之間共享數據,那么我們依然需要通過docker run -it -v my-volume:/foo
的方式將/foo中數據存放於指定的my-volume中。
3.對比
相同點:兩者都是 host 文件系統中的某個路徑。
不同點:
bind mount | docker managed volume | |
---|---|---|
volume 位置 | 可任意指定 | /var/lib/docker/volumes/... |
對已有mount point 影響 | 隱藏並替換為 volume | 原有數據復制到 volume |
是否支持單個文件 | 支持 | 不支持,只能是目錄 |
權限控制 | 可設置為只讀,默認為讀寫權限 | 無控制,均為讀寫權限 |
移植性 | 移植性弱,與 host path 綁定 | 移植性強,無需指定 host 目錄 |
4.數據容器
如果用戶需要在多個容器之間共享一些持續更新的數據,最簡單的方式是使用數據卷容器。數據卷容器也是一個容器,但是它的目的是專門用來提供數據卷供其他容器掛載。通常會在容器中創建一個或多個卷,其他的容器就可以通過--volumes-from選項來訪問它們。
運行一個名為storage的數據容器,它包含一個卷並在后台運行:
docker run -d -v /data --name storage ubuntu
接下來我們運行另一個容器:
docker run -it --name
storage2 --volumes-from storage ubuntu bash