Docker Devicemapper存储介绍

Device Mapper简介

DeviceMapper自Linux 2.6被引入。它在内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核和架构,包含三个重要的对象概念,MapperDevice,Mapping Table, Target device。

Mapped Device 是一个逻辑抽象,可以理解成为内核向外提供的逻辑设备,它通过Mapping Table描述的映射关系和Target Device建立映射。Target device表示的是Mapped Device所映射的物理空间段,对Mapped Device所表示逻辑设备来收,就是该逻辑设备映射到的一个物理设备。

Mapping Table里有 Mapped Device 逻辑的起始地址、范围、和表示在 Target Device 所在物理设备的地址偏移量以及Target 类型等信息(注:这些地址和偏移量都是以磁盘的扇区为单位的,即 512 个字节大小,所以,当你看到128的时候,其实表示的是128*512=64K)。

DeviceMapper 中的逻辑设备Mapped Device不但可以映射一个或多个物理设备Target Device,还可以映射另一个Mapped Device,于是,就是构成了一个迭代或递归的情况,就像文件系统中的目录里除了文件还可以有目录,理论上可以无限嵌套下去。

devicemapper驱动将每一个Docker镜像和容器存储在它自身的具有精简置备(thin-provisioned)、写时拷贝(copy-on-write)和快照功能(snapshotting)的虚拟设备上。由于Device Mapper技术是在块(block)层面而非文件层面,所以Docker Engine的devicemapper存储驱动使用的是块设备来存储数据而非文件系统。

Thin Provisioning 精简配置

Thinprovisioning.jpg

Docker使用了Thin Provisioning的Snapshot的技术实现分层镜像,

Thin Provisioning Snapshot 演示

首先,我们需要先建两个文件,一个是data.img,一个是meta.data.img:

[root@localhost ~]#  dd if=/dev/zero of=/tmp/data.img bs=1K count=1 seek=10M
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.000172451 s, 5.9 MB/s
[root@localhost ~]# dd if=/dev/zero of=/tmp/meta.data.img bs=1K count=1 seek=1G
1+0 records in
1+0 records out
1024 bytes (1.0 kB) copied, 0.000164882 s, 6.2 MB/s

注意命令中seek选项,表示略过of选项指定得输出文件得前10M个output的blocksize的空间后再写入内容。因为bs是1个字节,所以是10G的大小,但其实在硬盘上没有占用空间的,占有空间只有1k的内容。直到写入内容时,才会在硬盘上分配空间。
用ls命令查看

[root@localhost tmp]# ls -lsh /tmp/data.img
4.0K -rw-r--r--. 1 root root 11G Jan 25 20:27 /tmp/data.img
[root@localhost tmp]# ls -lsh /tmp/meta.data.img
4.0K -rw-r--r--. 1 root root 1.1T Jan 25 20:27 /tmp/meta.data.img

创建loopback设备。

[root@localhost tmp]# losetup /dev/loop2015 /tmp/data.img
[root@localhost tmp]# losetup /dev/loop2016 /tmp/meta.data.img

[root@localhost tmp]# losetup -a
/dev/loop2015: [64768]:16788486 (/tmp/data.img)
/dev/loop2016: [64768]:16788157 (/tmp/meta.data.img)

为这个设备建一个Thin Provisioning的Pool, 用dmsetup命令:

[root@localhost tmp]# dmsetup create test-thin-pool \
    --table "0 20971522 thin-pool /dev/loop2016 /dev/loop2015 \
    128 65536 1 skip_block_zeroing"

参数解释如下(更多信息参看man pnage):

  • dmsetup create 创建thin pool的命令
  • test-thin-pool是自定义的一个pool名,不冲突就好。
  • table是这个pool的参数设置
    • 0代表起的sector位置
    • 20971522代码结句的sector号,前面说过,一个sector是512字节,所以,20971522个正好是10GB
    • /dev/loop2016是meta文件的设备
    • /dev/loop2015是data文件的设备
    • 128是最小的可分配的sector数
    • 65536是最少可用sector的water mark,也就是一个threshold
    • 1 代表有一个附加参数
    • skip_block_zeroing是个附加参数,表示略过用0填充的块

然后,就可以看到一个Device Mapper的设备:

[root@localhost tmp]# ll /dev/mapper/test-thin-pool
lrwxrwxrwx. 1 root root 7 Jan 25 20:30 /dev/mapper/test-thin-pool -> ../dm-2

接下来,创建一个Thin Provisioning的Volume:

[root@localhost tmp]# dmsetup message /dev/mapper/test-thin-pool 0 "create_thin 0"
[root@localhost tmp]# dmsetup create test-thin-volumn-001 --table "0 2097152 thin /dev/mapper/test-thin-pool 0"

期中:

  • 第一个命令中的create_thin是关键字,后面的0表示这个Volume的device的id
  • 第二个命令,是真正的为这个Volumn创建一个可以mount的设备,名字叫test-thin-volumn-001。 2091512只有1GB。

在mount前,格式化一下:

[root@localhost tmp]# mkfs.ext4 /dev/mapper/test-thin-volumn-001
mke2fs 1.42.9 (28-Dec-2013)
Discarding device blocks: done
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
Stride=16 blocks, Stripe width=16 blocks
65536 inodes, 262144 blocks
13107 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=268435456
8 block groups
32768 blocks per group, 32768 fragments per group
8192 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

可以挂载了

[root@localhost tmp]# mkdir /mnt/base
[root@localhost tmp]# mount /dev/mapper/test-thin-volumn-001 /mnt/base
[root@localhost tmp]# echo "hello, im am a base" > /mnt/base/id.txt
[root@localhost tmp]# cat /mnt/base/id.txt
hello, im am a base

创建snapshot:

[root@localhost tmp]# dmsetup message /dev/mapper/test-thin-pool 0 "create_snap 1 0"
[root@localhost tmp]# dmsetup create mysnap1 --table "0 2097152 thin /dev/mapper/test-thin-pool 1"

挂载snapshot:

[root@localhost tmp]# ll /dev/mapper/mysnap1
lrwxrwxrwx. 1 root root 7 Jan 25 20:37 /dev/mapper/mysnap1 -> ../dm-4
[root@localhost tmp]# mkdir /mnt/mysnap1
[root@localhost tmp]# mount /dev/mapper/mysnap1 /mnt/mysnap1/
[root@localhost tmp]# ls /mnt/mysnap1/
id.txt  lost+found
[root@localhost tmp]# cat /mnt/mysnap1/id.txt
hello, im am a base
[root@localhost tmp]# echo >> i am snap1 >> /mnt/mysnap1/id.txt
[root@localhost tmp]# echo i am snap1 >> /mnt/mysnap1/id.txt
[root@localhost tmp]# cat /mnt/mysnap1/id.txt
hello, im am a base
am snap1
i am snap1

我们再看下/mnt/base,没有新加的内容。

[root@localhost tmp]# cat /mnt/base/id.txt
hello, im am a base

我们能看到分层镜像的样子了。

Docker存储驱动devicemapper

devicemapper是RHEL的Docker Engine的默认存储驱动,有两种配置模式:loop-lvm和direct-lvm。
loop-lvm是默认的模式,它使用OS层面离散的文件来构建精简池(thin pool)。该模式主要是设计出来让Docker能够简单的被”开箱即用(out-of-the-box)”而无需额外的配置。但如果是在生产环境的部署Docker,官方明文不推荐使用该模式。
direct-lvm是Docker推荐的生产环境的推荐模式,他使用块设备来构建精简池来存放镜像和容器的数据。

自动配置

自动配置docker的devicemapper的存储驱动,需要一块独立的块设备,比如/dev/sdb。

[root@localhost ~]# fdisk -l
...
...
Disk /dev/sdb: 53.7 GB, 53687091200 bytes, 104857600 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x0007eabf

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1            2048   104857599    52427776   8e  Linux LVM

全新安装的docker,启动服务前,修改配置文件/etc/sysconfig/docker-storage-setup

DEVS="/dev/sdb"
VG=docker-vg
DATA_SIZE=100%FREE

说明一下:

  • DEVS是独立的快设备名
  • VG是vg的名字
  • DATA_SIZE默认50%,这里设定是100%FREE

启动docker后,devicemapper的存储卷就创建成功了。

[root@node1 ~]# lvs
  LV          VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  docker-pool docker-vg twi-aot---  49.89g             24.35  6.20
  lv_01       root_vg01 -wi-ao---- <41.00g

手动配置

如果没有独立的磁盘块设备,可以在系统中的磁盘设备上空闲的块空间配置。

  1. 查看设备名,我们假定是/dev/xvdf
  2. 停止docker
# systemctl stop docker
  1. 安装包
yum install device-mapper-persistent-data lvm2 -y
  1. 创建pv
# pvcreate /dev/xvdf
Physical volume "/dev/xvdf" successfully created.
  1. 创建dockervg
# vgcreate docker /dev/xvdf
Volume group "docker" successfully created
  1. 创建两个lv thinpoolthinpoolmeta
# sudo lvcreate --wipesignatures y -n thinpool docker -l 95%VG

Logical volume "thinpool" created.

# sudo lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG

Logical volume "thinpoolmeta" created.
  1. 把lv转换成thin pool和metadata
# sudo lvconvert -y \
--zero n \
-c 512K \
--thinpool docker/thinpool \
--poolmetadata docker/thinpoolmeta

WARNING: Converting logical volume 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 to thin pool.
  1. 通过lvm profile配置自动扩容
# vi /etc/lvm/profile/docker-thinpool.profile
  1. 指定thin_pool_autoextend_thresholdthin_pool_autoextend_percent值。

当磁盘使用率达到80%,增加20%的容量.

activation {
  thin_pool_autoextend_threshold=80
  thin_pool_autoextend_percent=20
}
  1. 应用LVM profile.
sudo lvchange --metadataprofile docker-thinpool docker/thinpool

Logical volume docker/thinpool changed.
  1. 启用LV的监控
# sudo lvs -o+seg_monitor

LV       VG     Attr       LSize  Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor
thinpool docker twi-a-t--- 95.00g             0.00   0.01                             monitored
  1. 如果之前运行过docker,先备份
# mv /var/lib/docker /var/lib/docker.bk
  1. 编辑/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"
    ]
}
  1. 启动docker
# systemctl start docker
  1. 验证
# docker info

Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 0
Server Version: 17.03.1-ce
Storage Driver: devicemapper
 Pool Name: docker-thinpool
 Pool Blocksize: 524.3 kB
 Base Device Size: 10.74 GB
 Backing Filesystem: xfs
 Data file:
 Metadata file:
 Data Space Used: 19.92 MB
 Data Space Total: 102 GB
 Data Space Available: 102 GB
 Metadata Space Used: 147.5 kB
 Metadata Space Total: 1.07 GB
 Metadata Space Available: 1.069 GB
 Thin Pool Minimum Free Space: 10.2 GB
 Udev Sync Supported: true
 Deferred Removal Enabled: true
 Deferred Deletion Enabled: true
 Deferred Deleted Device Count: 0
 Library Version: 1.02.135-RHEL7 (2016-11-16)
<output truncated>

Data fileMetadata file是空的,pool名字是docker-thinpool

device mapper在Docker中的性能表现

device mapper的性能主要受“需要时分配”策略和“写时复制”策略影响,下面分别介绍:

需要时分配(allocate-on-demand)

device mapperdriver通过allocate-on-demand策略为需要写入的数据分配数据块。也就是说,每当容器中的进程需要向容器写入数据时,device mapper就从资源池中分配一些数据块并将其映射到容器。
当容器频繁进行小数据的写操作时,这种机制非常影响影响性能。
一旦数据块被分配给了容器,对它进行的读写操作都直接对块进行操作了。

写时复制(copy-on-write)

与aufs一样,device mapper也支持写时复制策略。容器中第一次更新某个文件时,device mapper调用写时复制策略,将数据块从镜像快照中复制到容器快照中。
device mapper的写时复制策略以64KB作为粒度,意味着无论是对32KB的文件还是对1GB大小的文件的修改都仅复制64KB大小的文件。这相对于在文件层面进行的读操作具有很明显的性能优势。
但是,如果容器频繁对小于64KB的文件进行改写,device mapper的性能是低于aufs的。

存储空间使用效率

device mapper不是最有效使用存储空间的storage driver,启动n个相同的容器就复制了n份文件在内存中,这对内存的影响很大。所以device mapper并不适合容器密度高的场景。

参考

本文参考和节选了以下文章:

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Device Mapper 简介 DeviceMapper自Linux 2.6被引入成为了Linux最重要的一个技...
    51reboot阅读 3,646评论 0 3
  • devicemapper驱动将每一个 Docker镜像 和容器存储在它自身的具有精简置备(thin-provisi...
    jianweixs阅读 4,767评论 0 0
  • 一、Docker 简介 Docker 两个主要部件:Docker: 开源的容器虚拟化平台Docker Hub: 用...
    R_X阅读 4,377评论 0 27
  • Docker Docker这两年可谓大红大紫,仿佛一夜之间,街坊邻居茶余饭后都在说Docker,我这也掰扯掰扯Do...
    jony456123阅读 562评论 0 1
  • 作者:记渡——夭夭 1 星期五的晚上,7点钟,如往常一样,我和方素相约在他们公司附近的“茶马天下”吃云南菜,犒劳这...
    记渡阅读 362评论 0 0