Docker 存储引擎对于普通开发人员来讲可能并不关心,主要是性能和稳定性上的综合考虑,不过 Docker 存储引擎的设计思想仍是很是值得学习的。python
Docker 存储引擎的核心思想是“层”的概念,理解了这个层,就基本能够理解它的设计思路。docker
当咱们拉取一个 Docker 镜像的时候,每每看到以下界面。json
一个镜像被分红许多的“层”,每“层”包含了若干的文件,而一层层堆叠起来就组成了咱们的一个完整的镜像。咱们镜像中的文件就是全部“层”文件的并集。ubuntu
咱们构建 Docker 镜像通常采用 Dockerfile 的方式,而 Dockerfile 的每行命令,其实就会生成一个“层”,即便什么文件都没有添加。缓存
FROM ubuntu:15.04
COPY . /app
RUN make /app
CMD python /app/app.py
复制代码
Docker 的镜像(image)是静态的,因此当镜像构建完成后,全部的层都是只读的,并会赋予一个惟一的 ID。而容器(container)是动态的,当容器启动后,Docker 会给这个容器建立一个可读写“层”,位于全部镜像“层”的最上面。咱们对容器的全部操做也就是在这个“层”里完成,当咱们执行 docker commit
将容器生成镜像的时候,就是把这个“层”给拍了个快照,添加了一个新的只读层。bash
文件的建立是在读写层增长文件,那修改和删除呢?服务器
这就要提一下 Docker 设计的 copy-on-write (CoW) 策略。并发
当咱们试图读取一个文件时,Docker 会从上到下一层层去找这个文件,找到的第一个就是咱们的文件。因此下面层相同的文件就被“覆盖”了。而修改就是当咱们找到这个文件时,将它“复制”到读写层并修改,这样读写层的文件就是咱们修改后的文件,而且“覆盖”了镜像中的文件了。而删除就是建立了一个特殊的 whiteout
文件,这个 whiteout
文件覆盖的文件即表示删除了。app
这样的设计有什么好处吗?高并发
显而易见的就是减小了存储空间,因为镜像被分红了多个层,而各个层是静态只读的,是能够共享的。当你从一个镜像构建另外一个镜像时,只须要添加新的层,原有的层不会被复制。
咱们能够用 docker history
命令查看咱们建立的镜像,相同的层将共享且只保存一份。
咱们能够在系统的 /var/lib/docker/<存储驱动>/
下看到咱们全部的层。
第二个好处是启动容器就变得很是轻量和快速。由于咱们的容器只是添加了一个“空”的读写层,其余的都是复用的只读层,须要用时才会去搜索。
所以,服务器上存储了上百个镜像,启动了上千个容器,一点也不费力。
Docker 的存储引擎设计思路是这样,可是针对不一样的文件系统,是由不一样的存储驱动去实现的。下面咱们来聊聊 Docker 的存储驱动。
Docker 主要有一下几类存储驱动:
须要注意的是,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(overlay2 和 overlay)。
overlayFS 是从 aufs 之上改进和简化而来的,比 aufs 和 devicemapper 有更好的性能,大部分状况下也比 btrfs 好。
它将文件简化为上、下两层,上面的称为 upperdir
,可读写,下面的称为 lowerdir
,只读,统一后暴露的视图称为 merged
。
它有以下特性:
页缓存:overlayFS 支持页缓存分享,多个容器若是读取相同层的同一个文件,能够共享页缓存,有效利用内存,使得它对于高并发读场景十分高效。
层查找:因为第一次修改只读层文件时须要复制到读写层,因此对于大文件会有一些延迟。可是 overlayFS 仍是比 aufs 更快,由于在搜索和缓存方面作了很多优化。
重命名:overlayFS 不支持不一样层文件的重命名操做,须要修改成复制而后删除。