参考文章:[深入浅出 Docker]
Docker 存储驱动的选择
每个 Docker 容器都有一个本地存储空间,用于保存层叠的镜像层(Image Layer)以及挂载的容器文件系统。默认情况下,容器的所有读写操作都发生在其镜像层上或挂载的文件系统中。所以存储是每个容器的性能和稳定性不可或缺的一个环节。
以往,本地存储是通过存储驱动(Storage Driver)进行管理的,有时候也被称为 Graph Driver
或者 GraphDriver
。虽然存储驱动在上层抽象设计中都采用了栈式镜像层存储和写时复制(Copy-on-Write
)的设计思想,但是 Docker 在 Linux 底层支持几种不同的存储驱动的具体实现,每一种实现方式都采用不同方法实现了镜像层和写实复制。虽然底层实现的差异不影响用户与 Docker 之间的交互,但是对 Docker 的性能和稳定性至关重要。
在 Linux 上,Docker 可选择的一些存储驱动包括 AUFS
(最原始也是最老的),Overlay2
(可能是未来的最佳选择),Device Mapper
,Btrfs
和 ZFS
。
Docker 在 Windows 操作系统上只支持一种存储驱动,即 Windows Filter
.
存储驱动的选择是节点级别的,这意味着每个 Docker 主机只能选择一种存储驱动,而不能为每个容器选择不同的存储驱动。在 Linux 上,可以通过修改 /etc/docker/daemon.json
文件来修改存储引擎配置,修改完后需要重启 Docker 才能够生效。
- 下面代码片段展示了如何将存储驱动设置为
overlay2
1 | { |
注:如果配置所在行不是文件的最后一行,则需要在行尾处添加逗号
,
如果修改了正在运行 Docker 主机的存储引擎类型,则现有镜像和容器在重启之后将不可用,这是因为每种存储驱动在主机上存储镜像层的位置是不同的(通常在 /var/lib/docker/<storage-driver>/...
目录下)。修改了存储驱动的类型,Docker 就无法找到原有的镜像和容器了。切换到原来的存储驱动,之前的镜像和容器就可以继续使用了。
如果希望在切换存储引擎之后还能够继续使用之前的镜像和容器,需要将镜像保存为 Docker 格式,上传到某个镜像仓库,修改本地 Docker 存储引擎并重启,之后从镜像仓库将镜像拉取到本地,最后重启容器。
- 通过下面的命令来检查 Docker 当前的存储驱动类型
1 | # docker system info |
选择存储驱动并正确地配置在 Docker 环境中是一件重要的事情,特别是在生产环境中。下面的清单可以作为一个参考指南,帮助我们选择合适的存储驱动。但是仍然建议参考 Docker 官网上由 Linux 发行商提供的最新文档来做出选择。
- 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。
再次强调,上面的清单内容只是一个参考建议,读者需要时刻关注 Docker 文档中关于存储驱动的最新支持和版本兼容列表。尤其是正在使用 Docker 企业版(EE), 并且有售后支持合同的情况下,更有必要查阅最新文档。
Device Mapper 配置
大部分 Linux 存储驱动不需要或需要很少的配置。但是,Device Mapper
通常需要合理配置之后才能表现出良好的性能。
默认情况下,Device Mapper
采用 loopback mounted sparse file
作为底层实现来为 Docker 提供存储支持。如果我们需要的是开箱即用并且对性能没什么要求,那么这种方式是可行的。但是这并不适合用于生产环境。实际上,默认方式的性能很差,并不支持生产环境。
为了达到 Device Mapper 在生产环境中的最佳性能,读者需要将底层实现修改为 direct-lvm
模式。这种模式下通过使用基于裸块设备(Raw Block Device)的LVM 精简池(LVM thin pool)来获取更好的性能。
在 Docker 17.06 以及更高版本中可以配置 direct-lvm
作为存储驱动。但是在本书撰写时,该方式存在某种限制。其中最主要的一点是,这种方式只能配置一个块设备,并且只有在第一次安装后才能设置生效。未来可能会有改进,但是就目前情况来看配置单一块设备这种方式在性能和可靠性上都有一定的风险。
让 Docker 自动设置 direct-lvm
下面的步骤会将 Docker 配置存储驱动为 Device Mapper,并使用 direct-lvm 模式。
将下面的存储驱动配置添加到
/etc/docker/daemon.json
当中.1
2
3
4
5
6
7
8
9
10
11{
"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"
]
}Device Mapper 和 LVM 是很复杂的知识点,并不在本书的讨论范围之内。下面简单介绍一下各配置项的含义:
- dm.directlvm_device: 设置了块设备的位置。为了存储的最佳性能以及可用性,块设备应当位于高性能存储设备(如本地 SSD)或者外部 RAID 存储阵列上;
- dm.thinp_percent: 设置了镜像和容器允许使用的最大存储空间占比,默认是 95%;
- dm.thinp_metapercent: 设置了元数据存储(MetaData Storage)允许使用的存储空间大小。默认是 1%;
- dm.thinp_autoextend_threshold: 设置了 LVM 自动扩展精简池的阈值,默认是 80%;
- dm.thinp_autoextend_percent: 表示当触发精简池自动扩容机制的时候,扩容的大小应当占现有空间的比例;
- dm.directlvm_device_force: 允许用户决定是否将块设备格式化为新的文件系统。
重启 Docker
确认 Docker 已经成功运行,并且块设备配置已被成功加载。
1
docker version
即使 Docker 在 driver-lvm 模式下智能设备单一块设备,其性能也会显著优于 loopback 模式;