©
本文档使用
php.cn手册 发布
Device Mapper是基于内核的框架,支持Linux上的许多高级卷管理技术。Docker的devicemapper
存储驱动程序利用此框架的精简配置和快照功能进行镜像和容器管理。本文将Device Mapper存储驱动程序称为devicemapper
,并将内核框架称为Device Mapper
。
对于支持它的系统,devicemapper
支持包含在Linux内核中。但是,需要特定配置才能将其用于Docker。例如,在RHEL或CentOS的股票安装中,Docker将默认为overlay
,这不是受支持的配置。
devicemapper
驱动程序使用专用于Docker的块设备,并在块级而不是文件级运行。这些设备可以通过将物理存储添加到Docker主机来扩展,并且它们比在操作系统级别使用文件系统更好。
如果您在RHEL,CentOS或Oracle Linux上使用Docker EE,则必须使用devicemapper
存储驱动程序。
devicemapper
存储驱动程序是RHEL,CentOS和Oracle Linux上唯一支持Docker EE和商业支持Docker Engine(CS-Engine)的存储驱动程序。请参阅产品兼容性表格。
devicemapper
在CentOS,Fedora,Ubuntu或Debian上运行的Docker CE也受支持。
更改存储驱动程序将使您已创建的任何容器在本地系统上都不可访问。使用docker save
保存的容器,并推动现有图像多克尔集线器或私人仓库,让你不必后重新创建它们。
devicemapper
存储驱动程序配置Docker在遵循这些程序之前,您必须先满足所有先决条件。
loop-lvm
测试模式此配置仅适用于测试。环回设备速度慢且资源密集,并且需要您以特定大小在磁盘上创建文件。他们还可以引入竞争条件。他们应该进行测试,因为安装更容易。
对于生产系统,请参阅为生产配置direct-lvm模式。
停止Docker。$ sudo systemctl stop docker
2. 编辑/etc/docker/daemon.json
。如果它还不存在,请创建。假设文件为空,请添加以下内容。{ "storage-driver": "devicemapper" }查看每个存储驱动程序的所有存储选项:
- [Stable](../../../reference/commandline/dockerd/index#storage-driver-options)- [Edge](https://docs.docker.com/edge/engine/reference/commandline/dockerd/#storage-driver-options)
如果daemon.json
文件包含格式错误的JSON,Docker将无法启动。
启动Docker。$ sudo systemctl start docker
验证守护进程正在使用devicemapper
存储驱动程序。使用docker info
命令并寻找Storage Driver
。$ docker info 容器:0 正在运行:0 已暂停:0 已停止:0 图像:0 服务器版本:17.03.1-ce存储驱动程序:devicemapper 池名称:docker-202:1-8413957-pool 池大小:65.54 kB 基本设备大小:10.74 GB 备份文件系统:xfs 数据文件:/ dev/loop0 元数据文件:/dev/loop1 使用的数据空间:11.8 MB 数据空间总数:107.4 GB 数据空间可用:7.44 GB 使用的元数据空间:581.6 kB 元数据空间总数:2.147 GB 可用元数据空间:2.147 GB 精简池最小可用空间:10.74 GB Udev同步支持:true 延迟删除已启用:false 延迟删除已启用:false 延期删除设备计数:0 数据循环文件:/var/lib/docker/devicemapper/devicemapper/data 元数据循环文件:/var/lib/docker/devicemapper/devicemapper/metadata 库版本:1.02.135-RHEL7 (2016-11-16) <output truncated>
该主机在运行的loop-lvm
节点,这是不支持在生产系统上。这是由以下事实表明的:Data loop file
a和a Metadata loop file
在文件下/var/lib/docker/devicemapper/devicemapper
。这些是回送加载的稀疏文件。对于生产系统,请参阅为生产配置direct-lvm模式。
使用devicemapper
存储驱动程序的生产主机必须使用direct-lvm
模式。该模式使用块设备来创建精简池。这比使用回送设备更快,更高效地使用系统资源,并且块设备可以根据需要增长。但是,loop-lvm
模式需要更多的设置。
在满足先决条件之后,请按照以下步骤将Docker配置为devicemapper
以direct-lvm
模式使用存储驱动程序。
警告:更改存储驱动程序将使您已创建的任何容器在本地系统上都无法访问。使用
docker save
保存的容器,并推动现有图像多克尔集线器或私人仓库,这样就不需要以后重新创建。
在Docker 17.06及更高版本中,Docker可以为您管理块设备,简化direct-lvm
模式配置。这仅适用于新的Docker设置。您只能使用一个块设备。如果您需要使用多个块设备,请手动配置direct-lvm模式。添加了以下新的配置选项:
Option | Description | Required? | Default | Example |
---|---|---|---|---|
dm.directlvm_device | The path to the block device to configure for direct-lvm. | Yes | dm.directlvm_device="/dev/xvdf" | |
dm.thinp_percent | The percentage of space to use for storage from the passed in block device. | No | 95 | dm.thinp_percent=95 |
dm.thinp_metapercent | The percentage of space to for metadata storage from the passed=in block device. | No | 1 | dm.thinp_metapercent=1 |
dm.thinp_autoextend_threshold | The threshold for when lvm should automatically extend the thin pool as a percentage of the total storage space. | No | 80 | dm.thinp_autoextend_threshold=80 |
dm.thinp_autoextend_percent | The percentage to increase the thin pool by when an autoextend is triggered. | No | 20 | dm.thinp_autoextend_percent=20 |
dm.directlvm_device_force | Whether to format the block device even if a filesystem already exists on it. If set to false and a filesystem is present, an error is logged and the filesystem is left intact. | No | false | dm.directlvm_device_force=true |
编辑daemon.json
文件并设置适当的选项,然后重新启动Docker以使更改生效。以下daemon.json
设置了上表中的所有选项。
{ "storage-driver": "devicemapper", "storage-opts": [ "dm.directlvm_device=/dev/xdf", "dm.thinp_percent=95", "dm.thinp_metapercent=1", "dm.thinp_autoextend_threshold=80", "dm.thinp_autoextend_percent=20", "dm.directlvm_device_force=false" ]}
查看每个存储驱动程序的所有存储选项:
Stable
Edge
重新启动Docker以使更改生效。Docker会调用这些命令为您配置块设备。
警告:在Docker为您准备好块设备后更改这些值不受支持,并且会导致错误。
您仍然需要执行定期维护任务。
以下过程将创建配置为精简池的逻辑卷,以用作存储池的备份。它假定您有一个备用块设备,/dev/xvdf
并有足够的空间来完成任务。设备标识符和音量大小在您的环境中可能不同,您应该在整个过程中替换您自己的值。该过程还假定Docker守护进程处于该stopped
状态。
确定要使用的块设备。该设备将位于/dev/
(如/dev/xvdf
)下,并且需要足够的可用空间来存储主机将运行的工作负载的映像和容器层。理想情况下,这将是一个固态硬盘。
2. 停止Docker。$ sudo systemctl stop docker
3. 安装下列软件包:
- **RHEL / CentOS**: `device-mapper-persistent-data`, `lvm2`, and all dependencies
- **Ubuntu / Debian**: `thin-provisioning-tools`, `lvm2`, and all dependencies
4. 使用该pvcreate
命令在步骤1中创建块设备上的物理卷。替换您的设备名称/dev/xvdf
。 警告:接下来的几个步骤是破坏性的,所以请确保您指定了正确的设备!
$ sudo pvcreate/dev/xvdf 物理卷“/dev/xvdf”已成功创建。
5. docker
使用该vgcreate
命令在同一设备上创建一个卷组。$ sudo vgcreate docker/dev/xvdf成功创建卷组“docker”
6. 创建两个命名的逻辑卷thinpool
并thinpoolmeta
使用该lvcreate
命令。最后一个参数指定可用空间的大小,以便在空间不足时自动扩展数据或元数据,作为临时性缺口。这些是推荐值。$ sudo lvcreate --wipesignatures y -n thinpool docker -l 95%VG 创建逻辑卷“thinpool”。$ sudo lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG 创建逻辑卷“thinpoolmeta”。
6. 使用该lvconvert
命令将卷转换为精简池和精简池元数据的存储位置。$ sudo lvconvert -y \ --zero n \ -c 512K \ --thinpool docker/thinpool \ --poolmetadata
警告:使用元数据擦除将逻辑卷docker/thinpool和docker/thinpoolmeta转换为精简池的数据和元数据卷。这将破坏逻辑卷的内容(文件系统等)将docker/thinpool转换为精简池。
7. 通过lvm
配置文件配置精简池的自动扩展。$ sudo vi /etc/lvm/profile/docker-thinpool.profile
8. 指定thin_pool_autoextend_threshold
和thin_pool_autoextend_percent
值。 thin_pool_autoextend_threshold
是lvm
尝试自动扩展可用空间之前所用空间的百分比(100 =disabled,不推荐)。 thin_pool_autoextend_percent
是自动扩展时添加到设备的空间量(0 = disabled)。当磁盘使用率达到80%时,下面的示例将增加20%的容量。激活{ thin_pool_autoextend_threshold=80 thin_pool_autoextend_percent=20 } 保存文件。
9. 使用该lvchange
命令应用LVM配置文件。$ sudo lvchange --metadataprofile docker-thinpool docker/thinpool逻辑卷docker/thinpool已更改。
10. 启用对主机上逻辑卷的监视。没有这一步,即使存在LVM配置文件,自动扩展也不会发生。$ sudo 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
11. 如果您以前曾经在此主机上运行过Docker,或者/var/lib/docker/
存在,请将其移出,以便Docker可以使用新的LVM池来存储映像和容器的内容。$ mkdir /var/lib/docker.bk $ mv /var/lib/docker/* /var/lib/docker.bk 如果以下任何步骤失败并且您需要恢复,您可以删除/var/lib/docker
并替换为/var/lib/docker.bk
。
12. 编辑/etc/docker/daemon.json
并配置devicemapper
存储驱动程序所需的选项。如果该文件先前为空,则应该包含以下内容: 注意:dm.use_deferred_deletion=true
使用默认内核版本3.18时,RHEL,CentOS或Ubuntu 14.04尚不支持延迟删除选项。
{ "storage-driver": "devicemapper", "storage-opts": "dm.thinpooldev=/dev/mapper/docker-thinpool", "dm.use_deferred_removal=true", "dm.use_deferred_deletion=true" }
启动Docker。 systemd:$ sudo systemctl start docker 服务:$ sudo service docker start
2. 验证Docker是否正在使用新配置docker info
。$ docker info容器:0运行:0暂停:0已停止:0映像:0服务器版本:17.03.1-ce存储驱动程序:devicemapper池名称:docker-thinpool池大小:524.3 kB基本设备大小:10.74 GB备份文件系统: xfs数据文件:元数据文件:使用的数据空间:19.92 MB数据空间总数:102 GB数据空间可用:102 GB使用的元数据空间:147.5 kB元数据空间总计:1.07 GB元数据空间:1.069 GB精简池最小可用空间:10.2 GB Udev的同步支持:真递延去除启用:真递延删除启用:真实延迟删除设备数量:0库版本:1.02.135-RHEL7(2016年11月16日)<output truncated>如果Docker配置正确时,Data file
和Metadata file
将是空白的,并且池名将会是docker-thinpool
。
3. 验证配置正确后,可以删除/var/lib/docker.bk
包含以前配置的目录。$ rm -rf /var/lib/docker.bk
不要单独依靠LVM自动扩展。卷组可以自动扩展,但是卷仍能写满。您可以使用lvs
或监视卷上的可用空间lvs -a
。考虑在操作系统级别使用监控工具,例如Nagios。
要查看LVM日志,您可以使用journalctl
:
$ journalctl -fu dm-event.service
如果您遇到精简池问题,可以将存储选项设置dm.min_free_space
为一个值(表示百分比)/etc/docker.daemon.json
。例如,将其设置为10
在可用空间达到或接近10%时确保操作失败并发出警告。请参阅Engine守护程序参考中的存储驱动程序选项。
您可以增加正在运行的精简池设备上的池的容量。如果数据的逻辑卷已满并且卷组处于满负荷状态,这很有用。具体过程取决于您是使用loop-lvm精简池还是直接使用lvm精简池。
调整loop-lvm
精简池的最简单方法是使用device_tool实用程序,但可以使用操作系统实用程序。
在Docker Github存储库device_tool.go
的contrib/
目录中提供了一个社区贡献的脚本。您可以使用此工具调整loop-lvm
精简池的大小,避免上述漫长的过程。此工具无法保证正常工作,但您只能loop-lvm
在非生产系统上使用。
如果您不想使用device_tool
,则可以手动调整精简池的大小(#use-operating-system-utilities)。
要使用该工具,请克隆Github存储库,更改为contrib/docker-device-tool
,并按照其中的说明README.md
编译该工具。
2. 使用该工具。以下示例将精简池的大小调整为200GB。$ ./device_tool resize 200GB
如果您不想使用设备工具实用程序,则可以loop-lvm
使用以下步骤手动调整精简池的大小。
在loop-lvm
模式中,回送设备用于存储数据,另一个用于存储元数据。loop-lvm
模式仅支持测试,因为它具有显着的性能和稳定性缺陷。
如果您使用的loop-lvm
模式,输出docker info
会显示文件路径Data loop file
和Metadata loop file
:
$ docker info |grep 'loop file' Data loop file: /var/lib/docker/devicemapper/devicemapper/data Metadata loop file: /var/lib/docker/devicemapper/devicemapper/metadata
按照以下步骤增加精简池的大小。在此示例中,精简池为100 GB,并增加到200 GB。
列出设备的大小。$ sudo ls -lh /var/lib/docker/devicemapper/devicemapper/ total 1175492 -rw------- 1 root root 100G Mar 30 05:22 data -rw------- 1 root root 2.0G Mar 31 11:17 metadata
2. data
使用该truncate
命令将文件的大小增大到200 G,该命令用于增加或减小文件的大小。请注意,减小尺寸是一种破坏性操作。$ sudo truncate -s 200G /var/lib/docker/devicemapper/devicemapper/data
3. 验证文件大小已更改。$ sudo ls -lh /var/lib/docker/devicemapper/devicemapper/ total 1.2G -rw------- 1 root root 200G Apr 14 08:47 data -rw------- 1 root root 2.0G Apr 19 13:27 metadat
4. 环回文件已在磁盘上更改,但未在内存中更改。列出内存中环回设备的大小,以GB为单位。重新加载,然后再次列出大小。重新加载后,大小为200 GB。$ echo $ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 100 $ sudo losetup -c /dev/loop0 $ echo $ $(sudo blockdev --getsize64 /dev/loop0) / 1024 / 1024 / 1024 200
5. 重新加载devicemapper精简池。a. 先获取泳池名称。池名称是第一个由其分隔的字段:
。这个命令提取它。$ sudo dmsetup status | grep'thin-pool'| awk -F':'{'print $ 1'} docker-8:1-123141-pool b.转储精简池的设备映射表。$ sudo dmsetup table docker-8:1-123141-pool 0 209715200-pool 7:1 7:0 128 32768 1 skip_block_zeroing c. 使用输出的第二个字段计算精简池的总部分。该数字以512-k扇区表示。一个100G文件有209715200个512-k扇区。如果你把这个数字加倍到200G,你会得到419430400个512k扇区。d. 使用以下三个重新加载具有新扇区号的精简池dmsetup
命令。$ sudo dmsetup suspend docker-8:1-123141-pool $ sudo dmsetup reload docker-8:1-123141-pool --table'0 419430400 thin-pool7:1 7:0 128 32768 1 skip_block_zeroing'$ sudo dmsetup resume docker-8:1-123141-pool
要扩展direct-lvm
精简池,您需要首先将新的块设备附加到Docker主机,并记下内核分配给它的名称。在这个例子中,新的块设备是/dev/xvdg
。
按照此步骤扩展direct-lvm
精简池,替换您的块设备和其他参数以适合您的情况。
收集有关您的卷组的信息。使用此pvdisplay
命令查找您的精简池当前正在使用的物理块设备以及卷组的名称。$ sudo pvdisplay |grep 'VG Name' PV Name /dev/xvdf VG Name docker
在以下步骤中,根据需要替换块设备或卷组名称。
使用上一步中的vgextend
命令VG Name
和新块设备的名称扩展卷组。$ sudo vgextend docker /dev/xvdg Physical volume "/dev/xvdg" 已成功创建。卷组“docker”已成功扩展
2. 扩展docker/thinpool
逻辑卷。该命令立即使用100%的体积,而不会自动扩展。要扩展元数据精简池,请使用docker/thinpool_tmeta
。docker/thinpool_tmeta
. $ sudo lvextend -l+100%FREE -n docker/thinpool 逻辑卷docker/thinpool_tdata的大小从95.00 GiB(24319个扩展盘区)变为198.00个GiB(50688个盘区)。逻辑卷docker/thinpool_tdata已成功调整大小。
3. 使用Data Space Available
输出中的字段验证新的精简池大小docker info
。如果您扩展了docker/thinpool_tmeta
逻辑卷,请查找Metadata Space Available
。存储驱动程序:devicemapper池名称:docker-thinpool池块大小:524.3 kB基本设备大小:10.74 GB备份文件系统:xfs数据文件:元数据文件:使用的数据空间:212.3 MB数据空间总计:212.6 GB数据空间可用:212.4 GB元数据已用空间:286.7 kB元数据空间总计:1.07 GB元数据空间可用:1.069 GB <output truncated>
devicemapper
存储驱动是怎么工作的警告:不要直接操作其中的任何文件或目录
/var/lib/docker/
。这些文件和目录由Docker管理。
lsblk
从操作系统的角度来看,使用该命令可以查看设备及其池:
$ sudo lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT xvda 202:0 0 8G 0 disk └─xvda1 202:1 0 8G 0 part /xvdf 202:80 0 100G 0 disk ├─docker-thinpool_tmeta 253:0 0 1020M 0 lvm │ └─docker-thinpool 253:2 0 95G 0 lvm └─docker-thinpool_tdata 253:1 0 95G 0 lvm └─docker-thinpool 253:2 0 95G 0 lvm
使用mount
命令查看Docker正在使用的安装点:
$ mount |grep devicemapper/dev/xvda1 on /var/lib/docker/devicemapper type xfs (rw,relatime,seclabel,attr2,inode64,noquota)
在使用时devicemapper
,Docker会将图像和图层内容存储在精简池中,并通过将它们安装在容器的子目录下将它们公开在容器中/var/lib/docker/devicemapper/
。
/var/lib/docker/devicemapper/metadata/
目录包含有关Devicemapper配置本身的元数据以及有关存在的每个图像和容器层的元数据。devicemapper
存储驱动程序使用快照,这个元数据包含有关这些快照的信息。这些文件是JSON格式。
/var/lib/devicemapper/mnt/
目录包含存在的每个图像和容器图层的装入点。图像层挂载点为空,但容器的挂载点显示容器的文件系统,因为它显示在容器内。
devicemapper
存储驱动程序使用专用的块设备,而不是格式化的文件系统,并在copy-on-write(CoW)操作上以获得最大性能的块级的文件进行操作。
devicemapper
另一个功能是使用快照(有时也称为精简设备或虚拟设备),它将每层中引入的差异存储为非常小的轻量级精简池。快照提供了许多好处:
容器之间共享的图层只能存储在磁盘上一次,除非它们是可写的。例如,如果您有10张全部基于的不同图像alpine
,则alpine
图像及其所有父图像只会在磁盘上存储一次。
快照是copy-on-write(CoW)策略的实现。这意味着给定的文件或目录只有在容器被修改或删除时才会被复制到容器的可写层。
由于devicemapper
在块级别运行,因此可以同时修改可写层中的多个块。
快照可以使用标准的操作系统级备份工具进行备份。只需复制一份/var/lib/docker/devicemapper/
。
当您使用devicemapper
存储驱动程序启动Docker时,所有与映像和容器图层相关的对象都将存储在/var/lib/docker/devicemapper/
其中,并由一个或多个块级设备(环回设备(仅测试)或物理磁盘)支持。
所述基部设备是最低级的对象。这是精简池本身。你可以使用它来检查它docker info
。它包含一个文件系统。这个基础设备是每个图像和容器层的起点。基础设备是Device Mapper的实现细节,而不是Docker层。
有关基础设备和每个图像或容器图层的元数据/var/lib/docker/devicemapper/metadata/
以JSON格式存储。这些图层是写入时复制快照,这意味着它们是空的,直到它们与父图层分离。
每个容器的可写入层都安装在一个安装点中/var/lib/docker/devicemapper/mnt/
。每个只读图像层和每个停止的容器都存在一个空目录。
每个图像图层都是其下面图层的快照。每幅图像的最底层是存储在池中的基础设备的快照。运行容器时,它是容器所基于的映像的快照。以下示例显示了一个具有两个运行容器的Docker主机。第一个是ubuntu
容器,第二个是busybox
容器。
devicemapper
读取和写入的工作方式与devicemapper
,读取发生在块级别。下图显示了读取0x44f
示例容器中的单个块()的高级过程。
应用程序0x44f
在容器中发出块请求。由于容器是图像的精简快照,它没有该块,但它具有一个指向最接近的父图像上存在的块的指针,并从那里读取该块。该块现在存在于容器的内存中。
编写新文件:使用devicemapper
驱动程序,将新数据写入容器是通过按需分配操作完成的。新文件的每个块都分配在容器的可写层中,并且块写入那里。
更新现有文件:文件的相关块从最近的图层中读取。当容器写入文件时,只有修改后的块被写入容器的可写层。
删除文件或目录:当您删除容器可写层中的文件或目录时,或者图像层删除其父层中存在的文件时,devicemapper
存储驱动程序将截取对该文件或目录的进一步读取尝试,并作出响应文件或目录不存在。
编写然后删除文件:如果容器写入文件并稍后删除文件,则所有这些操作都发生在容器的可写层中。在这种情况下,如果你正在使用direct-lvm
,块被释放。如果您使用loop-lvm
,块可能不会被释放。这是不用于loop-lvm
生产的另一个原因。
allocate-on demand
性能影响:devicemapper
存储驱动程序使用allocate-on-demand
操作将精简池中的新块分配到容器的可写层。每个块都是64KB,所以这是用于写入的最小空间量。
写时复制性能影响:容器首次修改特定块时,该块将写入容器的可写层。因为这些写操作发生在块的级别而不是文件,所以性能影响最小化。但是,编写大量数据块仍然会对性能产生负面影响,并且devicemapper
在此场景中,存储驱动程序实际上可能比其他存储驱动程序的性能更差。对于写入繁重的工作负载,应使用完全绕过存储驱动程序的数据卷。
在使用devicemapper
存储驱动程序时要记住这些事项以最大限度地提高性能。
使用 direct-lvm
:loop-lvm
模式不是高性能的,不应该在生产中使用。
使用快速存储:固态硬盘(SSD)比旋转磁盘提供更快的读取和写入速度。
内存使用情况:devicemapper
使用比其他一些存储驱动程序更多的内存。每个启动的容器都会将其文件的一个或多个副本加载到内存中,具体取决于同时修改同一文件的块数。由于内存压力,devicemapper
存储驱动程序可能不是高密度用例中某些工作负载的正确选择。
将卷用于写入繁重的工作负载:卷为写入繁重的工作负载提供最佳和最可预测的性能。这是因为它们绕过了存储驱动程序,并且不会产生精简配置和写入时复制引入的任何潜在开销。卷还有其他好处,例如允许您在容器之间共享数据,并且即使在没有正在运行的容器正在使用它们时也会持久存在。
了解图像,容器和存储驱动程序
选择存储驱动程序
AUFS存储驱动程序在实践中
Btrfs存储驱动程序在实践中
守护进程引用