Docker使用devicemapper存储驱动

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值相同。

当然,这个差异也与dfdu命令的统计方法有关。

注意:在启动容器时使用-v参数挂载出来的目录或文件,都不包含在dfdu命令的统计结果中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值