您好,欢迎来到纷纭教育。
搜索
您的当前位置:首页彻底搞懂Docker镜像分层的实现

彻底搞懂Docker镜像分层的实现

来源:纷纭教育
彻底搞懂Docker镜像分层的实现

⽬录

创建测试镜像查看镜像

使⽤dockerinspect使⽤dockerhistory镜像分层图

镜像分层的好处镜像分层的实现Copy-on-write策略创建测试镜像

我们创建⼀个最简单的镜像:

1.构建测试镜像v1.0:docker build -t image_test:1.0 .

FROM alpine:3.15.0 #除了继承基础镜像,啥也不做

2.构建测试镜像v2.0:docker build -t image_test:2.0 .

FROM alpine:3.15.0

RUN dd if=/dev/zero of=file1 bs=10M count=1 #添加⼀个10M的⽂件file1

3.构建测试镜像v3.0:docker build -t image_test:3.0 .

FROM alpine:3.15.0

RUN dd if=/dev/zero of=file1 bs=10M count=1 #添加⼀个10M的⽂件file1RUN dd if=/dev/zero of=file2 bs=10M count=1 #添加⼀个10M的⽂件file2

这样本地就构建了3个测试镜像:

查看镜像

我们有2种⽅法查看镜像:

1. 使⽤docker inspect:获取镜像的元数据

2. 使⽤docker history:查看镜像的构建历史 使⽤docker inspect

使⽤docker inspect

查看镜像的元数据。

其中Parent可以看到⽗镜像, Layers这⼀项下⾯可以看到镜像的所有层。

使⽤docker history

使⽤docker history可以看到镜像的构建历史。我们每⼀⾏列出了镜像包含的层。

使⽤docker history我们看到有⼀⾏很特别,就是镜像ID为的⾏,这⼀⾏是什么呢?

看了 的描述,我们知道这些构建步骤要么是构建在另⼀个系统,要么是镜像的部分是从DockerHub上拉取下来的,要么是使⽤的是另⼀种构建⼯具BuildKit构建的。很显然,我们这⾥就是第⼆种情况,因为我们的Dockerfile中第⼀句指令就是FROM alpine:3.15.0.

镜像分层图

根据上⾯的docker history命令,我们可以轻松的画出三个镜像的分层图:

从上⾯的图可以看到,我们的镜像是分层的,我们的Dockerfile中新增⼀条指令,就会新增⼀层!

如果我们将多个命令合成⼀个,那么也只会⽣成⼀层。修改⼀下上⾯的image_test:3.0,把两条RUN合并成⼀条:

FROM alpine:3.15.0

RUN dd if=/dev/zero of=file1 bs=10M count=1 && \\ dd if=/dev/zero of=file2 bs=10M count=1

使⽤docker history 查看image_test:4.0,可以看到,只有2层了!

镜像分层的好处

知道了镜像是分层的,那么我们是不是好奇为啥要这么设计呢?试想⼀下我们如果不分层会有什么问题?

以拉取镜像为例!

拉取镜像的镜像很⼤,⽐如Redis的镜像有100多M

第⼀次我们拉取6.2版本的Redis,下载了完成的100M到本地,下次我要下载6.2.6版本的,是不是⼜得下载100M。尽管可能两个版本之间就改了⼏⾏配置⽂件。

这样是⾮常低效的。如果能只下载有差异的部分就好了!

这个痛点,也就是镜像分层要解决的问题。实际上,Docker也是这么实现的。

第⼀次下载redis:6.2时,因为之前没有下载过,所以下载了所有的层,总共113M。⽹络慢点的话还是需要花⼀些时间的!

第⼆次下载redis:7.0-rc,就变得快了很多!因为前⾯3层是redis:6.2是⼀样的,这些层已经下载过了!

这种思想和我们常⽤的版本管理⼯具git也是⼀样的!

如果版本2是基于版本1的基础上,那么版本2不需要copy⼀份全量的数据,只需⼀份和版本1差异化的增量数据即可!这样的最终好处是,可以体现在以下⽅⾯:

拉取更快:因为分层了,只需拉取本地不存在的层即可!存储更少:因为共同的层只需存储⼀份即可!运⾏时存储更少:容器运⾏时可以共享相同的层!

对于第3点,多个基于相同镜像运⾏的容器,都可以直接使⽤相同的镜像层,每个容器只需⼀个⾃⼰的可写层即可:

镜像分层的实现

前⾯说过,Docker镜像分层和Git的版本很像!我们不妨以此类⽐!只是为了⽅便我们理解:

Git

版本

在前⼀个版本的基础上修改了代码新版本只包含差异

已提交的commit是不能修改的

分层

在前⼀层的基础上

Dockerfile中加了RUN等指令新镜像只包含了差异修改旧的镜像层是不能修改的

Docker

commit了修改,新增了⼀个版本新建⼀个镜像层

总⽽⾔之,镜像层是只读的,新的镜像层是基于前⼀个镜像层的修改,只保留了增量修改的部分!使⽤了联合⽂件系统,对⽂件系统的修改作为⼀次提交来⼀层层的叠加!容器本质上也是在镜像的基础上加了⼀层可写层!这个在另外的章节再详细讨论!

Copy-on-write策略

Copy-on-write是⼀种提⾼⽂件共享和复制效率的策略。

如果⼀个⽂件和⽬录在低⼀层的镜像层中存在,并且其它层想要读取这个⽂件,就直接使⽤这个⽂件。

如果其它层想要修改这个⽂件(不管是构建镜像时,还是在容器运⾏的过程中),这个⽂件都会被先拷贝到新的⼀层中,然后再修改它。

这样做的好处是可以⼤⼤减少每⼀层的⼤⼩!

更具体的实现请参考官⽅⽂档中:

到此这篇关于彻底搞懂Docker镜像分层的⽂章就介绍到这了,更多相关Docker镜像分层内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- fenyunshixun.cn 版权所有 湘ICP备2023022495号-9

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务