深入理解 Docker Volume

2021-07-03 12:17:00 字數 3983 閱讀 1918

本文主要介紹了docker volume的原理以及使用方式,是docker入門教程的延伸。作者通過從資料的共享、資料容器、備份、許可權以及刪除volume五方面深入介紹了volume的工作原理,從實戰中幫助讀者了解volume。

從docker irc頻道以及 stackoverflow 的問題來看,很多人還不是很明白docker volume的工作原理。在這篇文章中,我會盡最大的努力來解釋volume是如何工作的,並展示一些最佳實踐。這篇文章主要是針對那些對volume不了解的docker使用者,當然有經驗的使用者也可以通過本文了解一些volume的細節。

如果想要了解docker volume,首先我們需要知道docker的檔案系統是如何工作的。docker映象是由多個檔案系統(唯讀層)疊加而成。當我們啟動乙個容器的時候,docker會載入唯讀映象層並在其上(譯者注:映象棧頂部)新增乙個讀寫層。如果執行中的容器修改了現有的乙個已經存在的檔案,那該檔案將會從讀寫層下面的唯讀層複製到讀寫層,該檔案的唯讀版本仍然存在,只是已經被讀寫層中該檔案的副本所隱藏。當刪除docker容器,並重新啟動通過該映象啟動時,之前的更改將會丟失。在docker中,唯讀層及在頂部的讀寫層的組合被稱為 union file system (聯合檔案系統)。

為了能夠儲存(持久化)資料以及共享容器間的資料,docker提出了volume的概念。簡單來說,volume就是目錄或者檔案,它可以繞過預設的聯合檔案系統,而以正常的檔案或者目錄的形式存在於宿主機上。

我們可以通過兩種方式來初始化volume,這兩種方式有些細小而又重要的差別。我們可以在執行時使用 -v 來宣告volume:

$ docker run -it --name container-test -h container -v /data debian /bin/bash

root@container:/# ls /data

root@container:/#

上面的命令會將 /data 掛載到容器中,並繞過聯合檔案系統,我們可以在主機上直接操作該目錄。任何在該映象 /data 路徑的檔案會將被複製到volume。我們可以使用 docker inspect 命令找到volume在主機上的儲存位置:

$ docker inspect -f } container-test

你會看到類似的輸出:

map[/data:/var/lib/docker/vfs/dir/cde167197ccc3e138a14f1a4f...b32cec92e79059437a9]

這說明docker把在 /var/lib/docker 下的某個目錄掛載到了容器內的 /data 目錄下。讓我們從主機上新增檔案到此資料夾下:

$ sudo touch /var/lib/docker/vfs/dir/cde167197ccc3e13814f...b32ce9059437a9/test-file

進入我們的容器內可以看到:

$ root@container:/# ls /data

test-file

只要將主機的目錄掛載到容器的目錄上,那改變就會立即生效。我們可以在dockerfile中通過使用 volume 指令來達到相同的目的:

from debian:wheezy

volume /data

但還有另一件只有 -v 引數能做到而dockerfile是做不到的事是在容器上掛載指定的主機目錄。例如:

$ docker run -v /home/adrian/data:/data debian ls /data

該命令將掛載主機的 /home/adrian/data 目錄到容器內的 /data 目錄上。任何在 /home/adrian/data 目錄的檔案都將會出現在容器內。這對於在主機和容器之間共享檔案是非常有幫助的,例如掛載需要編譯的源**。為了保證可移植性(並不是所有的系統的主機目錄都是可以用的),掛載主機目錄不需要從dockerfile指定。當使用 -v 引數時,映象目錄下的任何檔案都不會被複製到volume中。(譯者注:volume會複製到映象目錄,映象不會複製到卷)

資料共享

如果要授權乙個容器訪問另乙個容器的volume,我們可以使用 -volumes-from 引數來執行 docker run 。

$ docker run -it -h newcontainer --volumes-from container-test debian /bin/bash

root@newcontainer:/# ls /data

test-file

root@newcontainer:/#

值得注意的是不管container-test是否執行,它都會起作用。只要有容器連線volume,它就不會被刪除。

資料容器

常見的使用場景是使用純資料容器來持久化資料庫、配置檔案或者資料檔案等。 官方的文件 上有詳細的解釋。例如:

$ docker run --name dbdata postgres echo "data-only container for postgres"

該命令將會建立乙個包含已經在dockerfile裡定義過volume的postgres映象,執行 echo 命令然後退出。當我們執行 docker ps 命令時, echo 可以幫助我們識別某映象的用途。我們可以用 -volumes-from 命令來其它容器的volume:

$ docker run -d --volumes-from dbdata --name db1 postgres

使用資料容器的兩個注意點:

不要執行資料容器,這純粹是在浪費資源。

不要為了資料容器而使用「最小的映象」,如 busybox 或 scratch ,只使用資料庫映象本身就可以了。你已經擁有該映象,所以並不需要占用額外的空間。

備份如果你在用資料容器,那做備份相當容易:

$ docker run --rm --volumes-from dbdata -v $(pwd):/backup debian tar cvf /backup/backup.tar /var/lib/postgresql/data

該示例應該會將volume裡所有的東西壓縮為乙個tar包(官方的postgres dockerfile在/var/lib/postgresql/data目錄下定義了乙個volume)

許可權與許可

通常你需要設定volume的許可權或者為volume初始化一些預設資料或者配置檔案。要注意的關鍵點是,在dockerfile的 volume 指令後的任何東西都不能改變該volume,比如:

from debian:wheezy

run useradd foo

volume /data

run touch /data/x

run chown -r foo:foo /data

該docker file如預期那樣執行,我們本來希望 touch 命令在映象的檔案系統上執行,但是實際上它是在乙個臨時容器的volume上執行。如下所示:

from debian:wheezy

run useradd foo

run mkdir /data && touch /data/x

run chown -r foo:foo /data

volume /data

docker可以將映象中volume下的檔案掛載到volume下,並設定正確的許可權。如果你指定volume的主機目錄將不會出現這種情況。

如果你沒有通過 run 指令設定許可權,那麼你就需要在容器啟動時使用 cmd 或 entrypoint 指令來執行(譯者注:cmd指令用於指定乙個容器啟動時要執行的命令,與run類似,只是run是映象在構建時要執行的命令)。

刪除volumes

這個功能可能會更加重要,如果你已經使用 docker rm 來刪除你的容器,那可能有很多的孤立的volume仍在占用著空間。

volume只有在下列情況下才能被刪除:

該容器可以用 docker rm -v 來刪除且沒有其它容器連線到該volume(以及主機目錄是也沒被指定為volume)。注意, -v 是必不可少的。

docker run 中使用 rm 引數

除非你已經很小心的,總是像這樣來執行容器,否則你將會在 /var/lib/docker/vfs/dir 目錄下得到一些殭屍檔案和目錄,並且還不容易說出它們到底代表什麼。

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...