![](https://evi0s.com/wp-content/uploads/2018/11/lvm_banner.png)
概念
Device Mapper
Docker 最先是跑在 Ubuntu 和 Debian 上的,使用 aufs 存储器。由于 Docker 越来越流行,许多公司希望在 RHEL 上使用,但是上游内核中没有包括 aufs,所以 RHEL 不能使用 aufs。最终开发者们开发了一个新的后端存储引擎 Device Mapper,基于已有的 Device Mapper 技术,并且使 Docker 支持可插拔,现在全世界有很多真实案例在生产环境使用 Device Mapper。
镜像层与共享
Device Mapper 存储每个镜像和容器在自己的虚拟设备上,也就是说这些设备是按需分配(copy-on-write snapshot devices),Device Mapper 技术是工作在 block 级别的而不是文件级别的。
Device Mapper 创建镜像的方式是
- Device Mapper 基于块设备或 loop mounted sparse files 来创建一个虚拟池
- 然后在上面创建一个有文件系统的基础设备(base device)
- 每个镜像层就是基于这个基础设备的 COW 快照(snapshot),也就是说这些快照初始化时是空的,只有数据写入时才会占用池中的空间。
loop-lvm 和 direct-lvm 区别
因为上述的原因,对于 CentOS/RHEL 这类没有相关驱动的系统,一般使用 Device Mapper 驱动利用 LVM 的一些机制来模拟分层存储。这样的做法除了性能比较差之外,稳定性一般也不好,而且配置相对复杂。Docker 安装在 CentOS/RHEL 上后,会默认选择 Device Mapper,但是为了简化配置,其 Device Mapper 是跑在一个稀疏文件模拟的块设备上,也被称为 loop-lvm。这样的选择是因为不需要额外配置就可以运行 Docker,这是自动配置唯一能做到的事情。但是 loop-lvm 的做法非常不好,其稳定性、性能更差,无论是日志还是 docker info 中都会看到警告信息。官方文档有明确的文章讲解了如何配置块设备给 Device Mapper 驱动做存储层的做法,这类做法也被称为配置 direct-lvm。
除了前面说到的问题外,devicemapper + loop-lvm 还有一个缺陷,因为它是稀疏文件,所以它会不断增长。用户在使用过程中会注意到/var/lib/docker/devicemapper/devicemapper/data
不断增长,而且无法控制。很多人会希望删除镜像或者可以解决这个问题,结果发现效果并不明显。原因就是这个稀疏文件的空间释放后基本不进行垃圾回收的问题。因此往往会出现即使删除了文件内容,空间却无法回收,随着使用这个稀疏文件一直在不断增长。
所以对于 CentOS/RHEL 的用户来说,在没有办法使用 UnionFS 的情况下,一定要配置 direct-lvm 给 devicemapper,无论是为了性能、稳定性还是空间利用率。
或许有人注意到了 CentOS 7 中存在被 backports 回来的 overlay 驱动,不过 CentOS 里的这个驱动达不到生产环境使用的稳定程度,所以不推荐使用。
手动配置 DIRECT-LVM 模式
配置 LVM 及 thinpool
- 挂载新的磁盘
[root@evi0s ~]# fdisk /dev/sdb #创建LVM分区,创建过程省略
对于 Vultr 这类 VPS 而言,挂载新的硬盘不太可能,可以使用fdisk
来直接创建一个linux lvm
类型分区
- 停止 Docker 进程
[root@evi0s ~]# systemctl stop docker
- 安装软件包
- RHEL/CentOS: device-mapper-persistent-data, lvm2, and all dependencies
- Ubuntu/Debian: thin-provisioning-tools, lvm2, and all dependencies
- 创建物理卷
[root@evi0s ~]# pvcreate /dev/vda2
Physical volume "/dev/vda2" successfully created.
- 创建卷组
[root@evi0s ~]# vgcreate docker /dev/vda2
- 创建 2 个名为 thinpool 和 thinpoolmeta 的逻辑卷
[root@evi0s ~]# lvcreate --wipesignatures y -n thinpool docker -l 95%VG
WARNING: xfs signature detected on /dev/docker/thinpool at offset 0. Wipe it? [y/n]: y
Wiping xfs signature on /dev/docker/thinpool.
Logical volume "thinpool" created.
[root@evi0s ~]# lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
Logical volume "thinpoolmeta" created.
剩余的 4% 留给它们自动扩展
- 转换成 thinpool
[root@evi0s ~]# lvconvert -y \
--zero n \
-c 512K \
--thinpool docker/thinpool \
--poolmetadata docker/thinpoolmeta
- 设置 thinpool 的自动扩展参数
[root@evi0s ~]# vi /etc/lvm/profile/docker-thinpool.profile
activation {
thin_pool_autoextend_threshold=80
thin_pool_autoextend_percent=20
}
应用上述配置
[root@evi0s ~]# lvchange --metadataprofile docker-thinpool docker/thinpool
Logical volume docker/thinpool changed.
当空间大于 80% 时进行扩展,扩展的大小是空闲空间的 20%。
- 查看 thinpool 是否是已监视状态
[root@evi0s ~]# 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
配置 Docker
- 备份
/var/lib/docker
[root@evi0s ~]# mkdir /var/lib/docker.bk
[root@evi0s ~]# mv /var/lib/docker/* /var/lib/docker.bk
- 编辑
/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"
]
}
- 启动 Docker
[root@evi0s ~]# systemctl start docker.service
这里可能会启动失败,提示flag重复。
可以去修改docker.service
文件,去掉启动时的存储引擎的参数
- 验证配置
[root@evi0s ~]# docker info
Containers: 5
Running: 5
Paused: 0
Stopped: 0
Images: 31
Server Version: 1.13.1
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: 7.039 GB
Data Space Total: 10.2 GB
Data Space Available: 3.162 GB
Metadata Space Used: 11.9 MB
Metadata Space Total: 104.9 MB
Metadata Space Available: 92.95 MB
Thin Pool Minimum Free Space: 1.02 GB
Udev Sync Supported: true
Deferred Removal Enabled: true
Deferred Deletion Enabled: true
Deferred Deleted Device Count: 0
Library Version: 1.02.146-RHEL7 (2018-01-22)
Logging Driver: journald
Cgroup Driver: systemd
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Swarm: inactive
Runtimes: docker-runc runc
Default Runtime: docker-runc
Init Binary: /usr/libexec/docker/docker-init-current
containerd version: (expected: aa8187dbd3b7ad67d8e5e3a15115d3eef43a7ed1)
runc version: 5eda6f6fd0c2884c2c8e78a6e7119e8d0ecedb77 (expected: 9df8b306d01f59d3a8029be411de015b7304dd8f)
init version: fec3683b971d9c3ef73f284f176672c44b448662 (expected: 949e6facb77383876aeff8a6944dde66b3089574)
Security Options:
seccomp
WARNING: You're not using the default seccomp profile
Profile: /etc/docker/seccomp.json
Kernel Version: 4.19.2-1.el7.elrepo.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
Number of Docker Hooks: 3
CPUs: 1
Total Memory: 985.3 MiB
Name: evi0s.com
ID: C6B4:B57F:3YHM:QE4N:LFV2:HSTN:GE7M:375K:3SBK:ZDR5:VSZ6:7I3P
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Registries: docker.io (secure)
如果 Data file 和 Metadata file 为空,Pool Name 是 docker-thinpool,则配置完成。
确认没问题之后,删除 /var/lib/docker.bk
参考
声明
已在 Vultr 上测试成功,部分过程根据环境适当修改
原帖地址 Docker 1.12 配置 direct-lvm
发表评论
沙发空缺中,还不快抢~