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 里的这个驱动达不到生产环境使用的稳定程度,所以不推荐使用。

Device Mapper: loop-lvm

默认 CentOS 7 下 Docker 使用的 Device Mapper 设备默认使用 loopback 设备,后端为自动生成的稀疏文件,如下:

[root@k8s01 ~]# ls -lsh /var/lib/docker/devicemapper/devicemapper/
total 2.4G
2.4G -rw------- 1 root root 100G Mar 20 18:34 data
4.0M -rw------- 1 root root 2.0G Mar 20 18:34 metadata

data(存放数据)和 metadata(存放元数据)的大小从输出可以看出初始化默认为 100G 和 2G 大小,都是稀疏文件,使用多少占用多少。

Device Mapper: direct-lvm

生产环境下应该使用 direct-lvm,如果之前有镜像在 loop-lvm 模式下创建,需要切换,则需要把镜像做备份(push 到 hub 或者私有 registry)。所以最好的做法,还是在刚刚给 CentOS 服务器安装 Docker 的时候,直接做好配置。

二、手动配置 DIRECT-LVM 模式

配置 LVM 及 thinpool

1. 挂载新的磁盘

[root@k8s01 ~]# fdisk /dev/sdb    #创建LVM分区,创建过程省略

2. 停止 Docker 进程

[root@k8s01 ~]# systemctl stop docker

3. 安装软件包

  • RHEL/CentOS: device-mapper-persistent-data, lvm2, and all dependencies
  • Ubuntu/Debian: thin-provisioning-tools, lvm2, and all dependencies

4. 创建物理卷

[root@k8s01 ~]# pvcreate /dev/sdb1
Physical volume "/dev/sdb1" successfully created.

5. 创建卷组

[root@k8s01 ~]# vgcreate docker /dev/sdb1

6. 创建 2 个名为 thinpool 和 thinpoolmeta 的逻辑卷

[root@k8s01 ~]# 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@k8s01 ~]# lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
  Logical volume "thinpoolmeta" created.

剩余的 4% 留给它们自动扩展

7. 转换成 thinpool

[root@k8s01 ~]# lvconvert -y \
--zero n \
-c 512K \
--thinpool docker/thinpool \
--poolmetadata docker/thinpoolmeta

8. 设置 thinpool 的自动扩展参数

[root@k8s01 ~]# vi /etc/lvm/profile/docker-thinpool.profile
activation {
    thin_pool_autoextend_threshold=80
    thin_pool_autoextend_percent=20
}

应用上述配置

[root@k8s01 ~]# lvchange --metadataprofile docker-thinpool docker/thinpool
Logical volume docker/thinpool changed.

当空间大于 80% 时进行扩展,扩展的大小是空闲空间的 20%。

9. 查看 thinpool 是否是已监视状态

[root@k8s01 ~]# 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@k8s02 ~]# mkdir /var/lib/docker.bk
[root@k8s02 ~]# mv /var/lib/docker/* /var/lib/docker.bk

2. 编辑 /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. 启动 Docker

systemctl start docker

4. 验证配置

[root@k8s01 ~]# docker info
Containers: 30
Running: 30
Paused: 0
Stopped: 0
Images: 15
Server Version: 18.02.0-ce
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: 2.412GB
Data Space Total: 816GB
Data Space Available: 813.6GB
Metadata Space Used: 1.573MB
Metadata Space Total: 8.586GB
Metadata Space Available: 8.584GB
Thin Pool Minimum Free Space: 81.6GB
Deferred Removal Enabled: true
Deferred Deletion Enabled: true
Deferred Deleted Device Count: 0
Library Version: 1.02.107-RHEL7 (2015-10-14)
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 9b55aab90508bd389d7654c4baf173a981477d55
runc version: 9f9c96235cc97674e935002fc3d78361b696a69e
init version: 949e6fa
Security Options:
seccomp
  Profile: default
Kernel Version: 3.10.0-327.28.3.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 8
Total Memory: 7.633GiB
Name: k8s01
ID: QY5Y:NSF5:DRG6:DFAF:WA53:WYSW:BKEA:FKY6:L3MS:5KU4:VJJL:3JUB
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
HTTP Proxy: http://127.0.0.1:8118/
No Proxy: localhost,127.0.0.1,gj7l88s1.mirror.aliyuncs.com,docker.io,registry.cn-hangzhou.aliyuncs.com,acs-cn-hangzhou-mirror.oss-cn-hangzhou.aliyuncs.com
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false

如果 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

参考命令

查看挂载信息

[root@k8s01 ~]# lsblk

 

 

P.S. 本文是帮朋友代为发表,非博主所写。

发表评论

发表评论

*

沙发空缺中,还不快抢~