理解docker映象,容器和儲存驅動
理解docker映象,容器和儲存驅動
2016年9月5日
14:40
一. 映象
映象作為docker中最基本的概念,有以下幾個特性:
- 分層,每個映象都由一個或多個映象層組成
- 可通過在某個映象加上一定的映象層得到新映象(此過程可通過編寫dockerfile或在容器中commit實現)
- 每個都分層擁有唯一ID
- 映象在儲存和使用時共享相同的映象層(根據ID),所以在pull映象時,已有的映象層會自動跳過下載
- 每個映象層都是隻讀,即使啟動成容器,也無法對其真正的修改,修改只會作用於最上層的容器層
二. 映象 vs容器
- 映象加上一層可讀寫層(容器層)組成該映象對應容器的檔案系統
- 在容器中通過commit
三. Copy-On-Write,COW
寫時拷貝,多個程式共享同一份檔案,讀操作時對這份檔案無影響,當程式需要進行寫操作時才把要寫的部分拷貝一份給對應程式。COW只是一種策略,有多種方法去實現。根據這種思想可以大大減少儲存冗餘。docker實現了COW策略,所以容器會共享相同的映象層,如下圖(同一個映象啟動成多個容器時)
生成新映象的方法有,從容器中commit,或者使用dockerfile。dockerfile其實本質是也是啟動容器去commit
dockerfile中每一個命令就對應生成一個映象,即每個命令對應一個映象層,如下圖
為什麼要這麼細粒度的劃分層是因為,細粒度的映象層被共用到的機率越大。舉個極端的例子,如果把基於一個ubuntu映象上所做的操作都歸到一層的話,那麼這一層共用到的機率幾乎為零,因為定製化程度太高,每個人所需的環境不同。
四. docker storage driver
docker將容器的一些底層執行環境進行抽象,從複雜的實現中分離出了driver元件,讓使用者得以專注於業務相關的容器使用。使用者可以通過選定不同的driver元件來對docker中容器大環境的定製,具體的實現操作則交由
driver分為三類:
- exec-driver,實現對容器執行環境的隔離和資源的限制,可選方案:lxc或native(libcontainer);
- network-driver,實現容器網路相關的操作;
- graph-driver,實現映象儲存相關操作,可選方案:devicemapper,aufs,btrfs,zfs等。
storage driver,docker中的一個元件,也稱graphdriver。
功能:
- 映象的儲存管理,包括從hub上pull的映象和通過dockerfile生成的新映象等;
- 容器啟動時,為容器準備檔案系統
對於graphdriver選擇何種方案去實現,並不影響docker功能方面的使用。每種方案都能實現映象的分層結構和COW策略,但不同的方案對於docker的儲存速度和穩定性是有影響的。目前相對比較成熟的有,aufs和devicemapper(WAE使用中)
下圖為各個方案的特點:
五. devicemapper
基於linux核心中的DeviceMapper框架實現,該框架實現了物理儲存裝置與虛擬儲存裝置的對映,或虛擬裝置與虛擬裝置之間的對映。這使得使用者能夠用該框架來實現磁碟的自由、動態的劃分。LVM2,software RAIDs和dm-cryptdisk encryption等都是基於該框架的實現。更為重要的是,Device Mapper框架中提供兩個功能,thin-provisioning和snapshot。
thin-provisioning,類似於虛擬記憶體,提供給使用者的空間只有在使用者進行寫操作時才真正進行分配。假設使用者有一塊100g的thin塊裝置,使用了20g,實際系統提供的大小就是20g,只有當使用者進行儲存操作時才分配更多的空間,直到100g。
snapshot,快照,是一種COW策略的實現,假設從A裝置做快照得到B裝置時,並未對A進行完整拷貝,而是當對B裝置進行寫操作時,才將需要改變的那部分做屬於B裝置的拷貝。
devicemapper利用了該框架中的thin-provisioning和snapshot實現了映象的分層結構和儲存優化。在用devicemapper作為graphdriver的docker中,每個映象和容器都對應一個裝置,通過對映象做snapshot操作得到容器,所以容器中擁有映象的內容且操作這些內容不影響映象本身,因為容器和映象對應不同的裝置。
devicemapper有兩種模式可選,loop-lvm和direct-lvm。devicemapper的大致思路是,先通過虛擬化技術得到一個thin-pool裝置(可理解成一個資源池),接著在thin-pool上建立一個基礎裝置,此後docker上所有映象和容器都是基於此裝置的snapshot。兩個模式的區別就在與建立thin-pool的方法不同。
loop-lvm:
- 建立兩個稀疏檔案data和metadata
- 將這兩個檔案對映成兩個塊裝置(loopback塊裝置)
- 將兩個裝置通過核心中Device Mapper對映成thin-pool
注意!該模式不推薦用於生產環境,因為該模式在宿主機跑高密度容器數量的話,效能下降急劇,生產環境中一臺宿主機不可能只跑單個容器
direct-lvm:
(利用了基於Device Mapper的LVM)
- 將空餘塊裝置(可以是分割槽)建立成physical volume(pv)
- 在由這些PV組成volume group(vg)
- 從vg中建立兩個logical volume(lv),data和matedata
- 將data和matedata對映成thin-pool
*這些步驟可由已有指令碼docker-storage-setup自動執行,docker啟動前會自動執行該指令碼,指令碼位置/usr/bin/docker-storage-setup,只要在對應配置檔案中提供用於建立VG的PV(對應配置檔案中DEVS),或者提供已有的VG,便可讓指令碼自動執行上述步驟。具體可通過service docker-storage-setup status檢視,對應執行指令碼內有使用說明。也可手動建立(Configure direct-lvm mode forproduction)
以下通過一些命令區別兩種模式:
loop-lvm:
docker詳情
列出塊裝置
direct-lvm模式:
docker詳情
列出塊裝置
列出所有logical volume的資訊
六. 目錄相關
宿主機上容器、映象等儲存相關的主目錄:/var/lib/docker
[[email protected] docker]# tree ./
./
├── containers <---容器相關
│ ├──f1a04d3537edd5741f39ff262277362b35bbf17776fcafa31e67412f97e4d9f9
│ │ ├── config.json
│ │ ├──f1a04d3537edd5741f39ff262277362b35bbf17776fcafa31e67412f97e4d9f9-json.log
│ │ ├── hostconfig.json
│ │ ├── hostname
│ │ ├── hosts
│ │ ├── resolv.conf
│ │ ├── resolv.conf.hash
│ │ └── secrets
├── devicemapper <---儲存驅動相關
│ ├── metadata <---映象、容器對應塊裝置的元資料
│ │ ├──0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b
│ │ ├──05c2ea2d81bceeddc2881beb63d2ee26537593de9f47b4613c0d5afb1353f7df
│ │ ├──f1a04d3537edd5741f39ff262277362b35bbf17776fcafa31e67412f97e4d9f9
│ │ ├──f1a04d3537edd5741f39ff262277362b35bbf17776fcafa31e67412f97e4d9f9-init
│ │ ├──f6d195bba85ba6b9c075186ee62fe56f5d3b27e29ad9a31da8753820f3e2586b
│ │ ├──f6d195bba85ba6b9c075186ee62fe56f5d3b27e29ad9a31da8753820f3e2586b-init
│ │ ├── base
│ │ ├── deviceset-metadata
│ │ └── transaction-metadata
│ └── mnt <---容器對應裝置的掛載目錄,docker會自動mount和umount,所以手動開啟為空,可自行mount,對應裝置在/dev/mapper/
│ ├──0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b
│ ├──05c2ea2d81bceeddc2881beb63d2ee26537593de9f47b4613c0d5afb1353f7df
├── graph <---映象目錄,儲存映象層元資料
│ ├──0288ae931294ce04f5d69c60146faca7d9be8de4004421d650f4227fa60bd92b
│ │ ├── checksum <---映象校驗和,用於判斷映象是否損壞
│ │ ├── json <---描述映象基礎資訊
│ │ ├── layersize <---映象層大小
│ │ └── tar-data.json.gz <---描述映象層內檔案在磁碟中的位置
│ ├──05c2ea2d81bceeddc2881beb63d2ee26537593de9f47b4613c0d5afb1353f7df
│ │ ├── checksum
│ │ ├── json
│ │ ├── layersize
│ │ └── tar-data.json.gz
│ └── _tmp
├── linkgraph.db
├── repositories-devicemapper
├── tmp
├── trust
└── volumes