Device Mapper 介紹
Device Mapper 是 Linux2.6 內核中支持邏輯卷管理的通用設備映射機制,它爲實現用於存儲資源管理的塊設備驅動提供了一個高度模塊化的內核架構。整個 device mapper 機制由兩部分組成:
- 內核部分:主要提供完成存儲策略所需要的機制
- 用戶空間部分:device mapper 庫以及它提供的 dmsetup 工具
內核部分包含三個重要的對象概念,Mapped Device、Mapping Table、Target device。
-
Mapped Device:是一個邏輯抽象,可以理解成爲內核向外提供的邏輯設備,它通過Mapping Table描述的映射關係和 Target Device 建立映射;
-
Mapping Table:存有 Mapped Device 邏輯的起始地址、範圍、和表示在 Target Device 所在物理設備的地址偏移量以及Target 類型等信息;
-
Target device:表示的是 Mapped Device 所映射的物理空間段,對 Mapped Device 所表示的邏輯設備來說,就是該邏輯設備映射到的一個物理設備;
Device Mapper在內核中通過一個一個模塊化的 Target Driver 插件實現對 IO 請求的過濾或者重新定向等工作,當前已經實現的插件包括軟 Raid、加密、多路徑、鏡像、快照等,在這諸多“插件”中,有一個東西叫Thin Provisioning Snapshot
,這是Docker使用Device Mapper中最重要的模塊,稱爲devicemapper存儲驅動
,它利用Device Mapper框架的精簡置備和快照功能來管理鏡像和容器。
Thin Provisioning Snapshot 簡介
先說一下 Thin Provisioning
技術,這個技術是虛擬化技術中的一種,實現對存儲空間的”超賣“能力。
而Docker使用了Thin Provisioning的Snapshot
的技術,在 docker 啓動時,會在精簡池(Thin Pool)中創建一個具有文件系統的 Base 設備,每一個新鏡像
(和鏡像數據層)是這個 base 設備的一個快照,而容器
數據層又是從其鏡像創建的快照。
快照是寫時複製(CoW)策略的實現,這意味着給定的文件或目錄只有在容器被修改或刪除時纔會被複制到容器的可寫層。
配置 direct-lvm 模式用於生產環境
docker默認安裝時,devicemapper存儲驅動程序配置的是loop-lvm模式,該模式使用兩個稀疏文件作爲迴環設備,來存儲鏡像和容器的數據和元數據:
/var/lib/docker/devicemapper/devicemapper/data
/var/lib/docker/devicemapper/devicemapper/metadata
由於迴環設備速度慢且資源密集,生產環境建議使用direct-lvm 模式。
做以下步驟(轉自)前,請先停止docker。
1.由於使用的是虛擬機,先創建個新的分區(或其他塊設備):
$ fdisk /dev/sda
按提示創建一個新的分區: /dev/sda4
2.通過pvcreate
命令在 /dev/sda4塊設備上創建物理卷pv:
$ pvcreate /dev/sda4
Physical volume "/dev/sda4" successfully created.
3.通過 vgcreate 命令在同一個設備上創建名爲 docker的卷組vg:
$ vgcreate docker /dev/sda4
Volume group "docker" successfully created
4.通過 lvcreate 命令創建兩個名爲 thinpool 和 thinpoolmeta 的邏輯卷lv:
最後一個參數指定可用空間的大小,以便在空間不足時自動擴展數據或元數據。這些是推薦值。
$ lvcreate --wipesignatures y -n thinpool docker -l 95%VG
Logical volume "thinpool" created.
$ lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
Logical volume "thinpoolmeta" created.
5.通過 lvconvert 命令把thinpool
數據卷和thinpoolmeta
元數據卷換爲精簡池(Thin Pool):
$ lvconvert -y \
--zero n \
-c 512K \
--thinpool docker/thinpool \
--poolmetadata docker/thinpoolmeta
Thin pool volume with chunk size 512.00 KiB can address at most 126.50 TiB of data.
WARNING: Converting docker/thinpool and docker/thinpoolmeta to thin pool's data and metadata volumes with metadata wiping.
THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)
Converted docker/thinpool and docker/thinpoolmeta to thin pool.
6.通過 lvm 配置文件配置精簡池的自動擴展:
$ vi /etc/lvm/profile/docker-thinpool.profile
指定 thin_pool_autoextend_threshold 和 thin_pool_autoextend_percent 的值。
-
thin_pool_autoextend_threshold 是觸發 lvm 嘗試自動擴展可用空間的空間使用率百分比(100 = 禁用,不推薦)。
-
thin_pool_autoextend_percent 是觸發自動擴展時會擴展的大小(0 = 禁用)。
下面的例子在磁盤使用率達到 80% 時自動增加 20% 的容量:
activation {
thin_pool_autoextend_threshold=80
thin_pool_autoextend_percent=20
}
7.使用 lvchange 命令應用 LVM 配置文件:
$ lvchange --metadataprofile docker-thinpool docker/thinpool
Logical volume docker/thinpool changed.
8.啓用對主機上邏輯卷的監視:
沒有這一步,即使存在 LVM 配置文件,也不會自動擴展。
$ lvs -o+seg_monitor
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert Monitor
thinpool docker twi-a-t--- <19.00g 0.00 0.03 monitored
9.如果之前在這個主機上運行過 Docker,或 /var/lib/docker/ 文件已經存在,移除文件以便讓 Docker 使用新的 LVM pool 來存儲鏡像和容器:
$ mkdir /var/lib/docker.bk
$ mv /var/lib/docker/* /var/lib/docker.bk
10.編輯 /etc/docker/daemon.json 並配置 devicemapper存儲驅動程序所需的選擇。增加下面的內容:
{
"storage-driver": "devicemapper",
"storage-opts": [
"dm.thinpooldev=/dev/mapper/docker-thinpool",
"dm.use_deferred_removal=true",
"dm.use_deferred_deletion=true"
]
}
11.啓動 Docker:
$ systemctl start docker
12.通過 docker info 命令驗證 Docker 使用了新的配置:
$ docker info
Client:
Debug Mode: false
Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 19.03.8
Storage Driver: devicemapper
Pool Name: docker-thinpool
Pool Blocksize: 524.3kB
Base Device Size: 10.74GB
Backing Filesystem: xfs
Udev Sync Supported: true
Data Space Used: 20.45MB
Data Space Total: 20.4GB
Data Space Available: 20.38GB
Metadata Space Used: 61.44kB
Metadata Space Total: 213.9MB
Metadata Space Available: 213.8MB
Thin Pool Minimum Free Space: 2.039GB
......
如果 Docker 配置正確,Pool Name 應該是 docker-thinpool
。
13.可以使用lsblk命令從操作系統角度查看設備和對應的池:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 41G 0 disk
├─sda1 8:1 0 300M 0 part /boot
├─sda2 8:2 0 2G 0 part [SWAP]
├─sda3 8:3 0 17.7G 0 part /
└─sda4 8:4 0 20G 0 part
├─docker-thinpool_tmeta 253:0 0 204M 0 lvm
│ └─docker-thinpool 253:2 0 19G 0 lvm
└─docker-thinpool_tdata 253:1 0 19G 0 lvm
└─docker-thinpool 253:2 0 19G 0 lvm
sr0 11:0 1 1024M 0 rom
dmsetup 工具
命令參考:dmsetup - Unix, Linux Command
常用參數:
dmsetup info [device_name]
: 輸出所有目前配置的 Device Mapper 設備信息dmsetup ls
: 命令列出映射的設備的設備名稱列表dmsetup status [device_name]
: 輸出結果是所有目前配置的設備映射器設備信息dmsetup message device_name sector message
: 給設備發送消息dmsetup create device_name --table "0 20971520 thin 253:3 185"
: 創建dm設備dmsetup remove device_name
: 移除dm設備
dmsetup 工具的使用
查看運行容器、鏡像的device信息
獲取容器的DeviceName:
$ docker inspect ba3ee5be798c | grep DeviceName
"DeviceName": "docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4",
其中docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4
即爲dm設備的名字。
查看Mapping Table:
$ dmsetup table | grep docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4
docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4: 0 20971520 thin 253:3 163
或
dmsetup table docker-253:2-2016050192-752dc1a74ce95c22dae84e257aa02119bb1da1feb1a6ff372d4ad9db08cf7bd4
0 20971520 thin 253:3 163
其中0 20971520 thin 253:3 163
的解釋爲:
logical_start_sector num_sectors target_type target_args
開始扇區 扇區數 設備類型 設備參數
0 20971520 thin 253:3 163
20971520
爲扇區數,一個扇區大小爲512kb,總共爲10g
即:20971520個扇區 = 20971520*512kb = 10,737,418,240kb = 10 * 2^30 kb = 10g
取出鏡像的文件
查看鏡像的Device信息
$ docker inspect centos | grep Device
"DeviceId": "13",
"DeviceName": "docker-8:3-36654382-89b4c8a4c8d56fde69622bc6e8df5f402eebf4b0f026966b56c65de7cd4517c0",
"DeviceSize": "10737418240"
使用dmsetup ls
命令查看docker-thinpool
設備的主設備號和次設備號
$ dmsetup ls
centos-dm (253:4)
docker-thinpool_tdata (253:1)
docker-thinpool_tmeta (253:0)
docker-thinpool (253:2)
得到主設備號和次設備號爲253:2
生成Mapping Table:0 20971520 thin 253:2 13
- 0 : 開始扇區
- 20971520 : 刪除數,由DeviceSize除以每個扇區的大小得到,即 10737418240/512 = 20971520
- thin : 設備類型
- 253:2 13 : 設備參數,由
[主設備號]:[次設備號] [DeviceId]
組成
創建dm設備:
dmsetup create centos-dm --table "0 20971520 thin 253:2 13"
再次使用dmsetup ls
命令,發現新增的名爲centos-dm
的dm設備:
$ dmsetup ls
centos-dm (253:4)
docker-thinpool_tdata (253:1)
docker-thinpool_tmeta (253:0)
docker-thinpool (253:2)
查看/dev/mapper目錄,發現新增了1個鏈接文件,鏈接到dm-4設備
$ ll /dev/mapper
lrwxrwxrwx. 1 root root 7 Apr 26 02:55 centos-dm -> ../dm-4
把dm-4設備掛載出來
$ mount /dev/dm-4 /tmp/test
查看掛載:
$ mount | grep centos-dm
/dev/mapper/centos-dm on /tmp/test type xfs (rw,relatime,seclabel,attr2,inode64,sunit=1024,swidth=1024,noquota)
查看鏡像文件:
$ ll /tmp/test
total 8
-rw-------. 1 root root 64 Apr 23 01:05 id
drwxr-xr-x. 14 root root 4096 Apr 23 01:05 rootfs
rootfs目錄中即爲鏡像裏的文件:
$ ll /tmp/test/rootfs/
lrwxrwxrwx. 1 root root 7 Apr 6 2017 bin -> usr/bin
drwxr-xr-x. 47 root root 4096 Apr 6 2017 etc
drwxr-xr-x. 2 root root 6 Nov 5 2016 home
lrwxrwxrwx. 1 root root 7 Apr 6 2017 lib -> usr/lib
lrwxrwxrwx. 1 root root 9 Apr 6 2017 lib64 -> usr/lib64
drwx------. 2 root root 6 Apr 6 2017 lost+found
drwxr-xr-x. 2 root root 6 Nov 5 2016 media
drwxr-xr-x. 2 root root 6 Nov 5 2016 mnt
取出運行中/停掉的容器中的內容
使用docker inspect
命令查看容器的device信息:
$ docker inspect {containerId} | grep Device
"DeviceId": "21",
"DeviceName": "docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c",
"DeviceSize": "10737418240"
之後的步驟與取出鏡像的文件
的方法相同。
給運行中的容器進行快照
使用docker inspect
命令查看容器的DeviceName和DeviceId:
$ docker inspect {containerId} | grep Device
"DeviceId": "21",
"DeviceName": "docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c",
"DeviceSize": "10737418240"
向dm設備發送create_snap
的消息:
dmsetup message /dev/mapper/docker-thinpool 0 "create_snap 22 21"
其中:
- 21 : 爲容器的DeviceId
- 22 : 爲自定的目標DeviceId
使用dmsetup create
命令創建dm設備:
$ dmsetup create dockersnap --table "0 20971520 thin /dev/mapper/docker-thinpool 22"
使用dmsetup ls
命令,發現新增的名爲dockersnap
的dm設備:
$ dmsetup ls
centos-dm (253:4)
docker-thinpool_tdata (253:1)
docker-thinpool_tmeta (253:0)
docker-thinpool (253:2)
docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c (253:3)
dockersnap (253:5)
接下來即可使用之前的步驟mount出來。
devicemapper存儲驅動下統計容器使用量
由於容器啓動後會對鏡像進行一次快照,並mount到一個掛載點(在/var/lib/docker/devicemapper/mnt
目錄中),可以考慮使用df
命令結果裏的Used
字段:
$ df -hT
Filesystem Type Size Used Avail Use% Mounted on
/dev/sda3 xfs 18G 4.5G 14G 26% /
devtmpfs devtmpfs 1.9G 0 1.9G 0% /dev
tmpfs tmpfs 1.9G 0 1.9G 0% /dev/shm
tmpfs tmpfs 1.9G 9.1M 1.9G 1% /run
tmpfs tmpfs 1.9G 0 1.9G 0% /sys/fs/cgroup
/dev/sda1 xfs 297M 144M 154M 49% /boot
tmpfs tmpfs 378M 0 378M 0% /run/user/0
/dev/dm-3 xfs 10G 57M 10G 1% /var/lib/docker/devicemapper/mnt/804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c
可以看到/dev/dm-3
對應的掛載點/var/lib/docker/devicemapper/mnt/804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c
,其Used
值爲57M。
掛載點路徑中有一串很長的hash串,這個串與DeviceName
中hash串相對應:
$ docker inspect 17a65165d9b6 | grep DeviceName
"DeviceName": "docker-8:3-36654382-804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c",
由於格式化後的xfs
文件系統自身的metadata也會佔用一定空間,所以這個Used
值往往比mount出的目錄要大(使用du
命令進行統計):
$ cd \
/var/lib/docker/devicemapper/mnt/804429bdfdec16a1a3d6f3e5fbbb3dcbc4494997b8d392c83a37aead924a398c
$ du -sh *
4.0K id
24M rootfs
可見mount出的目錄的總大小爲24M,並不與Used
值相同。
當然,這個差異也與df
與du
命令的統計方法有關。
注意:在啓動容器時使用-v
參數掛載出來的目錄或文件,都不包含在df
與du
命令的統計結果中。