Docker 1.12 配置 direct-lvm

概念

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

  1. 挂载新的磁盘
[root@evi0s ~]# fdisk /dev/sdb    #创建LVM分区,创建过程省略

对于 Vultr 这类 VPS 而言,挂载新的硬盘不太可能,可以使用fdisk来直接创建一个linux lvm类型分区

  1. 停止 Docker 进程
[root@evi0s ~]# systemctl stop docker
  1. 安装软件包
  • RHEL/CentOS: device-mapper-persistent-data, lvm2, and all dependencies
  • Ubuntu/Debian: thin-provisioning-tools, lvm2, and all dependencies
  1. 创建物理卷
[root@evi0s ~]# pvcreate /dev/vda2
Physical volume "/dev/vda2" successfully created.
  1. 创建卷组
[root@evi0s ~]# vgcreate docker /dev/vda2
  1. 创建 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% 留给它们自动扩展

  1. 转换成 thinpool
[root@evi0s ~]# lvconvert -y \
--zero n \
-c 512K \
--thinpool docker/thinpool \
--poolmetadata docker/thinpoolmeta
  1. 设置 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%。

  1. 查看 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

  1. 备份 /var/lib/docker
[root@evi0s ~]# mkdir /var/lib/docker.bk
[root@evi0s ~]# mv /var/lib/docker/* /var/lib/docker.bk
  1. 编辑 /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"
    ]
}
  1. 启动 Docker
[root@evi0s ~]# systemctl start docker.service

这里可能会启动失败,提示flag重复。
可以去修改docker.service文件,去掉启动时的存储引擎的参数

  1. 验证配置
[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

参考

https://docs.docker.com/storage/storagedriver/device-mapper-driver/#configure-direct-lvm-mode-for-production

声明

已在 Vultr 上测试成功,部分过程根据环境适当修改
原帖地址 Docker 1.12 配置 direct-lvm

发表评论

发表回复

*

沙发空缺中,还不快抢~