五方面深入介紹了Docker Volume的工作原理
本文主要介紹了Docker Volume的作用機制,是 Docker入門教程的延伸, 作者通過從數據的共享、數據容器、備份、權限以及刪除Volumes五方面深入介紹了Volumes的工作原理。
從Docker IRC(網絡即時聊天)頻道以及 stackoverflow(譯 者注:有關代碼問題的問答平臺:大部分代碼exception問題可以復制->粘貼->搜索來找到答案)的問題來看,Docker volumes是如何工作的這個問題上還存在很多混淆。在這篇文章中我會盡最大努力來解釋Volumes是如何工作的,并展示一些最佳實踐。雖然這篇文章 主要是針對泊塢窗的用戶幾乎沒有的知識量,盡管這篇文章主要是針對那些對Volumes不了解的Docker用戶,當然有經驗的用戶也可以學一些 Volumes的很多人不知道的細微之處的知識。
為了了解什么是Docker Volume,首先我們需要明確Docker內的文件系統是如何工作的。Docker鏡像被存儲在一系列的只讀層。當我們開啟一個容器,Docker讀取 只讀鏡像并添加一個讀寫層在頂部。如果正在運行的容器修改了現有的文件,該文件將被拷貝出底層的只讀層到最頂層的讀寫層。在讀寫層中的舊版本文件隱藏于該 文件之下,但并沒有被不破壞 - 它仍然存在于鏡像以下。當Docker的容器被刪除,然后重新啟動鏡像時,將開啟一個沒有任何更改的新的容器 - 這些更改會丟失。此只讀層及在頂部的讀寫層的組合被Docker稱為 Union File System(聯合文件系統)。
為了能夠保存(持久)數據以及共享容器間的數據,Docker提出了Volumes的概念。很簡單,volumes是目錄(或者文件),它們是外部默認的聯合文件系統或者是存在于宿主文件系統正常的目錄和文件。
初始化Volumes有兩種方式,對于理解來說一些細微的差別很重要。我們可以用在運行時使用-v來聲明Volumes:
$ 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 {{.Volumes}} 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中。
數據共享
從一個容器訪問另一個容器的volumes,我們只用使用-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。只要使用數據庫鏡像本身就可以了。如果你已經有了該鏡像,那么它并不需要花費額外的空間并且它還允許鏡像內的數據來做Volume </ul>
- 該容器可以用docker rm -v來刪除且沒有其他容器連接到該Volume(以及主機目錄是也沒被指定為Volume)。注意,-v是必不可少的。
- 該-rm標志被提供給docker run的 </ul>
- 瘋狂Docker之純數據容器
- 深入Docker之Volumes
- 容器數據管理 </ul>
- Docker提議 #8484 </ul>
備份
如果你在用數據容器,做備份是相當容易的:$ docker run --rm --volumes-from dbdata -v $(pwd):/backup debian tar cvf /backup/backup.tar /var/lib/postgresql/data
該示例應該會將Volume里所有的東西壓縮為一個tar包(官方的postgres Dockerfile定義了一個Volume在/var/lib/postgresql/data目錄下)
權限與許可
通常你需要設置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腳本來執行。
刪除Volumes
該功能比大多數人意識到的可能更微妙一些。如果你已經使用docker rm來刪除你的容器,可能有很多的孤立的Volumes在占用著那些空間。Volume只有在下列情況下才能被刪除:
除非你已經很小心的,總是像這樣來運行容器,否則你將會在/var/lib/docker/vfs/dir目錄下得到一些僵尸文件和目錄,并且還不容易說出他們到底代表什么。
延伸閱讀
以下資源更深入的探究了Volumes機制(譯注:以下譯文稍后奉上):另外,我們可以期待不久的將來會更多的有關處理volumes的工具:
原文鏈接:Understanding Volumes in Docker(翻譯:田浩)
來自: http://dockerone.com/article/128