Docker 镜像详解 ¶
镜像是什么 ¶
- 将 Docker 镜像理解为包含应用程序以及其相关依赖的一个基础文件系统,在 Docker 容器启动的过程中,它以只读的方式被用于创建容器的运行环境。
- 从另一个角度看,Docker 镜像其实是由基于 UnionFS 文件系统的一组镜像层依次挂载而得,而每个镜像层包含的其实是对上一镜像层的修改,这些修改其实是发生在容器运行的过程中的。所以,我们也可以反过来理解,镜像是对容器运行环境进行持久化存储的结果
我们下载的时候看到的一层层就是这个!
UnionFS (联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量及并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union文件系统是Docker镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性: 一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统联合加载会把各层文件系统叠加起来,这样最终的 文件系统会包含所有底层的文件和目录
Docker 镜像的加载原理 ¶
-
docker 的镜像实际上由一层一层的文件系统组成,这种层级的的文件系统UnionFS。
-
BootFS(boot filesystem)主要包含bootloader和el,bootloader主要是引导加载kernel,Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给P内核,此时系统也会卸载bootfs。
-
RootFS(root filesystem),在bootfs之上。包含的就是典型Linux系统中的/dev,/proc,/bin,/etc等标准目录和文件。rootfs就是 各种不同的操作系统发行版,比如Ubuntu,Centos等等。
为什么 Docker 中的 Centos 才 200M左右?
对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令,工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供rootfs就可以了。由此可见对于不同的linux发行版,bootfs基本是一致的,rootfs会有差别,因此不同的发行版可以公用bootfs.
虚拟机是分钟级别,容器是秒级!
分层理解 ¶
我们可以下载一个镜像,观察下载镜像的日志输出,可以看到是一层一层的下载
为什么 Docker 镜像要采用这种分层的结构呢?
最大的好处应该是资源共享!比如有很多镜像都是从相同的 Base 镜像构建而来,那么宿主机只需在磁盘上保留一份 Base 镜像,同时内存中也只需要加载一份 Base 镜像,这样就可以为所有的容器提供服务,而且镜像的每一层都可以被共享。
我们使用如下命令查看一下镜像的分层方式
docker inspect nginx
理解:
所有的 Docker 镜像都起始于一个基础镜像层,当进行修改或增加信的内容时,就会在当前的镜像层之上,创建新的镜像层。
举一个简单的例子:
-
假如基于 Linux Ubuntu 22.04 创建一个新的镜像,这就是新镜像的第一层;
-
如果在 Ubuntu 22.04 镜像中添加 Python 包,就会在基础镜像上创建第二个镜像层;
-
如果继续添加一个 Nginx ,就会再上一层的基础上创建新的一层,这就是镜像的第三层;
该镜像当前已经包含三个镜像层,如下表所示:
层数 | 应用 |
---|---|
第三层 | Nginx |
第二层 | Python |
第一层 | Ubuntu 22.04 |
在添加额外镜像层的同时,镜像始终保持是当前所有镜像的组合,下图中举了一个简单的例子,每个镜像层包含 3 个文件。而镜像包含了来自两个镜像层的所有文件,也就是 6 个文件。
下图展示一个三层镜像,在外部看上去整个镜像只有 6 个文件,是因为最上层中的 文件7 是 文件5 的一个更新版。
这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得文件5的更新版本文件7作为一个新的镜像层添加到镜像中。
Docker 通过存储引擎 (新版本采用快照机制)的方式来实现镜像层的堆栈,并保证多镜像层对外展示为统一的文件系统。
Linux上可用的存储引擎有 AUFS、Overlay2、Device Mapper、Btrfs 以及ZFS。额名思义,每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。
Docker在Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统之上实现了分层和CoW。
下图展示了与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。
此时用 docker inspect 查看 Layers 应该为 3 层。
commit 镜像 ¶
-
Docker镜像都是只读的,当容器启动时,一个新的可写层被加载到镜像的顶部!
-
这一层就是我们通常说的容器层,容器之下的都叫镜像层!
如何提交一个自己的镜像 ¶
docker commit 提交容器成为一个新的版本
# 命令与 git 类似
docker commit -m "提交的信息备注" -a "作者" <容器id> <目标镜像名:[TAG]>
1. 拉取一个 默认的 tomcat ¶
docker pull tomcat

2. 查看 Layers 层数 ¶
docker inspect tomcat|grep -A 15 "RootFS"

3. 将拉取的 tomcat run ¶
docker run -it -d -p 8080:8080 --name=tomcat tomcat
4. 发现 tomcat 默认 不带文件,添加默认文件 ¶
docker exec -it tomcat /bin/bash
5. commit 提交为新的镜像 ¶
将修改后的 tomcat commit 为新的镜像
docker commit -m "chore: 添加默认文件" -a "cc" tomcat tomcat:v1.0
docker inspect tomcat:v1.0|grep -A 15 "RootFS"
commit 后发现多了一层 Layers ,这就是我们 第 4 步进行的操作。
6. 将新的镜像 run 起来,查看是否正常 ¶
docker run -it -d -p 8080:8080 --name=tomcat tomcat:v1.0