docker深入2-存储驱动之使用devicemapper(direct-lvm)模式

2017/8/10


一、存储概述
1、如何选择驱动
参考:https://docs.docker.com/engine/userguide/storagedriver/selectadriver/#supported-backing-filesystems
每个存储方式都有优缺点,要根据实际的项目来选择:


首先,如果使用的操作系统内核支持多个驱动,则 Docker 将按照下述优先级来选择默认的存储驱动(如果没有显式的去配置存储驱动):
-> 如果支持 aufs 则选它,因为这是最老的驱动,尽管它不是普遍存在的。
-> 如果可能,选择只需尽量少的配置即可使用的驱动,例如 btrfs or zfs(要确保后端文件系统已经配置好)
-> 最后,将尝试使用再性能和稳定性上最通用的驱动
----> overlay2 是优先级最高的,其次是 overlay,这2个都不用配置。 
----> devicemapper 其次,但生产环境使用时,要配置为 direct-lvm 的方式,因为默认的 loopback-lvm 尽管不用配置,但性能超级差。

上述选择可查阅源码 Docker 17.03 (https://github.com/moby/moby/blob/v17.03.1-ce/daemon/graphdriver/driver_linux.go#L54-L63)


其次,要适合自己的业务场景的负载
aufs, overlay, and overlay2 文件级别的存储,更有效的利用内存,但容器的 writable layer 再写io压力大时,增加较快。
devicemapper, btrfs, and zfs 更擅长应对写io较大的业务
overlay 比 overlay2 更擅长处理小文件的写,大量 layers,文件系统路径很深的场景
btrfs and zfs 需要更多内存
zfs 是高负载的一个较好选择,例如应用到PaaS上


2、支持的文件系统
存储驱动                支持的文件系统          限制
---------------------------------------------------------------
overlay, overlay2       ext4, xfs               仅支持docker-ce,overlay2要求使用4.0以及更高的linux内核
aufs                    ext4, xfs
devicemapper            direct-lvm
btrfs                   btrfs
zfs                     zfs


3、docker-ce 测试过的操作系统和存储驱动:
操作系统                        支持的存储驱动
---------------------------------------------------------------
Docker CE on Ubuntu             aufs, devicemapper, overlay2 (Ubuntu 14.04.4 or later, 16.04 or later, Version 4.0 or higher of the Linux kernel), overlay, zfs
Docker CE on Debian             aufs, devicemapper, overlay2 (Debian Stretch, Version 4.0 or higher of the Linux kernel), overlay
Docker CE on RHEL/CentOS        devicemapper, overlay
Docker CE on Fedora             devicemapper, overlay2 (Fedora 26 or later, experimental), overlay (experimental)



二、现状
新版本(docker-ce)简化了dm方式的操作:

mkdir -p /etc/docker
tee /etc/docker/daemon.json <<-'EOF' 
{
  "storage-driver": "devicemapper",
  "storage-opts": [
    "dm.directlvm_device=/dev/sdb",
    "dm.thinp_percent=95",
    "dm.thinp_metapercent=1",
    "dm.thinp_autoextend_threshold=80",
    "dm.thinp_autoextend_percent=20",
    "dm.directlvm_device_force=false" 
  ],
  "registry-mirrors": ["https://xxxx.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload
systemctl restart docker



三、以前的方式是这样的(2016/12/9之前的doc,留作参考原理)
1、默认使用的是 devicemapper(loop-lvm)
[root@n33 lib]# docker info     
(略)        
Server Version: 1.12.3
Storage Driver: devicemapper
 Pool Name: docker-253:3-33517-pool
 Pool Blocksize: 65.54 kB
 Base Device Size: 10.74 GB
 Backing Filesystem: xfs
 Data file: /dev/loop0
 Metadata file: /dev/loop1
 Data Space Used: 11.8 MB
 Data Space Total: 107.4 GB
 Data Space Available: 7.433 GB
 Metadata Space Used: 581.6 kB
 Metadata Space Total: 2.147 GB
 Metadata Space Available: 2.147 GB
 Thin Pool Minimum Free Space: 10.74 GB
 Udev Sync Supported: true
 Deferred Removal Enabled: false
 Deferred Deletion Enabled: false
 Deferred Deleted Device Count: 0
 Data loop file: /var/lib/docker/devicemapper/devicemapper/data
 WARNING: Usage of loopback devices is strongly discouraged for production use. Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.
 Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
(略)
Docker Root Dir: /var/lib/docker
(略)

2、对应的设备
[root@n33 lib]# lsblk -I 7
NAME                      MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
loop0                       7:0    0  100G  0 loop 
└─docker-253:3-33517-pool 252:0    0  100G  0 dm   
loop1                       7:1    0    2G  0 loop 
└─docker-253:3-33517-pool 252:0    0  100G  0 dm 


3、调整为 devicemapper(direct-lvm)
1)准备工作
安装 lvm2
[root@n33 ~]# yum install lvm2
增加一块磁盘
[root@n33 ~]# ls /dev/vdb
/dev/vdb
停止 docker 服务
[root@n33 ~]# systemctl stop docker

2)配置设备
a)pv
[root@n33 ~]# pvcreate /dev/vdb
b)创建一个名称为 docker 的 vg 
[root@n33 ~]# vgcreate docker /dev/vdb
c)创建2个 lv,分别对应 data 和 metadata 设备
[root@n33 ~]# lvcreate --wipesignatures y -n thinpool docker -l 95%VG
[root@n33 ~]# lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
d)转换 pool 为 thinpool 格式
[root@n33 ~]# lvconvert -y --zero n -c 512K --thinpool docker/thinpool --poolmetadata docker/thinpoolmeta
e)调整 lvm 配置
The value should be the percentage of space used before lvm attempts to autoextend the available space (100 = disabled).
定义一个百分比的阈值,表明触发 lvm 自动扩容前,已用空间占比。
thin_pool_autoextend_threshold = 80

The value’s setting is the percentage of space to increase the thin pool (100 = disabled)
每次扩容 thin pool 空间的比例
thin_pool_autoextend_percent = 20

[root@n33 ~]# cat /etc/lvm/profile/docker-thinpool.profile
activation {
    thin_pool_autoextend_threshold=80
    thin_pool_autoextend_percent=20
}
f)lvchange 应用配置
[root@n33 ~]# lvchange --metadataprofile docker-thinpool docker/thinpool
g)lvs 查看卷的信息,验证 monitor 的状态
[root@n33 ~]# lvs -o+seg_monitor
  LV       VG     Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert Monitor  
  thinpool docker twi-a-t--- 190.00g             0.00   0.01                             monitored

3)调整 docker 存储
a)备份
[root@n33 ~]# mkdir /var/lib/docker.bk
[root@n33 ~]# mv /var/lib/docker/* /var/lib/docker.bk
如果这个 docker engine 上已经有部分 p_w_picpaths 在使用,且需要保存,请先提前推送到自己的 registry 中保存。


b)调整服务配置
【第一种方式】
[root@n33 ~]# vim /lib/systemd/system/docker.service 
增加参数:
--storage-driver=devicemapper --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --storage-opt=dm.use_deferred_removal=true --storage-opt=dm.use_deferred_deletion=true

或者:
[root@n33 ~]# sed -i '/^ExecStart=/c\ExecStart=/usr/bin/dockerd --storage-driver=devicemapper --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --storage-opt=dm.use_deferred_removal=true --storage-opt=dm.use_deferred_deletion=true' /lib/systemd/system/docker.service 


【第2种方式】
调整 daemon.json 的配置:
[root@n33 ~]# cat /etc/docker/daemon.json
{
    "storage-driver": "devicemapper",
    "storage-opts": [
        "dm.thinpooldev=/dev/mapper/docker-thinpool",
        "dm.use_deferred_removal=true",
        "dm.use_deferred_deletion=true"
    ]
}

【注意事项】
Note: Always set both dm.use_deferred_removal=true and dm.use_deferred_deletion=true to prevent unintentionally leaking mount points.
启用上述2个参数来阻止可能意外产生的挂载点泄漏问题

c)重启服务
[root@n33 ~]# systemctl daemon-reload
[root@n33 ~]# systemctl start docker

d)验证
[root@n33 lib]# docker info     
(略)  
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: 20.45 MB
 Data Space Total: 204 GB
 Data Space Available: 204 GB
 Metadata Space Used: 266.2 kB
 Metadata Space Total: 2.143 GB
 Metadata Space Available: 2.143 GB
 Thin Pool Minimum Free Space: 20.4 GB
 Udev Sync Supported: true
 Deferred Removal Enabled: true
 Deferred Deletion Enabled: true
 Deferred Deleted Device Count: 0
 Library Version: 1.02.107-RHEL7 (2016-06-09)
(略) 

e)可以通过 lvs, lvdisplay, vgs 等指令来查看 lvm 卷的状态
f)可以查看日志,了解 thin pool 在自动扩容触及阈值时的状态
[root@n33 ~]# journalctl -fu dm-event.service
g)对应的设备
[root@n33 ~]# lsblk -I '253' |grep -v vda
NAME                    MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
vdb                     253:16   0  200G  0 disk 
├─docker-thinpool_tmeta 252:0    0    2G  0 lvm  
│ └─docker-thinpool     252:2    0  190G  0 lvm  
└─docker-thinpool_tdata 252:1    0  190G  0 lvm  
  └─docker-thinpool     252:2    0  190G  0 lvm 
h)确认无误后,可以清理旧的数据
[root@n33 ~]# rm /var/lib/docker.bk -fr



4)整合到一个小脚本中来配置direct-lvm的存储
[root@n33 ~]# cat docker_direct_lvm_setup.sh    
#!/bin/bash
#
#2016/12/8
#v1.0.5 @PC

## 分配一块独立的磁盘供docker使用,本例使用的是 /dev/vdb
dev_name='/dev/vdb'

yum -y -q install lvm2
echo '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
pvcreate ${dev_name}
vgcreate docker ${dev_name}
lvcreate --wipesignatures y -n thinpool docker -l 95%VG
lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
lvconvert -y --zero n -c 512K --thinpool docker/thinpool --poolmetadata docker/thinpoolmeta
cat <<'_EOF' >/etc/lvm/profile/docker-thinpool.profile
activation {
    thin_pool_autoextend_threshold=80
    thin_pool_autoextend_percent=20
}
_EOF
lvchange --metadataprofile docker-thinpool docker/thinpool
echo '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'
lvs -o+seg_monitor
echo '+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++'

cat <<'_EOF'

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
接下来的操作步骤示例:

[1] 如果 docker 有旧的数据,先推送到registry中再移除;
# mkdir /var/lib/docker.bk
# mv /var/lib/docker/* /var/lib/docker.bk

[2] 更新docker服务的配置:
(方式一: 调整 docker.service 的配置参数)
# sed -i '/^ExecStart=/c\ExecStart=/usr/bin/dockerd --storage-driver=devicemapper --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --storage-opt=dm.use_deferred_removal=true --storage-opt=dm.use_deferred_deletion=true' /lib/systemd/system/docker.service 

(方式二: 在 daemon.json 中配置参数)
# cat /etc/docker/daemon.json
{
    "storage-driver": "devicemapper",
    "storage-opts": [
        "dm.thinpooldev=/dev/mapper/docker-thinpool",
        "dm.use_deferred_removal=true",
        "dm.use_deferred_deletion=true"
    ]
}


[3] 重启服务
# systemctl daemon-reload && systemctl start docker

[4] 验证是否调整完毕
# docker info
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
_EOF




ZYXW、参考
1、docs
https://docs.docker.com/engine/userguide/storagedriver/selectadriver/#supported-backing-filesystems
https://docs.docker.com/engine/userguide/storagedriver/device-mapper-driver/#/configure-direct-lvm-mode-for-production
2、Docker Device Mapper 使用 direct-lvm
http://www.cnblogs.com/SZLLQ2000/p/5486834.html
3、daemon.json
https://docs.docker.com/engine/reference/commandline/dockerd/