作者:三十
起源:恒生 LIGHT 云社区
Docker 是如何组织存储的
dokcer 在组织存储内容时很奇妙的利用了分层复用的思维。所以咱们能够以此为案例学习一下该思维。
1. 镜像分层
一个 Docker 镜像在构建的过程中分了很多层,每一层都是只读的。联合上面例子进行阐明:
# syntax=docker/dockerfile:1
FROM ubuntu:18.04
LABEL org.opencontainers.image.authors="org@example.com"
COPY . /app
RUN make /app
RUN rm -r $HOME/.cache
CMD python /app/app.py
这个 Dockerfile 中会有 4 条指令扭转了文件系统并创立了新层。
FROM
指令从 ubuntu:18.04 的镜像中创立了根底层。LABEL
指令仅仅批改了镜像的元数据,不会创立新层。COPY
指令将执行本次构建的当前目录中的内容增加到镜像当中,会创立一个新层记录扭转。- 第一个
RUN
指令,构建了程序并将后果输入到镜像中,会创立一个新层记录扭转。 - 第二个
RUN
指令,删除了缓存目录,会创立一个新层记录扭转。 CMD
指令定义了容器中运行的指令,只是批改了镜像的元数据,并不会创立新层。
这里每层都只记录与其上一层的不同。当咱们创立一个容器的时候,这是就会创立一层可写层,也叫容器层。对于正在运行中的容器的内容的变动都会记录在该层中。下图形容了该关系:
2. 容器分层
容器和镜像的不同次要是最顶层的可写层的不同,所有对于容器的写操作都会记录在这层中,如果容器被删除,那么这个可写层也会被删除,然而镜像会被保留。
留神:如果想要多个容器共享雷同的数据,能够通过 Docker Volumes 实现。
每个容器都有其本人的可写层,所有的变换都会被寄存在其中,所以多个容器可共享同一个镜像。下图形容了该关系:
留神 :此处还有个细节,多个镜像可能共用雷同的层,比方两个镜像中有雷同的层,那么在构建或是拉取的时候发现本地以存在,则不会再次构建或拉取。所以计算镜像大小的时候,不能仅通过 docker images
命令显示出的大小来汇总求和,该值有可能大于理论值。
3. 容器在磁盘占用的空间
能够通过 docker ps -s
命令,来看正在运行中的容器占用的空间(局部值)。两个列的不同代表的内容:
- size:容器的可写层占用的磁盘大小
- virtual size:蕴含了容器可写层和只读镜像的大小。
容器占用磁盘空间的其它路径:
- 容器产生的日志文件。
- 应用 Volume 和 bind mounts 挂载的内容。
- 容器的配置文件
- 内存中的内容(如果开启了 swapping)
- Checkpoints(如果应用了该性能)
4.Copy-on-Write(CoW)策略
Docker 中的存储驱动都是采纳该策略。
CoW 策略可能最大效率的共享和复制文件。如果一个文件在镜像的更低层存在,那么其下层(包含可写层)须要读取该内容则能够间接应用该文件。当须要对其进行批改时,会复制该文件到该层并进行批改。这最大限度的缩小了 IO 和每个后续层的大小。
4.1 共享使镜像更小
当咱们应用 docker pull
拉取镜像或是应用一个本地没有的镜像创立容器的时候,该镜像会被分层的存储到本地 Dockers 存储区域中。在 linux 中通常是 /var/lib/docker
。
咱们能够去 /var/lib/docker/<storage-driver>
目录下看咱们已拉取各层镜像。比方应用 overlay2
存储驱动。
这么多层,咱们能够通过 docker image inspect
来查看某个镜像蕴含哪些层
docker image inspect --format "{{json .RootFS.Layers}}" redis
docker image inspect --format "{{json .RootFS.Layers}}" mysql:5.7
通过下面查看咱们能够看到 redis 和 mysql5.7 使用了同一层,这样共享雷同层就大大节俭了存储镜像的空间,同时也晋升了拉取镜像的速度。
咱们能够通过 docker image history
命令来查看镜像分层状况,以 redis 为例
docker history redis
留神:
- 有些步骤的大小为 0,是因为他们只扭转了元数据,并不会产生新层,也不会占用额定的空间(除元数据自身)。所以上述 redis 镜像中蕴含了 5 层。
-
<missing>
步骤,这些步骤可能是以下状况中的一种- 在另一个零碎上构建的
- 从 Docker Hub 中提取的
- 应用 BuildKit 作为构建器构建的。
4.2 复制让容器更有效率
当咱们启动一个容器的时候,会增加一个可写层在镜像之上,用于存储所有的变动。当对已有文件进行批改的时候采纳 CoW 策略。首先会到各层寻找到该文件,而后复制该文件到可写层,而后进行批改并存储。
这么做可能让咱们最大限度地缩小 I / O 操作。
然而,很显著的是当一个容器中的利用须要进行频繁的写操作,那么会造成可写层越来越宏大,此时咱们能够通过 Volume 来帮忙咱们分担压力。
容器的元数据和日志是独自寄存的,个别是寄存在 /var/lib/docker/containers
中,咱们能够应用 du -sh /var/lib/docker/containers/*
来查看各个容器占用多少。(容器 ID 其实就是文件夹名称的前 12 位)。
想向技术大佬们多多取经?开发中遇到的问题何处探讨?如何获取金融科技海量资源?
恒生 LIGHT 云社区,由恒生电子搭建的金融科技业余社区平台,分享实用技术干货、资源数据、金融科技行业趋势,拥抱所有金融开发者。
扫描下方小程序二维码,退出咱们!