使用 Device Mapper 存储驱动程序(已弃用)

已弃用

Device Mapper 驱动程序 已弃用,并且在 Docker Engine v25.0 中被移除。如果您正在使用 Device Mapper,则必须在升级到 Docker Engine v25.0 之前迁移到受支持的存储驱动程序。阅读 Docker 存储驱动程序 页面以了解受支持的存储驱动程序。

Device Mapper 是一个基于内核的框架,它为 Linux 上许多高级卷管理技术提供了基础。Docker 的 devicemapper 存储驱动程序利用了此框架的精简配置和快照功能来进行映像和容器管理。本文将 Device Mapper 存储驱动程序称为 devicemapper,而将内核框架称为 *Device Mapper*。

对于支持它的系统,devicemapper 支持包含在 Linux 内核中。但是,需要特定的配置才能将其与 Docker 一起使用。

devicemapper 驱动程序使用专用于 Docker 的块设备,并在块级别而不是文件级别运行。可以通过将物理存储添加到 Docker 主机来扩展这些设备,并且它们的性能优于在操作系统 (OS) 级别使用文件系统。

先决条件

  • devicemapper 在运行在 CentOS、Fedora、SLES 15、Ubuntu、Debian 或 RHEL 上的 Docker Engine - Community 上受支持。
  • devicemapper 需要安装 lvm2device-mapper-persistent-data 软件包。
  • 更改存储驱动程序会使您已创建的任何容器在本地系统上不可访问。使用 docker save 保存容器,并将现有映像推送到 Docker Hub 或私有仓库,以便您不必稍后重新创建它们。

使用 devicemapper 存储驱动程序配置 Docker

在执行以下步骤之前,您必须首先满足所有 先决条件

为测试配置 loop-lvm 模式

此配置仅适用于测试。loop-lvm 模式利用“回环”机制,允许从本地磁盘上的文件读写,就好像它们是实际的物理磁盘或块设备一样。但是,回环机制的添加以及与 OS 文件系统层的交互意味着 IO 操作可能很慢且资源密集。回环设备的使用还可能引入竞争条件。但是,设置 loop-lvm 模式可以帮助在尝试启用 direct-lvm 模式所需的更复杂设置之前识别基本问题(例如缺少用户空间软件包、内核驱动程序等)。因此,loop-lvm 模式应仅用于在配置 direct-lvm 之前执行基本测试。因此,loop-lvm 模式仅应用于在配置 direct-lvm 之前执行基本测试。

对于生产系统,请参阅 为生产环境配置 direct-lvm 模式

  1. 停止 Docker。

    $ sudo systemctl stop docker
    
  2. 编辑 /etc/docker/daemon.json。如果它尚不存在,请创建它。假设文件为空,请添加以下内容。

    {
      "storage-driver": "devicemapper"
    }

    守护进程参考文档 中查看每个存储驱动程序的所有存储选项

    如果 daemon.json 文件包含格式错误的 JSON,Docker 不会启动。

  3. 启动 Docker。

    $ sudo systemctl start docker
    
  4. 验证守护进程是否正在使用 devicemapper 存储驱动程序。使用 docker info 命令并查找 Storage Driver

    $ docker info
    
      Containers: 0
        Running: 0
        Paused: 0
        Stopped: 0
      Images: 0
      Server Version: 17.03.1-ce
      Storage Driver: devicemapper
      Pool Name: docker-202:1-8413957-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.44 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/data
      Metadata loop file: /var/lib/docker/devicemapper/metadata
      Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    

此主机正在 loop-lvm 模式下运行,该模式 **不支持** 生产系统。这由 Data loop fileMetadata loop file 位于 /var/lib/docker/devicemapper 下的文件这一事实表明。这些是回环挂载的稀疏文件。对于生产系统,请参阅 为生产环境配置 direct-lvm 模式

为生产环境配置 direct-lvm 模式

使用 devicemapper 存储驱动程序的生产主机必须使用 direct-lvm 模式。此模式使用块设备创建瘦池。这比使用回环设备更快,更有效地使用系统资源,并且块设备可以根据需要扩展。但是,与 loop-lvm 模式相比,需要更多的设置。

满足 先决条件 后,请按照以下步骤将 Docker 配置为在 direct-lvm 模式下使用 devicemapper 存储驱动程序。

警告:更改存储驱动程序会使您已创建的任何容器在本地系统上不可访问。使用 docker save 保存容器,并将现有映像推送到 Docker Hub 或私有仓库,以便您不必稍后重新创建它们。

允许 Docker 配置 direct-lvm 模式

Docker 可以为您管理块设备,简化 direct-lvm 模式的配置。这仅适用于全新的 Docker 设置。 您只能使用一个块设备。如果您需要使用多个块设备,请改为 手动配置 direct-lvm 模式。以下新的配置选项可用

选项描述必需?默认值示例
dm.directlvm_device要为 direct-lvm 配置的块设备的路径。dm.directlvm_device="/dev/xvdf"
dm.thinp_percent要从传入的块设备中使用的存储空间百分比。95dm.thinp_percent=95
dm.thinp_metapercent要从传入的块设备中使用的元数据存储空间百分比。1dm.thinp_metapercent=1
dm.thinp_autoextend_thresholdlvm 应自动扩展瘦池的阈值,以占总存储空间的百分比。80dm.thinp_autoextend_threshold=80
dm.thinp_autoextend_percent触发自动扩展时要增加的瘦池百分比。20dm.thinp_autoextend_percent=20
dm.directlvm_device_force是否即使块设备上已经存在文件系统也要格式化该块设备。如果设置为 false 并且存在文件系统,则会记录错误并且文件系统将保持不变。falsedm.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"
  ]
}

守护进程参考文档 中查看每个存储驱动程序的所有存储选项

重新启动 Docker 使更改生效。Docker 会调用命令为您配置块设备。

警告:在 Docker 为您准备块设备后更改这些值不受支持,会导致错误。

您仍然需要 执行定期维护任务

手动配置 direct-lvm 模式

以下步骤创建配置为瘦池的逻辑卷,用作存储池的备份。它假设您在 /dev/xvdf 处有一个备用块设备,具有足够的空间来完成任务。设备标识符和卷大小可能在您的环境中有所不同,您应在整个过程中用自己的值替换它们。该步骤还假设 Docker 守护进程处于 stopped 状态。

  1. 标识要使用的块设备。该设备位于 /dev/ 下(例如 /dev/xvdf),需要有足够的空间来存储主机运行的工作负载的映像和容器层。固态硬盘是理想的选择。

  2. 停止 Docker。

    $ sudo systemctl stop docker
    
  3. 安装以下软件包

    • RHEL / CentOSdevice-mapper-persistent-datalvm2 和所有依赖项

    • Ubuntu / Debian / SLES 15thin-provisioning-toolslvm2 和所有依赖项

  4. 使用 pvcreate 命令在步骤 1 中的块设备上创建一个物理卷。将您的设备名称替换为 /dev/xvdf

    警告:接下来的几个步骤具有破坏性,因此请确保您指定了正确的设备!

    $ sudo pvcreate /dev/xvdf
    
    Physical volume "/dev/xvdf" successfully created.
    
  5. 使用 vgcreate 命令在同一设备上创建一个 docker 卷组。

    $ sudo vgcreate docker /dev/xvdf
    
    Volume group "docker" successfully created
    
  6. 使用 lvcreate 命令创建两个名为 thinpoolthinpoolmeta 的逻辑卷。最后一个参数指定允许自动扩展数据或元数据(如果空间不足)的空间量,作为临时权宜之计。以下是推荐的值。

    $ sudo lvcreate --wipesignatures y -n thinpool docker -l 95%VG
    
    Logical volume "thinpool" created.
    
    $ sudo lvcreate --wipesignatures y -n thinpoolmeta docker -l 1%VG
    
    Logical volume "thinpoolmeta" created.
    
  7. 使用 lvconvert 命令将卷转换为一个精简池和一个用于精简池元数据的存储位置。

    $ sudo lvconvert -y \
    --zero n \
    -c 512K \
    --thinpool docker/thinpool \
    --poolmetadata docker/thinpoolmeta
    
    WARNING: Converting logical volume docker/thinpool and docker/thinpoolmeta to
    thin pool's data and metadata volumes with metadata wiping.
    THIS WILL DESTROY CONTENT OF LOGICAL VOLUME (filesystem etc.)
    Converted docker/thinpool to thin pool.
    
  8. 通过 lvm 配置文件配置精简池的自动扩展。

    $ sudo vi /etc/lvm/profile/docker-thinpool.profile
    
  9. 指定 thin_pool_autoextend_thresholdthin_pool_autoextend_percent 值。

    thin_pool_autoextend_threshold 是在 lvm 尝试自动扩展可用空间之前使用的空间百分比(100 = 禁用,不推荐)。

    thin_pool_autoextend_percent 是自动扩展时添加到设备的空间量(0 = 禁用)。

    下面的示例在磁盘使用率达到 80% 时添加 20% 的容量。

    activation {
      thin_pool_autoextend_threshold=80
      thin_pool_autoextend_percent=20
    }

    保存文件。

  10. 使用 lvchange 命令应用 LVM 配置文件。

    $ sudo lvchange --metadataprofile docker-thinpool docker/thinpool
    
    Logical volume docker/thinpool changed.
    
  11. 确保逻辑卷的监控已启用。

    $ 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                             not monitored
    

    如果 Monitor 列中的输出报告逻辑卷为 not monitored(如上所示),则需要显式启用监控。如果没有此步骤,逻辑卷的自动扩展将不会发生,无论应用的配置文件中设置了什么。

    $ sudo lvchange --monitor y docker/thinpool
    

    再次运行 sudo lvs -o+seg_monitor 命令,以再次检查监控是否已启用。Monitor 列现在应报告逻辑卷正在 monitored

  12. 如果您之前在此主机上运行过 Docker,或者 /var/lib/docker/ 存在,请将其移开,以便 Docker 可以使用新的 LVM 池来存储镜像和容器的内容。

    $ sudo su -
    # mkdir /var/lib/docker.bk
    # mv /var/lib/docker/* /var/lib/docker.bk
    # exit
    

    如果以下任何步骤失败,您需要还原,您可以删除 /var/lib/docker 并将其替换为 /var/lib/docker.bk

  13. 编辑 /etc/docker/daemon.json 并为 devicemapper 存储驱动配置所需的选项。如果该文件之前为空,则现在应包含以下内容。

    {
        "storage-driver": "devicemapper",
        "storage-opts": [
        "dm.thinpooldev=/dev/mapper/docker-thinpool",
        "dm.use_deferred_removal=true",
        "dm.use_deferred_deletion=true"
        ]
    }
  14. 启动 Docker。

    systemd:

    $ sudo systemctl start docker
    

    service:

    $ sudo service docker start
    
  15. 使用 docker info 验证 Docker 是否正在使用新配置。

    $ docker info
    
    Containers: 0
     Running: 0
     Paused: 0
     Stopped: 0
    Images: 0
    Server Version: 17.03.1-ce
    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: 19.92 MB
     Data Space Total: 102 GB
     Data Space Available: 102 GB
     Metadata Space Used: 147.5 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
     Thin Pool Minimum Free Space: 10.2 GB
     Udev Sync Supported: true
     Deferred Removal Enabled: true
     Deferred Deletion Enabled: true
     Deferred Deleted Device Count: 0
     Library Version: 1.02.135-RHEL7 (2016-11-16)
    <...>
    

    如果 Docker 配置正确,Data fileMetadata file 将为空白,池名称为 docker-thinpool

  16. 验证配置正确后,您可以删除包含先前配置的 /var/lib/docker.bk 目录。

    $ sudo rm -rf /var/lib/docker.bk
    

管理 devicemapper

监控瘦池

不要只依赖 LVM 自动扩展。卷组会自动扩展,但卷仍然可能填满。您可以使用 lvslvs -a 监控卷的剩余空间。考虑使用操作系统级别的监控工具,例如 Nagios。

要查看 LVM 日志,可以使用 journalctl

$ sudo journalctl -fu dm-event.service

如果您在精简池中遇到反复出现的问题,您可以在 /etc/docker/daemon.json 中将存储选项 dm.min_free_space 设置为一个值(表示百分比)。例如,将其设置为 10 确保当剩余空间在 10% 或附近时,操作将以警告失败。请参阅 引擎守护进程参考中的存储驱动选项

增加正在运行设备上的容量

您可以增加运行中的精简池设备的容量。如果数据的逻辑卷已满并且卷组已满,这将非常有用。具体的操作步骤取决于您是使用 循环 LVM 精简池 还是 直接 LVM 精简池

调整循环 LVM 精简池的大小

调整 loop-lvm 精简池大小的最简单方法是 使用 device_tool 实用程序,但您也可以 使用操作系统实用程序

使用 device_tool 实用程序

moby/moby Github 存储库中提供了一个名为 device_tool.go 的社区贡献脚本。您可以使用此工具调整 loop-lvm 精简池的大小,避免上述冗长的过程。此工具不能保证有效,但您应该只在非生产系统上使用 loop-lvm

如果您不想使用 device_tool,您可以 手动调整精简池的大小

  1. 要使用该工具,请克隆 Github 存储库,更改为 contrib/docker-device-tool,并按照 README.md 中的说明编译该工具。

  2. 使用该工具。以下示例将精简池的大小调整为 200GB。

    $ ./device_tool resize 200GB
    
使用操作系统实用程序

如果您不想 使用 device-tool 实用程序,您可以使用以下步骤手动调整 loop-lvm 精简池的大小。

loop-lvm 模式下,回环设备用于存储数据,另一个用于存储元数据。loop-lvm 模式仅支持测试,因为它具有显著的性能和稳定性缺陷。

如果您使用的是 loop-lvm 模式,docker info 的输出将显示 Data loop fileMetadata loop file 的文件路径。

$ docker info |grep 'loop file'

 Data loop file: /var/lib/docker/devicemapper/data
 Metadata loop file: /var/lib/docker/devicemapper/metadata

按照以下步骤增加精简池的大小。在本例中,精简池为 100 GB,并增加到 200 GB。

  1. 列出设备的大小。

    $ sudo ls -lh /var/lib/docker/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. 使用 truncate 命令将 data 文件的大小增加到 200G,该命令用于增加 **或** 减少文件的大小。请注意,减小大小是一个破坏性操作。

    $ sudo truncate -s 200G /var/lib/docker/devicemapper/data
    
  3. 验证文件大小是否已更改。

    $ sudo ls -lh /var/lib/docker/devicemapper/
    
    total 1.2G
    -rw------- 1 root root 200G Apr 14 08:47 data
    -rw------- 1 root root 2.0G Apr 19 13:27 metadata
    
  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. 转储精简池的 device mapper 表。

    $ sudo dmsetup table docker-8:1-123141-pool
    0 209715200 thin-pool 7:1 7:0 128 32768 1 skip_block_zeroing
    

    c. 使用输出的第二个字段计算精简池的总扇区数。该数字以 512k 扇区表示。一个 100G 文件有 209715200 个 512k 扇区。如果将其翻倍到 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-pool 7:1 7:0 128 32768 1 skip_block_zeroing'
    $ sudo dmsetup resume docker-8:1-123141-pool
    

调整直接 LVM 精简池的大小

要扩展 direct-lvm 精简池,您需要首先将新的块设备附加到 Docker 主机,并记下内核为其分配的名称。在本例中,新的块设备为 /dev/xvdg

按照以下步骤扩展 direct-lvm 精简池,将您的块设备和其他参数替换为适合您情况的参数。

  1. 收集有关卷组的信息。

    使用 pvdisplay 命令查找当前由您的精简池使用的物理块设备以及卷组的名称。

    $ sudo pvdisplay |grep 'VG Name'
    
    PV Name               /dev/xvdf
    VG Name               docker
    

    在以下步骤中,根据需要替换您的块设备或卷组名称。

  2. 使用 vgextend 命令扩展卷组,使用上一步中的 VG Name 以及您 **新的** 块设备的名称。

    $ sudo vgextend docker /dev/xvdg
    
    Physical volume "/dev/xvdg" successfully created.
    Volume group "docker" successfully extended
    
  3. 扩展 docker/thinpool 逻辑卷。此命令立即使用卷的 100%,不进行自动扩展。要扩展元数据精简池,请使用 docker/thinpool_tmeta

    $ sudo lvextend -l+100%FREE -n docker/thinpool
    
    Size of logical volume docker/thinpool_tdata changed from 95.00 GiB (24319 extents) to 198.00 GiB (50688 extents).
    Logical volume docker/thinpool_tdata successfully resized.
    
  4. 使用 docker info 输出中的 Data Space Available 字段验证新的精简池大小。如果您扩展的是 docker/thinpool_tmeta 逻辑卷,请查找 Metadata Space Available

    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: 212.3 MB
     Data Space Total: 212.6 GB
     Data Space Available: 212.4 GB
     Metadata Space Used: 286.7 kB
     Metadata Space Total: 1.07 GB
     Metadata Space Available: 1.069 GB
    <...>

在重新引导后激活 devicemapper

如果您重新启动主机并发现 docker 服务启动失败,请查找错误“Non existing device”。您需要使用以下命令重新激活逻辑卷。

$ sudo lvchange -ay docker/thinpool

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/docker/devicemapper/mnt/ 目录包含每个存在镜像和容器层的挂载点。镜像层挂载点为空,但容器的挂载点显示容器的文件系统,如同从容器内部查看一样。

映像分层和共享

devicemapper 存储驱动使用专用的块设备而不是格式化的文件系统,并在块级别操作文件,以便在写入时复制 (CoW) 操作期间获得最大性能。

快照

devicemapper 的另一个功能是它使用快照(有时也称为 *精简设备* 或 *虚拟设备*),这些快照将每个层中引入的差异存储为非常小的、轻量级的精简池。快照提供许多好处。

  • 容器之间共享的层仅在磁盘上存储一次,除非它们是可写的。例如,如果您有 10 个不同的镜像,它们都基于 alpine,则 alpine 镜像及其所有父镜像在磁盘上仅存储一次。

  • 快照是写入时复制 (CoW) 策略的实现。这意味着只有当容器修改或删除给定文件或目录时,该文件或目录才会被复制到容器的可写层。

  • 由于 devicemapper 在块级别运行,因此可写层中的多个块可以同时修改。

  • 可以使用标准操作系统级备份实用程序备份快照。只需复制 /var/lib/docker/devicemapper/ 即可。

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` 容器。

Ubuntu and busybox image layers

容器如何使用 devicemapper 进行读写

读取文件

使用 `devicemapper` 时,读操作发生在块级别。下图显示了在一个示例容器中读取单个块(`0x44f`)的高级过程。

Reading a block with devicemapper

应用程序在容器中发出对块 `0x44f` 的读请求。由于容器是对镜像的薄快照,它不包含该块,但它拥有指向该块在最近父镜像中的位置的指针,并且它从那里读取该块。现在该块存在于容器的内存中。

写入文件

**写入新文件:** 使用 `devicemapper` 驱动器时,向容器写入新数据是通过**按需分配**操作完成的。新文件的每个块都会在容器的可写层中分配,并且该块被写入那里。

**更新现有文件:** 文件的相关块从其存在的最接近的层读取。当容器写入文件时,只有修改的块才会写入容器的可写层。

**删除文件或目录:** 当你在容器的可写层中删除文件或目录时,或者当镜像层删除在其父层中存在的文件时,`devicemapper` 存储驱动器会拦截对该文件或目录的后续读取尝试,并响应该文件或目录不存在。

**写入文件,然后删除文件:** 如果容器写入文件,然后删除文件,所有这些操作都在容器的可写层中进行。在这种情况下,如果你使用的是 `direct-lvm`,这些块会被释放。如果你使用的是 `loop-lvm`,这些块可能不会被释放。这是在生产环境中不使用 `loop-lvm` 的另一个原因。

Device Mapper 和 Docker 性能

  • **按需分配**性能影响:

    `devicemapper` 存储驱动器使用**按需分配**操作,将薄池中的新块分配到容器的可写层中。每个块大小为 64KB,因此这是写入所使用的最小空间量。

  • **写时复制性能影响:** 当容器第一次修改特定块时,该块会被写入容器的可写层。由于这些写入发生在块级别而不是文件级别,因此性能影响最小化。但是,写入大量块仍然会对性能产生负面影响,并且 `devicemapper` 存储驱动器在这种情况下实际上可能会比其他存储驱动器表现更差。对于写入密集型工作负载,你应该使用数据卷,它完全绕过存储驱动器。

性能最佳实践

使用 `devicemapper` 存储驱动器时,请记住以下几点,以最大限度地提高性能。

  • **使用 `direct-lvm`:** `loop-lvm` 模式性能不佳,不应在生产环境中使用。

  • **使用快速存储:** 固态硬盘 (SSD) 提供比旋转磁盘更快的读写速度。

  • **内存使用情况:** `devicemapper` 使用的内存比其他一些存储驱动器更多。每个启动的容器会将一个或多个文件副本加载到内存中,具体取决于同时修改的文件的块数。由于内存压力,`devicemapper` 存储驱动器可能不适合在高密度使用情况下某些工作负载。

  • **对写入密集型工作负载使用卷:** 卷为写入密集型工作负载提供最佳且最可预测的性能。这是因为它们绕过存储驱动器,并且不会产生薄配置和写时复制带来的任何潜在开销。卷还有其他优势,例如允许你在容器之间共享数据,并且即使在没有运行的容器使用它们时也能持久保存。

  • **注意:** 使用 `devicemapper` 和 `json-file` 日志驱动器时,容器生成的日志文件仍然存储在 Docker 的数据根目录中,默认情况下为 `/var/lib/docker`。如果你的容器生成大量日志消息,这可能会导致磁盘使用量增加,或者由于磁盘已满而无法管理你的系统。你可以配置一个 日志驱动器,将容器日志外部存储。