Docker數據卷-Volume
一:Volume
是什么,用來做什么的
當刪除docker容器時,容器內部的文件就會跟隨容器所銷毀,在生產環境中我們需要將數據持久化保存,就催生了將容器內部的數據保存在宿主機的需求,volume
就是被設計用于解決容器與主機之間、容器與容器之間共享文件,容器中數據的持久化,容器中的數據備份、遷移、恢復。
二:Volume
如何使用
在執行 docker run 命令的時候,使用-v參數用于指定數據卷,可以完成數據卷掛載。數據卷卷可以是命名的,也可以是匿名的。匿名卷被賦予一個隨機名稱,該名稱保證在給定的 Docker 主機內是唯一的。與命名卷一樣,即使您刪除使用它們的容器,匿名卷也會保留下來,除非您--rm
在創建容器時使用該標志,在這種情況下與容器關聯的匿名卷將被銷毀。
匿名數據卷的使用
在啟動容器的時候只指定容器內部的路徑,不寫宿主機路徑。如下:
lemon@DockerVolume:~$ docker run -d -p 8888:80 -v /usr/share/nginx/html --name nginx-volume nginx:latest
37d8c80f337d3a98d3470855fba5009625285e742acd268b42bbe3f969cd25a8
lemon@DockerVolume:~$
該命令將創建一個名稱為nginx-volume的Nginx容器,其中 -v 僅寫了容器內的路徑,并未提供卷名,使用命令 docker inspect nginx-volume | grep -A 11 “Mounts” 查看其掛載信息。
lemon@DockerVolume:~$ docker inspect nginx-volume | grep -A 11 "Mounts""Mounts": [{"Type": "volume","Name": "538688015ecc44b37c36861c07bff24f7330b06a2d8dd396d4980a9594de461d","Source": "/var/lib/docker/volumes/538688015ecc44b37c36861c07bff24f7330b06a2d8dd396d4980a9594de461d/_data","Destination": "/usr/share/nginx/html","Driver": "local","Mode": "","RW": true,"Propagation": ""}],
lemon@DockerVolume:~$
通過查詢掛載信息可知,該容器掛載了一個名稱為一段哈希串的volume類型的,其在宿主的存儲位置在:/var/lib/docker/volumes/538688015ecc44b37c36861c07bff24f7330b06a2d8dd396d4980a9594de461d/_data 目錄下,掛載的是容器內的路徑:/usr/share/nginx/html
命名數據卷的使用
在啟動容器的時候指定卷名,并綁定容器內部的路徑。如下:
lemon@DockerVolume:~$ docker run -d -p 8800:80 -v nginx_dir:/usr/share/nginx/html --name nginx-volume2 nginx:latest
2501c7eeab6484acf05dbc0de901fec2472835e1bc947af046a711352e153e0b
lemon@DockerVolume:~$
該命令將創建一個名稱為nginx-volume2的Nginx容器,其中 -v 提供了卷名和容器內的路徑映射關系,使用命令 docker inspect nginx-volume2 | grep -A 11 “Mounts” 查看其掛載信息。
lemon@DockerVolume:~$ docker inspect nginx-volume2 | grep -A 11 "Mounts""Mounts": [{"Type": "volume","Name": "nginx_dir","Source": "/var/lib/docker/volumes/nginx_dir/_data","Destination": "/usr/share/nginx/html","Driver": "local","Mode": "z","RW": true,"Propagation": ""}],
lemon@DockerVolume:~$
通過查詢掛載信息可知,該容器掛載了一個名稱為 nginx_dir
的volume類型的,其在宿主的存儲位置在:/var/lib/docker/volumes/nginx_dir/_data 目錄下,掛載的是容器內的路徑:/usr/share/nginx/html
通過這兩個示例發現不管是命名數據卷還是匿名數據卷,其存儲位置都在 /var/lib/docker/volumes/<數據卷名稱>/_data 目錄下,且掛載類型均為 volume
,那還有沒有其他的類型的數據卷掛載嗎,或者說我想指定存儲到宿主機的其他位置呢,比如,我希望將容器nginx-volume3 的目錄指定到/home/lemon/docker_nginx_data/ 目錄之下,我的/var/lib/docker目錄存儲在 / 根分區下,其存儲空間太小,希望將數據挪動到更大的目錄 /home/ 分區下。
下面我將來介紹其他的兩種類型文件綁定方式
三:docker
存儲的三種類型
如果希望將容器nginx-volume3 的目錄/usr/share/nginx/html 指定到/home/lemon/docker_nginx_data/ 目錄之下,就需要需用到如下的方式去指定掛載:
-v /home/lemon/docker_nginx_data:/usr/share/nginx/html
示例如下:
lemon@DockerVolume:~$ docker run -d -p 8801:80 -v /home/lemon/docker_nginx_data:/usr/share/nginx/html --name nginx-volume3 nginx:latest
016a57e9a5f419647b87fc603d966357644f12a71b0265f2b3d2eb12e1453877
lemon@DockerVolume:~$
使用命令 docker inspect nginx-volume3 | grep -A 11 “Mounts” 查看其掛載信息。
lemon@DockerVolume:~$ docker inspect nginx-volume3 | grep -A 11 "Mounts""Mounts": [{"Type": "bind","Source": "/home/lemon/docker_nginx_data","Destination": "/usr/share/nginx/html","Mode": "","RW": true,"Propagation": "rprivate"}],"Config": {"Hostname": "016a57e9a5f4",
lemon@DockerVolume:~$
通過查詢掛載信息可知,該容器將宿主機的/home/lemon/docker_nginx_data目錄與容器的/usr/share/nginx/html掛載了起來。與上面的兩個類型相比較,我們發現其Type
參數類型為 bind,與上面的兩種方式的 volume 類型不同。
此處我們來看一下volume與bind兩種類型優缺點:
對比項 | Volume(卷) | Bind (綁定掛載) |
---|---|---|
存儲位置 | Docker 統一管理,默認存放在 /var/lib/docker/volumes/ | 直接使用宿主機上的指定目錄 |
創建方式 | 通過 docker volume create 創建,Docker 負責管理 | 需要手動指定宿主機路徑 |
適用場景 | 推薦用于持久化存儲,如數據庫、日志等 | 適用于開發環境,可直接訪問宿主機文件 |
容器間共享 | 容易共享,多個容器可以掛載同一個 Volume | 手動管理,需要確保宿主機目錄存在 |
安全性 | 更安全,容器無法直接訪問宿主機 | 風險較高,容器可能影響宿主機數據 |
性能 | 一般更快,Docker 進行了優化 | 可能受文件系統性能影響 |
跨平臺 | 可以跨主機(NFS 等),便于遷移和備份 | 僅限本地,受宿主機文件系統影響 |
此處之外的區別,bind類型會存在空掛載的問題,比如上面的容器nginx-volume3我們在瀏覽器中訪問一下
會發現該容器無法訪問Nginx的歡迎頁,具體原由就出現在空掛載上,如果bind類型掛載的宿主機路徑為空,則會將容器內的掛載路徑變為空,該特性適用于將宿主機上的配置文件替換容器內部的配置文件,也在一定程度上適用與容器文件遷移或者文件備份,但是前提條件遷移的目標地址最好是相同的宿主機系統,例如Linux系統遷移至Linux,Windows系統遷移至Windows。跨系統遷移會在一定程度上可能導致文件不能使用。
除了bind類型以外,還有一個不太常用的tmpfs類型,用于將容器內的路徑指定到宿主機的內存上,通常用于一些高性能的文件讀寫環境下,例如將MySQL的數據庫指定到內存當中,以增加緩存刷盤速度,或者用于創建一個高速寫入的緩存路徑。
示例如下:
lemon@DockerVolume:~$ docker run -d -p 8802:80 --mount type=tmpfs,destination=/app --name nginx-volume4 nginx:latest
44354dea5bcbc588d44e795e60fc44200f7edcff20f289c7fb8a7efae2227c4e
lemon@DockerVolume:~$
lemon@DockerVolume:~$ docker inspect nginx-volume4 | grep -A 11 "Mounts""Mounts": [{"Type": "tmpfs","Target": "/app"}],"MaskedPaths": ["/proc/asound","/proc/acpi","/proc/kcore","/proc/keys","/proc/latency_stats",
--"Mounts": [{"Type": "tmpfs","Source": "","Destination": "/app","Mode": "","RW": true,"Propagation": ""}]
lemon@DockerVolume:~$
通過查詢掛載信息可以發現,tmpfs類型沒有在宿主機上指定路徑,是因為我們指定到了內存當中。
三種類型掛載的的位置
三種類型其本質是,掛載的宿主機文件系統的位置不同。
四:-v
與--mount
參數的區別
-v 只能掛載2種形式 bind,volume
–mount 可以掛載3種形式 bind,volume,tmpfs
兩者在功能上是等效的,但–mount更為靈活,適用于更復雜的掛載需求,使用哪種方式主要取決與具體的使用場景。如果你只需要簡單的將主機上的目錄掛載到容器內,-v參數足夠簡便,如果需要更多掛載選項,推薦使用–mount參數。
五:docker -v的四種用法
1. 不使用-v參數
示例:
lemon@DockerVolume:~/myfile$ docker run -d -p 8803:80 --name nginx-volume5 nginx:latest
bbecec9a49e86319ea239bed3227b54ae00ef514964ed70b9f4e4464cb547ac2
lemon@DockerVolume:~/myfile$ docker inspect nginx-volume5 | grep "Mounts""Mounts": [],
lemon@DockerVolume:~/myfile$
當不使用-v參數時,容器也不會在宿主機上創建volume,此時當容器刪除,數據也會跟隨刪除。
2. -v <容器內路徑>
示例:
lemon@DockerVolume:~/myfile$ docker run -d -p 8804:80 -v /usr/share/nginx/html --name nginx-volume6 nginx:latest
aa30246d69a549c21343b8ef4e7cf94f20c9e4e2a2dbcd3fa3af174b7c39dc7c
lemon@DockerVolume:~/myfile$ docker inspect nginx-volume6 | grep -A 15 "Mounts""Mounts": [{"Type": "volume","Name": "61e5198338d2fffafafe9f1bad51c67c2570506d63124c62355bc4e0e6bea5ef","Source": "/var/lib/docker/volumes/61e5198338d2fffafafe9f1bad51c67c2570506d63124c62355bc4e0e6bea5ef/_data","Destination": "/usr/share/nginx/html","Driver": "local","Mode": "","RW": true,"Propagation": ""}],"Config": {"Hostname": "aa30246d69a5","Domainname": "","User": "",
lemon@DockerVolume:~/myfile$
當 -v 參數僅指定容器內的路徑時,將創建一個匿名類型的volume,用于存儲容器的數據。
3. -v < Volume 名稱>:/<容器內路徑>
示例:
lemon@DockerVolume:~$ docker run -d -p 8805:80 -v NginxVolume7_VolumeName:/usr/share/nginx/html --name nginx-volume7 nginx:latest
d74098d3c4ec7af671e2ab6cd50f9bae51b33fa9fc4100f5adaa380463a062b5
lemon@DockerVolume:~$ docker inspect nginx-volume7 | grep -A 15 "Mounts""Mounts": [{"Type": "volume","Name": "NginxVolume7_VolumeName","Source": "/var/lib/docker/volumes/NginxVolume7_VolumeName/_data","Destination": "/usr/share/nginx/html","Driver": "local","Mode": "z","RW": true,"Propagation": ""}],"Config": {"Hostname": "d74098d3c4ec","Domainname": "","User": "",
lemon@DockerVolume:~$
當 -v 參數指定一個不存在volume時,在創建容器時,docker會自動創建該volume,這兩種類型的 -v 指定掛載方式,不會存在空掛載現象。
4. -v <宿主機路徑>:<容器內路徑>
示例:
lemon@DockerVolume:~$ docker run -d -p 8806:80 -v /home/lemon/nginx_volume8_dir:/usr/share/nginx/html --name nginx-volume8 nginx:latest
df36b3ee868d2e4573b4cb7dd1a1abfafbff4052f102417169b84b152c010c44
lemon@DockerVolume:~$ docker inspect nginx-volume8 | grep -A 15 "Mounts""Mounts": [{"Type": "bind","Source": "/home/lemon/nginx_volume8_dir","Destination": "/usr/share/nginx/html","Mode": "","RW": true,"Propagation": "rprivate"}],"Config": {"Hostname": "df36b3ee868d","Domainname": "","User": "","AttachStdin": false,"AttachStdout": false,
lemon@DockerVolume:~$
當 -v 參數將宿主機的目錄和容器內的目錄關聯起來時,默認會用宿主機的目錄替換容器內部的目錄數據,使用該種方式,需要注意空掛載現象。