1. Device mapper和thinprovison
1) Devicemapper简介
Devicemapper是内核中支持逻辑卷管理的通用设备映射机制,它为实现用于存储资源管理的块设备驱动提供了一个高度模块化的内核架构,它包含三个重要的对象概念,Mapped Device、Mapping Table、Target device。
图1devicemapper映射机制
Mapped Device是一个抽象的逻辑设备,通过MappingTable描述的映射关系(Mapped Device 逻辑的起始地址、范围、和表示在 Target Device 所在物理设备的地址偏移量以及Target 类型等信息)和Target Device建立映射,Target Device表示的是Mapped Device所映射的物理空间段。DeviceMapper在内核中通过一个一个模块化的 Target Driver 插件实现对 IO 请求的过滤或者重新定向等工作,当前已经实现的插件包括软 Raid、加密、多路径、镜像、快照等。在这诸多“插件”中,有一个东西叫Thin Provisioning,这是Docker使用DeviceMapper中最重要的模块。Thin Provisoning就是精简分配,就是逻辑上给你分配了足够的空间,但是实际上是实报实销的,真正占用了多少空间就给你分配多少空间。Thin provison具备以下特点:
a. 允许多个虚拟设备存储在相同的数据卷中,从而达到共享数据,节省空间的目的;
b. Thin snapshot支持任意深度的快照。之前的实现的性能为O(n),新的实现通过一个单独的数据避免了性能随快照深度的增加而降低。
c. 支持元数据存储到单独的设备上。这样就可以将元数据放到镜像设备或者更快的SSD上。
Dm-thin的这些特点满足了Docker的存储驱动需要: 1.COW的功能 2. 镜像分层共享
2) dm thin演示
2. docker怎样用devicemapper
2.1 daemon第一次启动:创建thin-pool,thin-pool(名字是docker-dev-inode-pool,dev是/var/lib/docker/devicemapper所在块设备的设备号,inode是这个目录的inode),是基于块设备或者loop设备创建,块设备需要两个一个存放data,一个存放metadata(通过--storage-opt dm.datadev和--storage-optdm.metadatadev指定块设备)。如果没有块设备,就创建2个稀疏文件,用loop挂载的方式模拟成一个块设备。之后从thin-pool中创建.一个base设备,对这个base设备做mkfs。块设备的元数据存放在/var/lib/docker/devicemapp/metadata目录下。
2.2创建镜像,基于base做snapshot创建一个新的dm设备,将这个dm设备挂载到/var/lib/docker/devicemapper/mnt目录下,将层的数据解压到该目录下。第二层基于第一层做snapshot。所有的新镜像都是基于base设备做snapshot,然后一层一层做snapshot生成最终镜像的dm设备。
图1 image
2.3 创建容器,容器基于镜像的dm设备做snapshot先生成init设备(init设备是容器的初始层,会在该层里生成一些运行时需要的文件和目录,比如/dev/pts /dev/shm /proc /sys 等)。真正容器的dm设备基于init设备做snapshot。
图2 container
Devicemapper读:
a. 容器中的一个应用要读0x44f块的内容,由于容器的dm设备是基于镜像的snapshot,所以里面没有这个数据,但是它有一个指针指向这个块数据在镜像dm设备的位置,如图中所示,0x44f这个块的内容在a005e这个设备的0xf33块上。
b. 从镜像a005e中读取0xf33块的内容到内存中,把内容返回给应用。(不能内存共享的原因?)。因为镜像很多层,所以不一定在镜像的最上层就能找到,如果找不到依次往下找。
图3 read
Devicemapper写:
a. 应用要写一个56K的数据
b. Thin-pool的写时分配机制就给这个dm分配一个64K的块,如果要写更多的数据就分配更多的块。
Devicemapper改:
a. 第一次修改容器中原来存在的数据(镜像中的数据),先找到要改的数据块;
b. COW机制把要修改的数据从底层拷贝到R/W层(也就是容器的dm设备),然后进行修改。
3 容器的dm操作流程
创建->激活->挂载->卸载->注销->删除
4 Docker devicemapper常用配置
4.1 配置direct lvm的方法:
方式一:
1) 如果docker已经使用其他graphdriver方式启动了(默认是devicemapper+loopback,安装完后默认是使用这种方式启动),先停止docker daemon
sevice dockerstop
然后删除/var/lib/docker目录(如果已有镜像和容器,先备份好再删除)
$ sudo rm -rf/var/lib/docker
2)基于系统上的一个块设备创建一个lvm物理卷
$ sudo pvcreate /dev/xvdf
Physical volume `/dev/xvdf`successfully created
将/dev/xvdf替换成自己系统上的块设备。
3)使用刚才创建的物理卷创建一个卷组
$ sudo vgcreate vg-docker /dev/xvdf
Volume group `vg-docker` successfully created
4)在第3步创建的vg-docker卷组中创建90GB大小的逻辑卷data
$ sudo lvcreate -L 90G -n data vg-docker
Logical volume `data` created.
这个命令行创建了一个lvm的逻辑卷data,创建成功后可以在主机上看到/dev/vg-docker/data这个文件。
5) 在vg-docker卷组中创建4GB大小的逻辑卷metadata
$ sudo lvcreate -L 4G -n metadata vg-docker
Logical volume `metadata` created.
同样,创建成功后,可以在主机上看到/dev/vg-docker/metadata这个文件
6)配置daemon
在daemon的启动参数中加上以下:
-s devicemapper --storage-opt dm.datadev=/dev/vg-docker/data --storage-optdm.metadatadev=/dev/vg-docker/metadata
方式二:
参考文档:
https://docs.docker.com/engine/userguide/storagedriver/device-mapper-driver/#configure-direct-lvm-mode-for-production
1) 基于块设备创建物理卷
$ pvcreate/dev/xvdf
2) 创建一个docker卷组
vgcreate docker /dev/xvdf
3) 从卷组里创建两个逻辑卷
$ lvcreate--wipesignatures y -n thinpool docker -l 95%VG
$ lvcreate--wipesignatures y -n thinpoolmeta docker -l 1%VG
4) 基于这两个逻辑卷创建thin-pool
$ lvconvert-y --zero n -c 512K--thinpool docker/thinpool --poolmetadata docker/thinpoolmeta
5) 配置lvm的配置文件
$ vi/etc/lvm/profile/docker-thinpool.profile
参考的docker-thinpool.profile为:
activation{
thin_pool_autoextend_threshold=80
thin_pool_autoextend_percent=20
}
注:这一步不是必须的,如果系统上没有空间给docker做自动扩展就不要设置这个不然会导致已经启动容器的dm设备被umount。
6) 使配置生效
$ lvchange--metadataprofiledocker-thinpool docker/thinpool
7) 检测lv的监控是否生效
$ lvs-o+seg_monitor
4.2 扩容(针对direct lvm方式)
1) 扩容docker用的卷组
$ sudovgextend vg-docker /dev/sdh1
Volume group "vg-docker" successfully extended
2) 扩容thin-pool的data卷
$ sudolvextend -l+100%FREE -n vg-docker/data
Extending logical volume data to 200GiB Logical volume data successfully resized
3) 更改thin-pool的映射表
a. 获取原有映射表
dmsetup table docker-253:17-1835016-pool
0 96460800 thin-pool 252:0 252:1 128 32768 1 skip_block_zeroing
b. 计算扩容后的扇区大小
blockdev --getsize64 /dev/vg-docker/data
264132100096
这个值是字节,要除以512,所以要扩容的总扇区数为
c. Reload映射表
dmsetup suspend docker-253:17-1835016-pool \ &&sudo dmsetup reload docker-253:17-1835016-pool --table '0 515883008 thin-pool252:0 252:1 128 32768 1 skip_block_zeroing' \ && sudo dmsetup resumedocker-253:17-1835016-poo
4.3额外常用参数的配置
5 Dmsetup常用命令
dmsetup status 查看dm状态,主要用来查看thin-pool是否正常。
dmsetup table 获取映射表
dmsetup remove 删除thin-pool
6 thin相关的命令
(加上issue的那个修复案例)
http://code.huawei.com/docker/docker/issues/63
系统异常掉电后,docker起不来报thin-pool相关的错误,此时可能是元数据卷损坏,此时可以用thin相关工具来修复。
a) 先用thin_check检测metada卷是否正常
thin_check vg--docker-metadata
如果正常的话应该是有类似如下的输出:
examining superblock
examining devices tree
examining mapping tree
如果有异常,则进行以下步骤进行修复
b) Dump映射表
thin_dump --repair /dev/mapper/metadata > meta.xml
c) Restore映射表
thin_restore -o metadata -i meta.xml
Restoring:[=================================================] \ 100%