有容雲——窺探Docker中的Volume Plugin內幕

有容雲發表於2016-05-16

編者注: 本文根據有容雲技術實施團隊原創分享內容整理。對Docker技術感興趣、或對本文中細節需繼續探討的朋友,歡迎加入我們參與討論! 特別鳴謝中生代技術群分享支援。

注:本期分享由張朝潞原創,有容雲整理髮布,轉載請註明出處

作者介紹: 張朝潞,有容雲(Yourun Cloud)平臺儲存架構師。曾工作於UIT,華三,騰訊,專注分散式儲存的研究和開發,對雲端計算儲存解決方案方面有很深的技術造詣和行業理解。

本次交流將與大家分享Docker Volume plugin相關的內容。今日主題是窺探Docker中的Volume plugin內幕。

因為應用資料對安全,可用性,共享,效能等方面的要求和Root Image的要求完全不一樣,所以Docker並不推薦採用Root Image的儲存方式來儲存應用資料,而是採用了Volume這樣一個獨立的資料訪問介面。

應用通過Volume去訪問相關的資料,Volume的實現和CoW的分層檔案系統完全獨立,通過Volume plugin機制可輕易驅動外部儲存。

下面我們就圍繞Volume Plugin Introduction、Container and Volume、Docker Volume Plugin、自定義Volume Plugin四個方面來展開。

一. Volume Plugin Introduction 通過Volume機制,Docker可以輕易地將主機目錄掛載到容器中;通過Docker的Volume Plugin機制,使Docker能夠方便地整合第三方儲存,為Docker提供Volume。

enter image description here

出處連結:https://github.com/docker/docker/blob/master/docs/extend/plugins.md

二. Container and Volume

1 .Container如何使用Volume? Volume機制可以使容器訪問儲存都使用統一的介面(檔案介面),對於容器中的程式來說,Volume就是一個已掛載的目錄,容器內程式使用該目錄就與普通目錄一樣。

Docker使用Container結構管理容器,Container結構中有map型別的MountPoints變數,用於儲存Container中所有已掛載的Volume即是MountPoint結構,MountPoint結構儲存掛載目錄和Volume結構的基本資訊,並且管理目錄的許可權控制、掛載傳播方式等特性。

Volume是個interface,Docker實現兩種Volume:①基於主機檔案系統。②基於Volume Plugin。

enter image description here

Container中的Volume

enter image description here

2.基於主機檔案系統提供Volume 容器啟動:docker run -i -v /data ubuntu:latest /bin/bash 容器內看到的掛載資訊:

/etc/resolv.conf、/etc/hostname和/etc/hosts三個檔案是為了解決每個Container都擁有自己的Hostname和DNS配置,使用了bind mount將主機的檔案,掛載到Container內部。/data也是使用了同樣的方式將主機的目錄掛載到Container中。下面是主機掛載到Container的檔案:

enter image description here

檢視/dev/disk/by-uuid/88f22c9e-9d5d-4c7e-8984-eba8446361e6是連結檔案指向/dev/sda2,這是主機的根目錄檔案系統。

enter image description here

3 .Container中的Volume 容器啟動: docker run -i -v cvol1:/data –volume-driver=convoy ubuntu:latest /bin/bash 將volume: dockervol掛載到容器目錄/data 容器內看到的掛載資訊:

enter image description here

此時掛載卷資訊:

enter image description here

三. Docker Volume Plugin

  1. Docker Volume Plugin框架

enter image description here

Docker volume框架 1.) Docker Daemon對Volume的管理

enter image description here

Docker Daemon中的Volume

如上圖,Docker Daemon結構中有個成員Volumes,型別是VolumeStore型別,包含一組管理Volume的函式:Create、Remove、List、Get、Refs ...。通過兩個變數,管理Container和Volume的關係。 names : map結構,Key是Volume的name,value是實現Volume介面的結構物件。儲存該Daemon內所有的Volume。 ReFS: map結構,key是volume的name,value是string陣列儲存引用該Volume的Container ID。 Docker Daemon通過Volumes變數,就可以管理所有的Volume,提供如下命令:

enter image description here

2.) docker volume 管理

enter image description here

基於本地檔案系統的volume框架

Docker提供兩個介面Volume和Driver,所有提供給Docker使用的Volume必須實現Volume介面。後端驅動需要實現Driver介面。Driver是對提供出去的Volume進行管理。目前Docker實現了兩種Volume &Driver。

① 基於本地檔案系統的Volume

可以在執行Docker create或Docker run時,通過-v引數將主機的目錄作為容器的資料卷。這部分功能便是基於本地檔案系統的volume管理。上圖中藍色部分LocalVolume和Root。這兩個結構就是對主機目錄和檔案進行管理,具體的對應關係如下圖:

enter image description here

從上圖可以看出,基於本地檔案系統的卷管理,Driver便是卷的根目錄/var/lib/docker/volumes。一個卷就是根目錄下的一個子目錄。

② 適配Plugin的Volume Docker為了支援第三方儲存方案,在1.8版本引入Volume Plugin機制,Volume Adapter和Volume Driver Adapter分別實現了介面Volume和Driver介面,用於表示由Plugin提供的Volume和Plugin driver。在下一小節詳細描述。

基於本地檔案系統的Volume框架中,全域性變數drivers儲存了所有註冊到Docker Daemon的Driver。Docker Daemon需要對Volume進行管理操作時,通過GetDriver函式從drivers變數中獲取指定名稱的Driver,通過Driver可以通過Create,Remove,List,Get對Driver中Volume進行管理。通過Get函式獲取Volume結構,可以對捲進行管理操作:Name,DriverName,Path,Mount,Unmount。

3 .) docker plugin 實現原理

enter image description here

Volume Plugin實現原理 ① Docker Plugin機制

 上一節已經說過Docker針對Volume Plugin實現了兩個適配型別Volume Driver Adapter和Volume Adapter。

Volume Driver Adapter : 實現Driver介面,用於抽象各種Plugin的驅動,該型別可以適配所有符合規範的Volume Plugin,對Plugin進行管理。 Volume Adapter : 實現Volume介面,用於抽象所有Plugin提供的Volume,該型別可以適配所有符合規範的Volume Plugin提供的型別,對Volume進行管理。 通過抽象,對於Plugin和其提供的Volume,Docker Daemon結構和Container結構使用上述兩個適配型別,對Plugin和Volume進行管理和使用。

上述兩個型別都有一個Volume Driver Proxy結構變數proxy,用於與Plugin進行通訊。Volume Driver Proxy結構實現了與plugin通訊的介面volume Driver,提供Create、Remove、Path、Mount、Unmount、List、Get介面與通訊。Volume Driver Proxy結構的client變數,使用這個變數與Plugin Daemon進行通訊。client變數是Plugin結構中的Client變數是Client結構型別,包含了http.Client型別物件。

上圖中左下方,Plugins結構型別的全域性變數Storage儲存所有被Docker Daemon發現的Plugin結構,Plugin結構代表外部外掛。

② Docker Plugin的發現過程

Docker Daemon通過Unix域套接字與Plugin Daemon進行通訊。所以Plugin需要讓Docker Daemon知道Plugin的Unix域套接字檔案的路徑。再執行命令:docker run ... -v volumename:/data --volume-driver=convoy

發現步驟: Docker Daemon首先會在/run/docker/plugins搜尋對應的套接字檔案,套接字檔名必須和Volume Driver名一致,如上述命令,便是搜尋convoy.sock。 如果上一步搜尋不到,則到/etc/docker/plugins和/usr/lib/docker/plugins兩個目錄搜尋spec或json檔案。檔案中指定套接字檔案的URL。如:unix:///var/run/convoy/convoy.sock 。 根據前面兩步發現的Unix域套接字URL,構建Plugin物件,並將新建物件加入到全域性變數storage的Plugins欄位中。

③ Docker Volume Plugin的使用
執行docker run命令時,指定引數--volume-driver=convoy。Docker Daemon會先從storage.plugins中尋找Plugin結構,如果沒有找到,就發起②的發現流程。找到則直接使用Client構建volume Driver Proxy。

④ Docker Daemon與Plugin Daemon通訊的API
前面已經提到過,Docker Daemon和Plugin Daemon基於Unix域套接字,使用Restful API進行通訊,下面是詳細的API:

Plugin.Activate : 傳送一個請求到Plugin,Plugin返回其型別,如convoy就返回Volume Driver。相當於Docker和Plugin Daemon直接的連線建立的握手報文。 VolumeDriver.Create : 建立一個卷,Docker會傳送卷名稱和引數傳送給外掛,卷外掛會根據Docker傳送過來的引數建立一個卷,並和這個卷名稱關聯。 VolumeDriver.Mount : 掛載一個捲到本機,Docker會把卷名稱和引數傳送給引數。外掛會返回一個本地路徑給Docker,這個路徑就是卷所在的位置。Docker在建立容器的時候,會將這個路徑掛載到容器中。 VolumeDriver.Path : 一個卷建立成功後,Docker會呼叫Path API來獲取這個卷的路徑,隨後Docker通過呼叫Mount API,讓外掛將這個卷掛載到本機。 VolumeDriver.Unmount : 當容器退出時,Docker daemon會傳送Umount API給外掛,通知外掛這個卷不再被使用,外掛可以對該卷做些清理工作(比如引用計數減一,不同的外掛行為不同)。 VolumeDriver.Remove : 刪掉特定的卷時呼叫,當執行"docker rm -v"命令時,Docker會呼叫該API傳送請求給外掛。 VolumeDriver.List : 執行docker volume ls命令時,會向plugin傳送該請求,獲取volume list。 VolumeDriver.Get : 獲取Plugin Volume的詳細資訊。 四. 自定義Volume Plugin 為了方便實現Volume Plugin,Docker提供go-plugins-helper包(https://github.com/docker/go-plugins-helpers),提供基礎的功能,僅僅需要實現一個介面volume.Driver,並啟動http server便可。

enter image description here

例子:GlusterFS就是使用這個包,基於GlusterFS提供Volume。https://github.com/calavera/docker-volume-glusterfs

關於Docker儲存方面的內容,我們之前分享過一篇叫《Docker容器對儲存的定義(Volume 與 Volume Plugin) 》的文章,感興趣的朋友可以關注有容雲搜尋下。好的,我們今天的分享先告一個段落,謝謝大家!

溫馨提示:

對Docker容器技術或容器生產實施感興趣的朋友歡迎加群討論。我們彙集了Docker容器技術落地實施團隊精英及業內技術派高人,線上為您分享Docker技術乾貨。我們的宗旨是為了大家擁有更專業的平臺交流Docker實戰技術,我們將定期邀請嘉賓做各類話題分享及回顧,共同實踐研究Docker容器生態圈。

加微信群方法: 1.關注【有容雲】公眾號 2.留言”我要加群” QQ群號:454565480

相關文章