DOCKER存储驱动之DEVICE MAPPER简介
Device Mapper是一個基于kernel的框架,它增強了很多Linux上的高級卷管理技術。Docker的devicemapper驅動在鏡像和容器管理上,利用了該框架的超配和快照功能。為了區別,本文使用Device Mapper指驅動中的框架,而devicemapper指Docker的存儲驅動。
注意:商業支持的Docker Engine(CS-Engine)建議在RHEL和CentOS上使用devicemapper存儲驅動。
AUFS之外的另一種選擇
Docker最初運行在Ubuntu和Devian上,并且使用AUFS作為存儲后端。當Docker變得流行后,很多想使用它的公司正在使用RHEL。不幸的是,因為Linux主線kernel并不包含AUFS,所以RHEL并沒有支持AUFS。
為了改變這種情況,Red Hat開發者研究將AUFS包含進kernel主線。最后,他們認為開發一種新的存儲后端是更好的主意。此外,他們打算使用已經存在的Device Mapper技術作為新存儲后端的基礎。
Red Hat與Docker公司合作貢獻這個新驅動。因為這次合作,Docker Engine被重新設計為存儲驅動插件化。因此devicemapper成為Docker支持的第二個存儲驅動。
Device Mapper在2.6.9之后就被何如Linux kernel主線,也是RHEL家族發布包的核心部分。這意味著devicemapper存儲驅動基于穩定的代碼,有著大量的工作產品和極強的社區支持。
鏡像分層和共享
devicemapper驅動把每個鏡像和容器都存儲在它自己的虛擬設備中,這些設備是超配的copy-on-write快照設備。Device Mapper技術工作在塊級別而不是文件級別,也就是說devicemapper存儲驅動的超配和copy-on-write操作直接操作塊,而不是整個文件。
注意:快照也是使用的thin設備或者虛擬設備。
使用devicemapper時,Docker如下創建鏡像:
devicemapper存儲驅動創建一個thin池。
這個池是在塊設備或者loop mounted sparse file上創建的。
然后創建一個基礎設備。
該基礎設備是一個帶文件系統的thin設備。可以通過docker info命令中的Backing filesystem值,來查看后端使用的是哪種文件系統。
每個新的鏡像(和鏡像層)都是該基礎設備的快照。
這些都是超配的copy-on-write快照。也就是說它們初始化的時候是空的,只有在有數據寫向它們時,才會從池中消耗空間。
使用devicemapper,容器層是基于鏡像的快照。和鏡像一樣,容器快照也是超配的copy-on-write快照。容器快照保存了容器的所有更新,當向容器寫數據時,devicemapper按需從池中分配空間給容器層。
下圖展示了一個thin池、基礎設備和兩個鏡像。
如果你仔細觀察圖片,你會發現每個鏡像層都是它下層的快照,鏡像的最底層是池中基礎設備的快照。這個基礎設備是Device Mapper產生的,并不是一個Docker鏡像層。
而容器又是鏡像的一個快照,下圖展示了兩個容器在整個存儲驅動的層次。
devicemapper的讀操作
下圖顯示了在一個容器中讀取一個塊(地址是0x44f)的過程。
應用在容器中請求訪問塊0x44f。
因為容器是鏡像的一個thin快照,它沒有實際的數據。但它有指針,指向鏡像棧中數據所在的鏡像快照。
存儲驅動根據指針找到對應鏡像層a005的快照塊0xf33。
devicemapper拷貝鏡像快照中塊0xf33的數據到容器內存中。
容器驅動將數據返回給請求應用。
寫操作
使用devicemapper驅動,寫數據到容器是通過一個按需分配操作來完成的。更新已有的數據使用了copy-on-write操作。不過Device Mapper是基于塊存儲的技術,所以這些操作都發生在塊的級別。
例如,要對容器中的一個大文件作小的修改,devicemapper驅動不拷貝整個文件,它只拷貝要修改的內容對應的塊,每個塊大小為64KB。
寫數據
向容器寫55KB的數據:
應用向容器發起寫56KB數據的請求;
按需分配操作給容器快照分配了一個新的64KB的塊。
如果寫的數據大于64KB,就需要分配多個塊給容器快照。
數據寫向新分配的塊。
覆寫已有數據
第一次修改已有的數據:
應用向容器發起修改數據的請求;
copy-on-write操作定位到需要更新的塊;
分配新的塊給容器快照,并拷貝數據到這些塊中;
修改的數據寫向新分配的這些塊。
容器中的應用并不會感知到這些按需分配和copy-on-write操作。然而,這些操作還是可能會對應用的讀寫帶來一些延遲。
Docker中配置devicemapper
devicemapper是部分Linux發行版的默認Docker存儲驅動,這其中就包括RHEL和它的分支。當前,以前發行版支持該驅動:
●RHEL/CentOS/Fedora
●Ubuntu
●Debian
●Arch Linux
Docker host使用loop-lvm的配置模式來運行devicemapper。該模式使用系數文件來創建thin池,這些池用于鏡像和容器快照。并且這些模式是開箱即用的,無需額外配置。不過,不建議在產品部署中使用loop-lvm模式。
可以通過docker info命令來查看是否使用了該模式。
通過上面輸出可得出,Docker host使用devicemapper存儲驅動。并且,還使用了loop-lvm模式,因為/var/lib/docker/devicemapper/devicemapper下有Data loop file和Metadata loop file這兩個文件。這些都是loopback映射的稀疏文件。
在產品中配置direct-lvm模式
產品部署中應該使用direct-lvm模式,該模式使用塊設備來創建thin池。下面的步驟描述了如何在Docker host使用direct-lvm模式得devicemapper存儲驅動。
注意:如果你已經在Docker host上運行了Docker daemon,并且有一些想保存的鏡像,那么在執行以下步驟之前,把它們push到Docker Hub,或者你的私有Docker Registry。
以下步驟會創建一個邏輯卷,配置為thin池,用作后端的存儲池。假設你有一個稀疏塊設備/dev/xvdf,并且該設備有足夠的空間來完成這個任務。在你的環境中,設備標識符和卷的大小可能不同,在你執行下面過程時,你應該替換為適合你環境的值。另外,以下的步驟應該在Docker Daemon停止的時候來執行。
1) 進入Docker host,并停止Docker daemon;
2) 安裝LVM2和thin-provisioning-tools安裝包;
LVM2安裝包提供了用戶空間的工具,用于管理邏輯卷。
thin-provisioning-tools用于激活和管理池。
3) 創建一個物理卷/dev/xvdf來替換塊設備;
$?pvcreate?/dev/xvdf4) 創建卷組docker;
$?vgcreate?docker?/dev/xvdf 5) 創建名為thinpool和thinpoolmeta的虛擬卷;
在該示例中,數據大小是docker卷組大小的95%,留下這些空閑空間,是用于數據或元數據的自動擴容。
6) 把池轉換為thin池;
$?lvconvert?-y?--zero?n?-c?512K?--thinpool?docker/thinpool?--poolmetadata?docker/thinpoolmeta7) 通過lvm文件來配置thin池的自動擴容;
$?vi?/etc/lvm/profile/docker-thinpool.profile 8) 指定thin_pool_autoextend_threshold值;
該值是lvm嘗試擴容到可用空間時,當前已空間使用量的百分比(100=禁止)。
9) 修改thin_pool_autoextend_percent;
該值是thin池要擴容的百分比(100=禁止)。
10) 檢查上面的步驟,你的docker-thinpool.profile文件應該是類似下面的內容:
一個/etc/lvm/profile/docker-thinpool.profile示例文件:
11) 應用新的lvm profile文件;
$?lvchange?--metadataprofile?docker-thinpool?docker/thinpool12) 確認lv是否被修改;
$?lvs?-o+seg_monitor 13) 如果之前Docker daemon被啟動過,那么需要將之前的graph driver目錄給挪走;
移動graph driver會刪除所有的鏡像容器和卷。下面的命令將/var/lib/docker的內容移動到另一個目錄中。
14) 使用特殊的devicemapper選項來配置Docker daemon;
有兩種方法來配置Docker daemon的devicemapper存儲驅動。你可以運行daemon時加上以下參數:
也可以在daemon配置文件中配置,如默認的配置文件/etc/docker/daemon.json中,可如下配置:
{"storage-driver":?"devicemapper","storage-opts":?[?????"dm.thinpooldev=/dev/mapper/docker-thinpool",?????"dm.use_deferred_removal=true",?????"dm.use_deferred_deletion=true"] } 注意:總是使用dm.use_deferred_removal=true和dm.use_deferred_deletion=true選項,以防止無意地泄露映射資源信息。
15) (可選的)如果使用了systemd,并且修改了daemon配置文件,需要重載systemd信息;
16) 重啟Docker daemon。
$?systemctl?start?docker 當你啟動Docker daemon后,確保一直監控者thin池和卷組的可用空間。當卷組自動擴容時,可能會占滿所有空間。可以使用lvs或lvs -a命令來監控邏輯卷,可以查看到數據和元數據的大小。另外,還可以使用vgs命令來監控卷組的可用空間。
當到達閾值后,日志會顯示thin池的自動擴容信息,可使用以下命令來查看日志:
當你確認你的配置文件無誤時,就可以刪除之前的備份目錄了。
$?rm?-rf?/var/lib/docker.bk你還可以使用dm.min_free_space參數。該值保證黨可用空間到達或者接近最小值時,操作失敗會有提示。可以查看更多的驅動選項。
檢查devicemapper結構體
可以通過lsblk命令查看devicemapper存儲驅動創建的pool相關的設備文件。
$?sudo?lsblkNAME???????????????MAJ:MIN?RM??SIZE?RO?TYPE?MOUNTPOINT xvda???????????????202:0????0????G??0?disk └─xvda1????????????202:1????0????G??0?part?/ xvdf???????????????202:80???0???0G??0?disk ├─vg--docker-data??????????253:0????0???0G??0?lvm │?└─docker-202:1-1032-pool?253:2????0???0G??0?dm └─vg--docker-metadata??????253:1????0????G??0?lvm└─docker-202:1-1032-pool?253:2????0???0G??0?dm 下圖顯示了上面示例的鏡像信息。
圖中,pool的名稱叫做Docker-202:1-1032-pool,橫跨data和metadata兩個設備。devicemapper的pool名稱格式為:
MAJ,MIN和INFO分別表示major、minor設備號,和inode號。
有兩個主要的目錄。/var/lib/docker/devicemapper/mnt目錄包含鏡像和容器層的映射點。/var/lib/docker/devicemapper/metadata目錄為每個鏡像層和容器快照都對應了一個文件,文件以JSON格式保存每個快照的元數據。
Device Mapper和Docker性能
理解按需分配和copy-on-write可以讓你對容器性能有個整體的了解。
按需分配性能影響
devicemapper存儲驅動在按需分配操作時會給容器分配一個新的塊。也就是說每次應用向容器某個位置寫數據時,一個或多個塊就會從池里面分配,并且映射給容器。
所有的塊都是64KB大小,一個小于64KB的寫請求也會導致分配64KB的塊,大于64KB的寫請求就要求多個64KB的塊。這會影響容器的性能,尤其容器有很多小的寫請求時。然而,一旦一個塊分配給容器后,后續的讀寫都會直接操作這個新分配的塊。
Copy-on-write性能影響
每次容器第一次更新已有數據時,devicemapper存儲驅動都會執行copy-on-write操作,該操作會將數據從鏡像快照拷貝到容器快照。這在容器性能上有著明顯的影響。
所有的copy-on-write操作都有64KB的粒度。因此,要修改1GB文件的32KB內容時,只需要拷貝64KB大小的塊到容器即可。如果要拷貝整個大文件到容器層時,該特性較于文件層的copy-on-write操作有著明顯的性能優勢。
然而,實際中,如果容器執行大量的小的寫請求時(<64KB),devicemapper性能差于AUFS。
其他device mapper性能注意事項
還有一些點會影響devicemapper存儲驅動的性能。
模式。Docker運行devicemapper存儲驅動的默認模式是loop-lvm。該模式使用稀疏文件,并且性能堪憂。在產品中不建議使用該模式,產品環境中建議使用direct-lvm,這樣存儲驅動就可以直接寫向塊設備。
高速存儲。為了更好的性能,可以將Data文件和Metadata文件放在高速存儲(如SSD)上。當然,也可以直接連接到SAN或NAS array上。
內存使用。devicemapper不是內存最高效的Docker存儲驅動。啟動同一個容器的n份拷貝需要將其文件大小的n份拷貝加載到內存中,這對于Docker host的內存有一定影響。因此,devicemapper存儲驅動可能不是Pass或其他高密度用例的最優方案。
最后一點,數據卷提供了更好和可預測的性能。因此,應該將負載高的寫請求寫到數據卷中。
轉載于:https://blog.51cto.com/welcomeweb/1921289
總結
以上是生活随笔為你收集整理的DOCKER存储驱动之DEVICE MAPPER简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《我的视频我做主:Premiere Pr
- 下一篇: 基于Qt的光盘刻录开发