什么是docker的写时复制(CoW)?有什么作用?
问题一个问题:docker CoW你知道是什么吗?
1、什么是CoW?
CoW = Copy-On-Write
也就是,你经常会听到的一个词,叫做:写时复制。
那么,到底什么是写时复制,究竟有什么样的作用呢?
2、CoW有什么作用?
下面的部分,咱们就逐一进行揭晓:
首先,写时复制策略,是一种共享、拷贝文件的方法,用以最大化的提高效率。我们都知道,镜像是以多层的的方式存在的,如果有一个文件,在镜像的较低层中已经存在了,当其他的层需要读取这个文件的时候,就只是使用这个已经存在的文件。
是不是,听着有点懵,没关系,我们接着看:当第一次,另外的一个层需要修改这个文件的时候(构建镜像和运行容器的场景),在较低层中的文件被拷贝到这个需要的层,然后进行修改。简单来说,就是需要修改哪个文件,就拷贝哪个文件,然后进行修改,这样在构建或者运行容器,修改文件时,就最小化了拷贝的I/O的大小。同时,后面的层,无论是容器的可写层,还是镜像层的大小也将保持比较小的大小。
3、CoW的好处?
下面的部分,我们更加详细的解释,CoW策略的好处:
3.1、共享镜像层减少镜像的大小
先说第一个最大的好处:共享的好处,减少镜像的大小。
当通过docker pull命令从镜像仓库拉取镜像,当本地没有这个镜像的时候,镜像的每一层都会被单独的拉取下来,然后存储到docker所在主机的存储目录中。
镜像的每一层都存储在自己的目录中,这些目录在docker宿主机的本地存储区域中(比如某个目录下,一般/var/lib/docker/<存储驱动>,当然可以修改目录的地址)。
假如,有2个Dockerfile,第一个创建一个镜像,名字:acme/my-base-image:1.0
# syntax=docker/dockerfile:1 FROM alpine RUN apk add --no-cache bash
第2个镜像,基于这个镜像(from),然后,增加了一些额外的层
# syntax=docker/dockerfile:1 FROM acme/my-base-image:1.0 COPY . /app RUN chmod +x /app/hello.sh CMD /app/hello.sh
第2个镜像包含了第1个镜像的所有的层,然后增加了一些其他的层。
由于docker在构建第1个镜像的时候,已经有了所有的层,所以呢,就不需要再次的拉取这些层。简单来说,就是这2个镜像在某些层上是共用的。
如果通过以上的2个Dockerfile来构建镜像,可以使用dokcer images 和 docker image history 命令看到,这些共享层的加密ID是相同的。
并且,共享的镜像的层,在docker的存储目录中,只有一份。同时呢,即使在向镜像仓库推送、存储的时候,也仅仅是存储一份,也是共享的。共享镜像层,也减少网络贷款和存储空间的大小。
3.2、复制使容器更高效
我们都知道,当启动一个容器的时候,会在所有的层上面增加一个可写的容器层。容器对于文件系统的任何的修改,都存储在这个层里面。最重要的,任何容器不会修改的文件,都不会被拷贝到这个可写层中来。也就是说,可写层会尽可能的小。
当需要在容器中对一个已经存在文件做修改时,存储驱动会执行一个写时拷贝的动作。具体的步骤如下(针对overlay2存储驱动):
- 在镜像层中搜索该文件的最新版本。整个的搜索文件的过程,先从最上层,也就是最新的层开始,然后一直到最基础的层,每次只搜搜一层(当然,前提是当前层,没有找到)。当这个文件被找到的时候,会将这个文件加载到缓存中,为后续的操作做好准备。
- 将文件拷贝到容器的可写层
- 所有的修改,都是在这个文件的拷贝上执行的,容器无法看到存在于底层的只读状态的文件的拷贝。也就是说,对于容器来说,不管底层的文件的,只是对需要的文件的副本进行修改。
记住,对于容器来说,那些需要写大量数据的容器会消耗比较大的空间。因为,当进行写的操作的时候,会消耗容器的可写层的空间。
注意:修改文件的元数据(比如文件的权限,所有者),同样会执行拷贝的动作,因此,也会将文件拷贝到可写层。
注意,注意!文件的拷贝的操作是有性能的开销的。对于大文件,多镜像层,多级的目录树来说,这样的影响会比较显著。
所以,简单来说,只是在可写层,对需要的文件进行拷贝,也减少了容器层的大小。
同时,对于容器的启动来说,仅仅是执行命令即可,减少容器的启动时间。
4、总结
我们来总结一下,CoW是什么,好处是什么?
CoW(Copy On Write):写时复制
好处:
- 共享镜像层,减少镜像大小、占用存储空间大小
- 减少容器大小
- 减少容器的启动时间
- 当多个容器使用相同镜像时,只需创建可写层
对比:
如果Docker每次创建一个新容器时都必须对底层映像堆栈进行完整的复制,那么容器创建时间和磁盘空间的使用将会显著增加。这类似于虚拟机的工作方式,每个虚拟机有一个或多个虚拟磁盘。