Docker 存储驱动介绍

每个 Docker 容器都有一个本地存储空间,用于保存层叠的镜像层(image layer)以及挂载的容器文件系统。

默认情况下,容器所有的读写操作都发生在其镜像层或挂载的文件系统中,所以存储是每个容器的性能和稳定性不可或缺的一个环节

以往,本地存储是通过存储驱动(Storage Driver)进行管理的,有时候也被称为 Graph Driver 或者 GraphDriver。

虽然存储驱动在上层抽象设计中都采用了栈式镜像层存储和写时复制(Copy-on-write)的设计思想,但是 Docker 在 linux 底层支持几种不同的存储驱动的具体实现,每一种实现方式都采用不同方法实现了镜像层和写时复制

虽然底层实现的差异不影响用户与 Docker 之间的交互,但是对 Docker 的性能和稳定性至关重要

Docker 在 linux 上的存储驱动

  • AUFS
  • Overlay2
  • Device Mapper
  • Btrfs —- 新版的文件系统,功能强大,支持 raid,以及使用量限制等
  • ZFS

Docker 在 windows 的存储驱动

  • filter

存储驱动配置

修改存储驱动

可以通过修改 /etc/docker/daemon.json 文件来修改存储驱动

[root@centos7 docker]# cat daemon.json 
{"storage-driver":"overlay2"},

找不到 daemon.json 文件的解决方法

官方说法,新创建一个即可

To configure the Docker daemon using a JSON file, create a file at /etc/docker/daemon.json on Linux systems, or C:\ProgramData\docker\config\daemon.json on Windows. On MacOS go to the whale in the taskbar > Preferences > Daemon > Advanced.

如果修改了正在运行 docker 主机的存储引擎类型,则现有的镜像和容器在重启后将不可用,这时因为每种存储驱动在主机上存储镜像层的位置是不同的(通常在 /var/lib/docker/ /… 目录下)

[root@centos7 ~]# ls /var/lib/docker/
builder  buildkit  containers  image  network  overlay2  plugins  runtimes  swarm  tmp  trust  volumes

修改了存储驱动的类型,Docker 就无法找到原有镜像和容器了。切换到原来的存储驱动,之前的镜像和容器就可以继续使用了。

如果希望在切换存储引擎之后还能继续使用之前的镜像和容器,需要将镜像保存为 docker 格式,上传到某个镜像仓库,修改本地 docker 存储引擎并重启,之后从镜像仓库将镜像拉取到本地,最后重启容器。

之所以 docker 更改存储驱动后找不到镜像的原因,就是 docker 需要通过存储驱动来与磁盘上的真实数据的镜像来交换数据。但是如果更换了存储驱动,那么进程中的 docker 将不会再寻找到磁盘中的镜像。

但是将镜像保存为 docker 模式就相当于将镜像打包传输到镜像仓库中,再重新拉取到本地来运行,最后重启容器,与直接重启服务的相差之处就是这种办法不会丢失现有正在运行的镜像。

命令检查驱动当前驱动类型

[root@centos7 ~]# docker system info
Client:
 Debug Mode: false

Server:
 Containers: 0
  Running: 0
  Paused: 0
  Stopped: 0
 Images: 0
 Server Version: 19.03.13
 Storage Driver: overlay2        ---正在使用的存储驱动
  Backing Filesystem: xfs
  Supports d_type: true
  Native Overlay Diff: true

各大系统巨头提供的官方使用存储驱动建议

  • Red Hat Enterprise Linux:4.x版本内核或更高版本 + Docker 17.06 版本或更高版本,建议使用 Overlay2。
  • Red Hat Enterprise Linux:低版本内核或低版本的 Docker,建议使用 Device Mapper。
  • Ubuntu Linux:4.x 版本内核或更高版本,建议使用 Overlay2。
  • Ubuntu Linux:更早的版本建议使用 AUFS。
  • SUSE Linux Enterprise Server:Btrfs。

Device Mapper 配置

大部分 linux 存储驱动不需要或需要很少的配置。但是 Device Mapper 通常需要合理配置之后才能表现出良好的性能。

Device Mapper 简介

Device Mapper是一个基于kernel的框架,它增强了很多Linux上的高级卷管理技术。Docker的devicemapper驱动在镜像和容器管理上,利用了该框架的超配和快照功能。为了区别。

默认情况下,Device Mapper 采用 loopback mounted sparse file 作为底层来为 Docker 提供存储支持。

如果需要的是开箱即用并且对性能没什么要求,那么这种方式是可行。但这并不适用于生产环境。实际上,默认方式的性能很差,并不支持生产环境。

为了达到 Device Mapper 在生产环境中的最佳性能,需要将底层修改为 direct-lvm 模式。

Device Mapper 的 direct-lvm 模式

这种模式下通过使用基于裸设备(Ram Block Device)的 LVM 精简池(LVM thin pool)来获取更好的性能。

这种方式只能配置一个块设备,并且只有在第一次安装后才能设置生效。未来可能会有改进,但就目前情况来看配置单一块设备这种方式在性能和可靠性上都有一定的风险。

让 Docker 自动设置 direct-lvm

将存储配置添加到 /etc/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"
    ]
}
  • dm.directlvm_device:设置了块设备的位置。为了存储最佳性能以及可用性,块设备应当位于高性能存储设备(如本地 SSD)或者外部的 RAID 存储阵列之上。
  • dm.thinp_percent=95:设置了镜像和容器允许使用的最大存储空间占比,默认为 95%
  • dm.thinp_metapercent:设置了元数据存储(MetaData Storage)允许使用的存储空间大小,默认是 1%
  • dm.thinp_autoextend_threshold:设置了 LVM 自动扩展精简池的阈值,默认为 80%
  • dm.thinp_autoextend_percent:表示当触发精简池(thin pool)自动扩容机制的时候,扩容的大小应当占现有空间的比例。
  • dm.directlvm_device_force:允许用户决定是否将块设备格式化为新的文件系统。+

重启 docker

手动配置 Device Mapper 的 direct-lvm

块设备

使用 direct-lvm 模式的时候,读者需要有可用的块设备,这些块设备应该位于高性能的存储设备之上,必须本地 SSD 或者外部高性能 LUN 存储。

如果 Docker 环境部署在企业私有云(On-Premise)之上,那么外部 LUN(逻辑单元号)存储可以使用 FC、ISCSI,或者其他支持块设备协议的磁盘阵列。

如果 Docker 环境部署在公有云之上,那么可以采用公有云厂商提供的任何高性能的块设备(通常基于 SSD)

LVM 配置

Docker 的 Device Mapper 存储驱动底层利用 LVM 来实现,因此需要配置 LVM 所需的物理设备、卷组、逻辑卷和精简池。

应当使用专用的物理卷并将其配置在相同的卷组当中。这个卷组不应当被 Docker 之外的工作负载所使用。

此外还需要配置额外两个逻辑卷,分别用于存储数据和源数据信息。另外,要创建 LVM 配置文件、指定 LVM 自动扩容的触发阈值,以及自动扩容的大小,并且自动扩容配置响应的监控,保证自动扩容被触发。

Docker 配置

修改 Docker 配置文件之前要先保存原始文件(etc/docker/daemon.json),然后再进行修改。

环境中的 dm.thinpooldev 配置项对应值可以跟下面的示例内容有所不同,需要修改为合适的配置。

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