Skip to content
DAILY QUOTE

“ ”

Docker镜像原理

1.镜像是什么

Docker镜像是一种轻量级、可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件。

镜像中包含运行某个软件所需的所有内容,例如:

  • 代码
  • 运行时库
  • 环境变量
  • 配置文件

应用可以直接打包成Docker镜像,然后通过镜像启动容器运行。

获取镜像的常见方式:

  • 从远程仓库下载。
  • 由别人拷贝提供。
  • 通过Dockerfile自己制作镜像。

2.Docker镜像加载原理

2.1UnionFS联合文件系统

UnionFS(联合文件系统)是一种分层、轻量级并且高性能的文件系统。它支持把文件系统的修改作为一次提交,一层层叠加起来,同时也可以把不同目录挂载到同一个虚拟文件系统下。

UnionFS是Docker镜像的基础。镜像可以通过分层进行继承,基于基础镜像可以制作出各种具体的应用镜像。

UnionFS的特点:

  • 一次可以同时加载多个文件系统。
  • 从外部看,只能看到一个统一的文件系统。
  • 联合加载会把各层文件系统叠加起来,最终展示出包含所有底层文件和目录的结果。

2.2bootfs和rootfs

Docker镜像实际上由一层一层的文件系统组成,这种层级文件系统就是UnionFS。

bootfs主要包含bootloaderkernel

  • bootloader主要用于引导加载kernel
  • Linux刚启动时会加载bootfs文件系统。
  • Docker镜像最底层是bootfs
  • boot加载完成后,整个内核会进入内存,此时内存使用权由bootfs转交给内核,系统会卸载bootfs

rootfs位于bootfs之上:

  • rootfs包含典型Linux系统中的/dev/proc/bin/etc等标准目录和文件。
  • rootfs对应不同操作系统发行版,例如Ubuntu、CentOS等。

平时安装到虚拟机里的Ubuntu通常有好几个G,为什么Docker镜像可以只有几十MB?

原因:对于一个精简的OS,rootfs可以很小,只需要包含最基本的命令、工具和程序库即可。因为底层直接使用宿主机的kernel,镜像自身只需要提供rootfs

所以不同Linux发行版的bootfs基本一致,rootfs会有差别。不同发行版可以共用bootfs

对比结果:虚拟机启动通常是分钟级,容器启动通常是秒级。

3.Docker镜像分层机制

3.1分层下载

下载镜像时,可以观察日志输出,镜像是一层一层下载的。

Docker镜像采用分层结构的好处:

  • 多个镜像如果都基于相同的Base镜像构建,宿主机磁盘上只需要保留一份Base镜像。
  • 内存中也只需要加载一份Base镜像,就可以为多个容器服务。
  • 镜像的每一层都可以被共享。

3.2查看镜像分层

可以通过docker image inspect命令查看镜像分层信息。

bash
docker image inspect tomcat

示例输出节选:

bash
ubuntu@Mystpet:~$ docker image inspect tomcat
[
    {
        "Id": "sha256:28cba8cc937ca4db18cd32d559f49708fb2868c79c3441d793be0611d2bd7d56",
        "RepoTags": [
            "tomcat:latest"
        ],
        "RepoDigests": [
            "tomcat@sha256:28cba8cc937ca4db18cd32d559f49708fb2868c79c3441d793be0611d2bd7d56"
        ],
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2026-03-17T02:50:37.478195863Z",
        "Config": {
            "ExposedPorts": {
                "8080/tcp": {}
            },
            "Env": [
                "PATH=/usr/local/tomcat/bin:/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
                "JAVA_HOME=/opt/java/openjdk",
                "LANG=en_US.UTF-8",
                "LANGUAGE=en_US:en",
                "LC_ALL=en_US.UTF-8",
                "JAVA_VERSION=jdk-25.0.2+10",
                "CATALINA_HOME=/usr/local/tomcat",
                "TOMCAT_NATIVE_LIBDIR=/usr/local/tomcat/native-jni-lib",
                "LD_LIBRARY_PATH=/usr/local/tomcat/native-jni-lib",
                "TOMCAT_MAJOR=11",
                "TOMCAT_VERSION=11.0.18",
                "TOMCAT_SHA512=e428203454e57962296e6e95705e46a1406d15569f67ea0cbd417f38fcad85e81de6fa1be62cfa660ec746312aefb87c39127eef7348e6f78cb57e9afb862ed4"
            ],
            "Cmd": [
                "catalina.sh",
                "run"
            ],
            "WorkingDir": "/usr/local/tomcat",
            "Labels": {
                "org.opencontainers.image.ref.name": "ubuntu",
                "org.opencontainers.image.version": "24.04"
            }
        },
        "Architecture": "amd64",
        "Os": "linux",
        "Size": 155554281,
        "RootFS": {
            "Type": "layers",
            "Layers": [
                "sha256:f2a7f072635332d307212e318e07284948b89f4167fce5c4d7c9cfb7590b74b6",
                "sha256:c19a303f70f0750fa67953740982715fa23cd40108f673526753aec8b938e8c3",
                "sha256:03687485058608317706c1b0b0f84960a876c296d12e4a0260853340ece802b9",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:b51be15d613f35209c07bb11d70fc2af5fb2b8de4269d9c9d54865f86f2d8610",
                "sha256:d726f2064a44be786bd1c51efe697f5c9d7c9dfc04f77c86f0931cd953137df8",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef",
                "sha256:48806314f082ee75f7267c110e2f9798268a3049e89ecfb59d431925dae22cf4",
                "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef"
            ]
        }
    }
]

重点看RootFS中的Layers字段,它记录了镜像的分层信息。

3.3分层构建过程

所有Docker镜像都起始于一个基础镜像层。当进行修改或者增加新内容时,就会在当前镜像层之上创建新的镜像层。

示例:

1.基于Ubuntu Linux16.04创建一个新镜像,这是第一层。
2.在镜像中添加Python包,会在基础镜像层之上创建第二层。
3.继续添加一个安全补丁,会创建第三层。

最终镜像包含这3个镜像层。

镜像始终是当前所有镜像层的组合。下面例子中,每个镜像层包含3个文件,而镜像最终包含来自两个镜像层的6个文件。

下面是一个稍微复杂的三层镜像。对外看来整个镜像只有6个文件,因为最上层中的文件7是文件5的更新版本。

这种情况下,上层镜像层中的文件会覆盖底层镜像层中的文件。文件的更新版本会作为一个新镜像层添加到镜像中。

Docker通过存储引擎实现镜像层堆栈,并保证多个镜像层对外展示为统一的文件系统。

Linux上常见的存储引擎包括:

  • AUFS
  • Overlay2
  • Device Mapper
  • Btrfs
  • ZFS

每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且各自有不同的性能特点。

Docker在Windows上仅支持windowsfilter一种存储引擎,该引擎基于NTFS文件系统实现分层和CoW。

下图展示了三层镜像合并后的统一视图。所有镜像层合并后,对外提供统一的文件系统视图。

4.镜像层和容器层

Docker镜像都是只读的。容器启动时,会在镜像顶部加载一个新的可写层。

这个新的可写层就是容器层,容器层下面的都叫镜像层。

简单理解:

  • 镜像层:只读,用来提供基础文件和运行环境。
  • 容器层:可写,用来保存容器运行时产生的修改。

5.commit镜像

docker commit可以把当前容器提交成一个新的镜像副本。

命令格式:

bash
docker commit -m="提交的描述信息" -a="作者" 容器id 目标镜像名:[版本TAG]

示例:

bash
ubuntu@Mystpet:~$ docker commit -a="mystpet" -m="test" 1b5 tomcat01:1.0

说明:如果想保存当前容器的状态,可以通过docker commit提交生成一个新镜像。它的效果类似于给虚拟机创建快照。