1. 程式人生 > >Docker之應用資料管理(volume/bind mount/tmpfs)

Docker之應用資料管理(volume/bind mount/tmpfs)

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

  1. 容器中的資料會隨著容器的停止執行而消失, 而且當其他的程序需要這些資料時,很難將這些資料從容器中提取出來;
  2. 容器的資料寫入層是緊密地對應著他的宿主作業系統的,資料不能容易的被遷移到其他地方;
  3. 要將資料寫入到容器的資料寫入層,需要一個特定的儲存驅動,利用linux核心構建一個統一的檔案系統,來管理宿主和容器的檔案系統。這層額外的虛擬化顯然會降低效能。為了避免效能下降,docker使用data volumes的方式,直接對宿主檔案系統進行寫操作。
Docker提供了三種不同的方式用於將宿主的資料掛載到容器中:volumes,bind mounts,tmpfs volumes。當你不知道該選擇哪種方式時,記住,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就可以看見原先的檔案了。