窺探Docker中的Volume Plugin內幕
作者介紹: 張朝潞,有容云(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。
出處鏈接: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。
Container中的Volume
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的文件:
查看/dev/disk/by-uuid/88f22c9e-9d5d-4c7e-8984-eba8446361e6是鏈接文件指向/dev/sda2,這是主機的根目錄文件系統。
3 .Container中的Volume 容器啟動: docker run -i -v cvol1:/data –volume-driver=convoy ubuntu:latest /bin/bash 將volume: dockervol掛載到容器目錄/data 容器內看到的掛載信息:
此時掛載卷信息:
三. Docker Volume Plugin
- Docker Volume Plugin框架
Docker volume框架 1.) Docker Daemon對Volume的管理
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,提供如下命令:
2.) docker volume 管理
基于本地文件系統的volume框架
Docker提供兩個接口Volume和Driver,所有提供給Docker使用的Volume必須實現Volume接口。后端驅動需要實現Driver接口。Driver是對提供出去的Volume進行管理。目前Docker實現了兩種Volume &Driver。
① 基于本地文件系統的Volume
可以在執行Docker create或Docker run時,通過-v參數將主機的目錄作為容器的數據卷。這部分功能便是基于本地文件系統的volume管理。上圖中藍色部分LocalVolume和Root。這兩個結構就是對主機目錄和文件進行管理,具體的對應關系如下圖:
從上圖可以看出,基于本地文件系統的卷管理,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 實現原理
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便可。
例子:GlusterFS就是使用這個包,基于GlusterFS提供Volume。https://github.com/calavera/docker-volume-glusterfs
關于Docker存儲方面的內容,我們之前分享過一篇叫《Docker容器對存儲的定義(Volume 與 Volume Plugin) 》的文章,感興趣的朋友可以關注有容云搜索下。好的,我們今天的分享先告一個段落,謝謝大家!
溫馨提示:
對Docker容器技術或容器生產實施感興趣的朋友歡迎加群討論。我們匯集了Docker容器技術落地實施團隊精英及業內技術派高人,在線為您分享Docker技術干貨。我們的宗旨是為了大家擁有更專業的平臺交流Docker實戰技術,我們將定期邀請嘉賓做各類話題分享及回顧,共同實踐研究Docker容器生態圈。
via: http://www.ituring.com.cn/article/215542