Docker(十五)-Docker的數據管理(volume/bind mount/tmpfs)


Docker提供了三種不同的方式用於將宿主的數據掛載到容器中:volumes,bind mounts,tmpfs volumes。當你不知道該選擇哪種方式時,記住,volumes總是正確的選擇。

volumes是Docker數據持久化機制。bind mounts依賴主機目錄結構,volumes完全由Docker管理。Volumes有以下優點:
  • Volumes更容易備份和移植。
  • 可以通過Docker CLI或API進行管理
  • Volumes可以無區別的工作中Windows和Linux下。
  • 多個容器共享Volumes更安全。
  • Volume驅動可以允許你把數據存儲到遠程主機或者雲端,並且加密數據內容,以及添加額外功能。
  • 一個新的數據內容可以由容器預填充。
而且,volumes不會增加容器的大小,生命周期獨立與容器。
 

 
如果你的容器產生不需要持久化數據,請使用tmpfs mount方式,可以避免容器的寫入層數據寫入。

 

雖然我們可以在docker容器中保存寫入的數據,但還是有這樣幾個不足:

  1. 容器中的數據會隨着容器的停止運行而消失, 而且當其他的進程需要這些數據時,很難將這些數據從容器中提取出來;
  2. 容器的數據寫入層是緊密地對應着他的宿主操作系統的,數據不能容易的被遷移到其他地方;
  3. 要將數據寫入到容器的數據寫入層,需要一個特定的存儲驅動,利用linux內核構建一個統一的文件系統,來管理宿主和容器的文件系統。這層額外的虛擬化顯然會降低性能。為了避免性能下降,docker使用data volumes的方式,直接對宿主文件系統進行寫操作。

選擇正確的掛載類型

無論選擇哪種掛載方式,在容器內部看來,數據就是數據,並沒有什么不同。主機的數據在容器的文件系統中總被顯示為目錄或文件。如何簡單的理解這三種掛載方式的不同之處呢,我們可以理解為在這三種方式下,容器內的數據在宿主機中存放的位置不同,見下圖:
 
  1. Volumes方式下:容器內的數據被存放到宿主機(linux)一個特定的目錄下(/var/lib/docker/volumes/)。這個目錄只有Docker可以管理,其他進程不能修改。如果想持久保存容器的應用數據,Volumes是Docker推薦的掛載方式。
  2. Bind mounts方式下:容器內的數據被存放到宿主機文件系統的任意位置,甚至存放到一些重要的系統目錄或文件中。除了Docker之外的進程也可以任意對他們進行修改;
  3. tmpfs方式下:容器的數據只會存放到宿主機的內存中,不會被寫到宿主機的文件系統中,因此不能持久保存容器的應用數據。

詳細介紹三種掛載方式

Volumes: 
  • 由Docker進程創建和管理。可以通過命令docker volume create來創建一個指定的卷,也可以由Docker進程在創建容器或服務的過程中來創建;
  • 當你為一個容器創建一個volume時,這個volume將會被存儲到宿主機的一個目錄下。當你掛載這個volume到一個容器中時,就是在掛載這個目錄到容器中。這和bind mount的工作機制很相似,當然,除了volume是被Docker所管理並與宿主機其他核心功能隔離之外。
  • 一個volume可以被同時掛載到多個容器中。當沒有任何容器在使用這個volume的時候,這個volume也仍然可以被Docker進程所使用,而不是自動被刪除。當然,你可以使用命令手動刪除volume:docker volume prune
  • 當你掛載一個volume時,可以選擇為他命名(named),也可以不命名(anonymous). 如果不命名的話,當這個volume首次被掛載到一個容器中時,Docker進程會分配給它一個隨機的名字,以保證在宿主機操作系統中這個volume的名字唯一。除了名字之外,命名和不命名的volume沒有區別。
  • Volume也支持使用volume drivers,以幫助你將數據保存到遠程主機或雲上。
Bind mounts:
  • 在docker的早期版本中就存在的功能,與volumes相比,他的功能比較局限。當使用bind mounts時,宿主機的目錄或文件被掛載到容器中。容器將按照掛載目錄或文件的絕對路徑來使用或修改宿主機的中的數據。宿主機中的目錄或文件不需要預先存在,在需要的時候會自動創建。使用Bind mounts在性能上是非常好的,但這依賴於宿主機有一個目錄妥善結構化的文件系統。如果你要創建一個新的Docker應用,我們仍推薦使用named volume的方式,因為你無法通過Docker CLI來管理bind mounts。(警告:bind mounts是一把雙刃劍,因為使用bind mounts的容器可以在通過容器內部的進程對主機文件系統進行修改,包括創建,修改和刪除重要的系統文件和目錄,這個功能雖然很強大,但顯然也會造成安全方面的影響,包括影響到宿主機上Docker以外的進程)
tmpfs mounts:
  • 在這種掛載方式下,容器內的應用數據將不會被持久的保存到硬盤上,其中的數據只能在某個容器的生存周期內被使用,或者用於保存一些不需要持久存儲,或一些敏感的數據信息。比如,在docker內部,swarm服務使用tmpfs方式來將secrets掛載到服務的容器中。(關於secrets,參考https://docs.docker.com/engine/swarm/secrets/)
Bind mounts和volumes都可以通過使用標志-v或--volume來掛載到容器中,只是格式有些許不同。tmpfs可以使用標志--tmpfs進行掛載。然而,在Docker17.06及其以上版本中,我們推薦使用--mount來對容器或服務進行這三種方式的掛載,因為這種格式更加清晰。

Volume的適用場景

  • 多個容器間需要共享數據。如果volume沒有手動被創建,它將會在首次掛載到某個容器之前被自動創建,當容器被停止或刪除時,這個volume不會隨之被刪除。多個容器可以同時以rw或ro的方式掛載這個volume。只有手動指定刪除volume,它才會被刪除。
  • 當宿主機並沒有專用於Docker的文件系統結構時。使用volume可以使宿主機的配置與容器的運行解耦。
  • 當你希望將數據保存到遠程主機或雲上。
  • 當你希望在不同的宿主機直接備份/恢復/遷移數據時,volume是一個很好的選擇。你可以停止運行使用volume的容器,然后直接備份volume所在的目錄即可,如/var/lib/docker/volumes/<volume-name>

bind mounts的適用場景

  • 將宿主機的系統配置文件共享給容器,這是Docker為容器提供DNS配置的默認方式,即通過bind mounts的方式將宿主的的/etc/resolv.conf文件掛載到容器中。
  • 將宿主機開發環境中的源代碼或實驗結果共享給容器。例如:你在宿主機上進行一個項目Maven的測試,每次你在宿主機上對Maven項目進行了更改后,容器就可以直接獲取更改后的結果
  • 當你可以確定宿主機的文件系統結構應該與容器內部完全一致時。

tmpfs的適用場景

  • 當你出於安全原因,或者容器性能優化的原因(如需要寫入大量的不持久的狀態數據時),不需要容器的數據長久保存時可以使用這種方式。

使用bind mounts和volumes的小Tips

  • 如果你使用volumes的方式掛載了一個空的volume到某個容器的一個非空目錄中,則這個非空目錄中已存在的內容會被拷貝到這個volume中。類似的,如果在啟動容器時指定了一個不存在的volume,一個空的volume會被自動創建;
  • 如果使用bind mounts的方式掛載,或者用volumes的方式掛載了一個非空的volume到容器的一個非空目錄中,則容器中這個非空目錄下的內容將暫時被掛載過來的volume中的內容所覆蓋(並未被刪除),當取消掛載后,容器中那個非空目錄中的文件仍然存在。就像在linux下的/mnt目錄下如果存在一些文件,在把USB掛載到/mnt時,在/mnt下就只能看到USB中的內容而看不見原先的文件,當取消USB掛載后,再進入/mnt就可以看見原先的文件了。

選擇使用 -v還是--mount

 
起初,-v或者--volume用於獨立容器,--mount用於swarm services。然而,從Docker 17.06開始,也可是使用--mount用於獨立容器。—mount命令更精准詳細。-v將選項進行了合並。使用--mount。
 
如果你需要制定volume驅動選項,你必須使用 --mount。
  • -v或者--volume:由3部分參數組成,使用“:”間隔。順序不能顛倒。
    • 第一個部分是volumes名字,在宿主機上具有唯一性。匿名卷名字系統給出。
    • 第二部分是掛載到容器里的文件或文件夾路徑。
    • 第三部分是可選項列表分隔符,例如“or”,這些可選項在下面會討論。
  •     —mount:由多個鍵值對組成,<key>=<value>。—mount要比-v或者--volume命令更長,但是更容易理解。
    • type,可以是bind,volume或者tmpfs。這篇文章主要討論volumes,所以type一直使用volume.
    • source,volumes的名字,匿名volume可以省略。source可縮寫為src.
    • destination,掛載到容器中的文件或目錄路徑。可也縮寫為dst或者使用target。
    • readonly,指定掛載在容器中為只讀。
    • volume-opt,可選屬性,可以多次使用。

-v和--mount的不同行為

與bind mounts不同,對於—mount和-v所有的選項都可以使用。
當使用volumes服務時,只支持--mount.
 

創建和管理volumes

不像bind mount,你可以在容器外創建和管理volumes。
 
創建一個volume:
$ docker volume create my-vol
 
顯示所有volumes
$ docker volume ls
local               my-vol
 
查看volumes
$ docker volume inspect my-vol
[
{
"Driver": "local",
        "Labels": {},
        "Mountpoint": "/var/lib/docker/volumes/my-vol/_data",
        "Name": "my-vol",
        "Options": {},
        "Scope": "local"
}
]
 
刪除一個volume:
$ docker volume rm my-vol
 
啟動一個帶volume的容器
如果你啟動一個帶有volume容器,volume還沒有創建,Docker會為你創建。下面的例子掛載myvol2到容器中的/app/下。
下面的例子-v和—mount結果是一樣的。
 
--mount:
$ docker run -d \
--name devtest \
--mount source=myvol2,target=/app \
  nginx:latest
 
-v:
$ docker run -d \
--name devtest \
-v myvol2:/app \
  nginx:latest
使用inspect查看掛載是否正確,查看Mounts部分:
"Mounts": [
{
"Type": "volume",
"Name": "myvol2",
"Source": "/var/lib/docker/volumes/myvol2/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
可以看出掛載正確,並且是可讀寫的。
 
停止容器然后刪除volume
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm myvol2
啟動一個帶有volumes服務
當你啟動服務定義一個volume,每個服務可以使用自己本地人volume.如果你使用local volume,容器不能分享數據,但是一些volume驅動支持分享存儲。Docker for AWS and Docker for Azure使用Cloudstor插件都支持持久化存儲。
下面的例子啟動4份nginx服務,每個使用一個本地存儲myvol2。
$ docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
  nginx:latest
 
使用docker service ps devtest-service 查看服務是否運行:
$ docker service ps devtest-service
ID                  NAME                IMAGE               NODE                DESIRED STATE       CURRENT STATE            ERROR               PORTS
4d7oz1j85wwn        devtest-service.1   nginx:latest        moby                Running             Running 14 seconds ago  
刪除服務
$ docker service rm devtest-service
 
服務標識的不同
docker service create 命令不支持-v或者—volume。必須使用—mount。
使用容器加載一個volume
 
和上面一樣,如果你啟動一個容器創建一個新的volume,在容器被掛載的目錄(/app/)中有文件或者文件夾,這個目錄中的內容會被拷貝到volume中。然后容器掛載使用volume,其他容器使用這個volume也可以訪問預加載內容。
為了說明這個,這個例子啟動一個nginx容器並且加載一個新volume nginx-vol,里面包括容器中/usr/share/nginx/html 目錄中的內容,里面存儲的是nginx默認的HTML內容。
--mount and -v具有相同結果
--mount:
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
  nginx:latest
 
-v
$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
  nginx:latest
 
以下是運行后清理命令
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
使用只讀volume
 
對於一些開發應用,容器需要回寫數據到Docker主機。但有時容器只需要讀數據。請記住多個容器可以掛載相同volume,一個掛載讀寫容器,也可以掛載只讀容器,還可以兩種同時掛載。
這個例子修改上面的例子,但是掛載的是只讀容器,使用’or’分隔符處理選項列表,
--mount and -v具有相同結果
--mount
$ docker run -d \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
  nginx:latest
 
-v
$ docker run -d \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html:ro \
  nginx:latest
 
使用 docker inspect nginxtest 命令查看是否掛載正確,查看Mounts部分
"Mounts": [
{
"Type": "volume",
"Name": "nginx-vol",
"Source": "/var/lib/docker/volumes/nginx-vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "",
"RW": false,
"Propagation": ""
}
],
 
清理命令
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
 
機器間共享數據
當構建高可用應用程序,你需要配置多個相同的服務訪問相同文件。
 

 

有幾種方法可以達到這種效果。一種是在你的應用中添加對雲存儲文件的訪問,如Amazon S3。另一種是使用支持外服存儲驅動(NFS, Amazon S3)的volume。
Volume驅動允許你在應用中抽象下層的存儲系統。例如,如果你的服務使用NFS驅動volume,你可以使用不同的驅動更新服務,就像存儲在雲中的數據,不需要修改應用邏輯。
使用volume驅動
當你使用docker volume create創建一個volume,或者當你啟動一個帶有沒創建volume的容器,你可以指定volume驅動。下面例子使用vieux/sshfs volume驅動 ,首先創建一個獨立的volume,然后啟動一個創建新volume的容器。
 
初始化設置
這個例子假設你有兩個節點,第一個是Docker主機而且可以連接到第二個的ssh.
在Docker主機中安裝vieux/sshfs插件:
$ docker plugin install --grant-all-permissions vieux/sshfs
 
使用volume驅動創建volume
這個樣例指定一個SSH密碼,但是如果兩個主機共享keys配置,你可以省略密碼。每個volume驅動可以沒有或者更多配置選項,可以使用-o標識。
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
  sshvolume
 
test@node2:/home/test 為遠程主機掛載點
 
啟動一個帶有使用volume驅動創建volume的容器
這個樣例指定一個SSH密碼,但是如果兩個主機共享keys配置,你可以省略密碼。每個volume驅動可以沒有或者更多配置選項。如果volume驅動要穿可選參數,你必須使用—mount。
$ docker run -d \
--name sshfs-container \
--volume-driver vieux/sshfs \
--mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \
  nginx:latest


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM