绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
深入 Docker 存储引擎
2020-05-09 11:51:44

前言

Docker 存储引擎对于普通开发人员来说可能并不关心,主要是性能和稳定性上的综合考虑,不过 Docker 存储引擎的设计思想还是非常值得学习的。

设计思想

Docker 存储引擎的核心思想是“层”的概念,理解了这个层,就基本可以理解它的设计思路。当我们拉取一个 Docker 镜像的时候,往往看到如下界面。


一个镜像被分成许多的“层”,每“层”包含了若干的文件,而一层层堆叠起来就组成了我们的一个完整的镜像。我们镜像中的文件就是所有“层”文件的并集。

我们构建 Docker 镜像一般采用 Dockerfile 的方式,而 Dockerfile 的每行命令,其实就会生成一个“层”,即使什么文件都没有添加。

FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py



Docker 的镜像(image)是静态的,所以当镜像构建完成后,所有的层都是只读的,并会赋予一个的 ID。而容器(container)是动态的,当容器启动后,Docker 会给这个容器创建一个可读写“层”,位于所有镜像“层”的上面。我们对容器的所有操作也就是在这个“层”里完成,当我们执行 docker commit 将容器生成镜像的时候,就是把这个“层”给拍了个快照,添加了一个新的只读层。


文件的创建是在读写层增加文件,那修改和删除呢?

这就要提一下 Docker 设计的 copy-on-write (CoW) 策略。

当我们试图读取一个文件时,Docker 会从上到下一层层去找这个文件,找到的个就是我们的文件。所以下面层相同的文件就被“覆盖”了。而修改就是当我们找到这个文件时,将它“复制”到读写层并修改,这样读写层的文件就是我们修改后的文件,并且“覆盖”了镜像中的文件了。而删除就是创建了一个特殊的 whiteout 文件,这个 whiteout 文件覆盖的文件即表示删除了。


这样的设计有什么好处吗?

显而易见的就是减少了存储空间,由于镜像被分成了多个层,而各个层是静态只读的,是可以共享的。当你从一个镜像构建另一个镜像时,只需要添加新的层,原有的层不会被复制。

我们可以用 docker history 命令查看我们创建的镜像,相同的层将共享且只保存一份。



我们可以在系统的 /var/lib/docker/<存储驱动>/ 下看到我们所有的层。

第二个好处是启动容器就变得非常轻量和快速。因为我们的容器只是添加了一个“空”的读写层,其他的都是复用的只读层,需要用时才会去搜索。



因此,服务器上存储了上百个镜像,启动了上千个容器,一点也不费力。

存储驱动

Docker 的存储引擎设计思路是这样,但是针对不同的文件系统,是由不同的存储驱动去实现的。下面我们来聊聊 Docker 的存储驱动。

Docker 主要有一下几类存储驱动:

  • overlay2:是当前版本推荐的存储驱动,无需额外的依赖和配置即可发挥的性能。在 18.09 版本之后替换了 overlay 存储驱动。支持 xfs,ext4 文件系统。
  • aufs:Docker 早期使用的存储驱动,是 Docker 18.06 版本之前,Ubuntu 14.04 版本前推荐的。支持 xfs,ext4 文件系统。
  • devicemapper:是较早版本的 CentOS 和 RHEL 系统推荐的存储驱动,因为它们不支持 overlay2,需要 direct-lvm 的支持。
  • btrfs:仅用于 btrfs 文件系统。
  • zfs:仅用于 zfs 文件系统。
  • vfs:不依赖于文件系统,但是性能奇差,主要用来测试。

需要注意的是,overlay2,overlay,aufs 的层是基于文件的,当单文件的写并发较高时需要大内存的支持,且读写层可能因为单个文件而变得很大。devicemapper,btrfs,zfs 的层是基于块存储的,因此对于单个文件的高并发影响不大。但是 btrfs 和 zfs 非常消耗内存。

有条件的情况下,我们还是建议选择 overlay2 的存储驱动。

配置存储驱动

配置 Docker 存储驱动非常简单,只需要修改配置文件即可。

注意,如果你原先有不同存储驱动的层数据,更换存储驱动后将不可用,建议备份镜像并清除 /var/lib/docker 下所有数据。

备份镜像可以用 docker save 导出镜像,之后用 docker load 导入镜像。

创建或修改文件 /etc/docker/daemon.json 并添加

{
  "storage-driver": "overlay2"
}

然后重启 Docker

systemctl restart docker

OverlayFS

下面我们重点讲讲 overlayFS(overlay2 和 overlay)。

overlayFS 是从 aufs 之上改进和简化而来的,比 aufs 和 devicemapper 有更好的性能,大部分情况下也比 btrfs 好。

它将文件简化为上、下两层,上面的称为 upperdir,可读写,下面的称为 lowerdir,只读,统一后暴露的视图称为 merged


它有如下特性:

页缓存:overlayFS 支持页缓存分享,多个容器如果读取相同层的同一个文件,可以共享页缓存,有效利用内存,使得它对于高并发读场景十分高效。

层查找:由于次修改只读层文件时需要复制到读写层,所以对于大文件会有一些延迟。但是 overlayFS 还是比 aufs 更快,因为在搜索和缓存方面做了不少优化。

重命名:overlayFS 不支持不同层文件的重命名操作,需要修改为复制然后删除。

佳实践

  • 尽可能使用 SSD 等高性能存储
  • 对于大量写场景,建议使用外挂盘(Volume)的方式

参考

分享好友

分享这个小栈给你的朋友们,一起进步吧。

Docker 专区
创建时间:2020-05-08 10:53:18
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux或Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

技术专家

查看更多
  • 小雨滴
    专家
戳我,来吐槽~