**:
【編者的話】本文主要介紹了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/bashroot@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 /datatest-file
只要將主機的目錄掛載到容器的目錄上,那改變就會立即生效。我們可以在dockerfile中通過使用volume
指令來達到相同的目的:
from debian:wheezyvolume /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/bashroot@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
使用資料容器的兩個注意點:
如果你在用資料容器,那做備份是相當容易的:
$ 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:wheezyrun useradd foo
volume /data
run touch /data/x
run chown -r foo:foo /data
該docker file不能按預期那樣執行,我們本來希望touch
命令在映象的檔案系統上執行,但是實際上它是在乙個臨時容器的volume上執行。如下所示:
from debian:wheezyrun 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是映象在構建時要執行的命令)。
這個功能可能會更加重要,如果你已經使用docker rm
來刪除你的容器,那可能有很多的孤立的volume仍在占用著空間。
volume只有在下列情況下才能被刪除:
即使用以上兩種命令,也只能刪除沒有容器連線的volume。連線到使用者指定主機目錄的volume永遠不會被docker刪除。
除非你已經很小心的,總是像這樣來執行容器,否則你將會在/var/lib/docker/vfs/dir
目錄下得到一些殭屍檔案和目錄,並且還不容易說出它們到底代表什麼。
以下資源更深入的**了volumes機制(譯註:以下譯文稍後奉上):
另外,我們可以期待不久的將來會更多的有關處理volumes的工具:
===========================
譯者介紹
田浩浩,
雪梨大學usyd
碩士研究生,目前在珠海從事android應用開發工作。業餘時間專注docker的學習與研究,希望通過
dockerone
把最新最優秀的譯文貢獻給大家,與讀者一起暢遊docker的海洋。
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...
mysql 索引深入理解 深入理解MySql的索引
為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...
深入理解C語言 深入理解指標
關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...