【DOCKER进阶】-2 容器镜像的分层

📅 2026/8/17 20:20:59
【DOCKER进阶】-2 容器镜像的分层
文章目录容器镜像与 Overlay2 存储一、容器镜像概述1. Docker 镜像2. 联合文件系统UnionFS二、Docker Overlay2 存储驱动1. 存储驱动说明2. 核心概念3. Overlay2 分层结构4. 元数据Metadata5. 为什么下载慢、删除快6. OverlayFS 与 overlay2 的区别三、镜像层文件查找与 chainID 计算1. 查找镜像指定层文件内容思路2. 完整操作流程步骤 1获取镜像短 ID步骤 2通过短 ID 获取镜像长 ID步骤 3根据镜像长 ID 获取镜像分层 ID步骤 4通过分层 ID 获取分层缓存 ID步骤 5查看该分层实际文件存储目录3. 镜像底层与中间层查找规则4. 中间层 chainID 计算示例四、容器与镜像的关系Nginx Overlay 演示1. 启动 Nginx 容器2. 查看容器 overlay 挂载信息3. Overlay 联合文件系统四层结构4. 查看只读层短 ID5. 容器内写文件测试容器镜像与 Overlay2 存储一、容器镜像概述1. Docker 镜像Docker 镜像是只读的容器模板是容器运行的基础。为容器提供静态文件系统运行环境rootfs。镜像 容器的「静止状态」容器 镜像的「运行状态」。2. 联合文件系统UnionFS联合文件系统是实现「联合挂载」技术的文件系统。联合挂载可以在一个挂载点同时挂载多个文件系统将挂载点原目录与被挂载内容整合最终呈现整合后的各层文件和目录。Docker 镜像基于该技术实现分层下载与分层存储。二、Docker Overlay2 存储驱动1. 存储驱动说明容器文件系统有多种存储驱动实现aufs联合文件系统、devicemapper设备映射、overlay、overlay2等。本文以overlay2为例说明。2. 核心概念registry / repositoryregistry 是 repository 的集合repository 是镜像的集合。image存储镜像元数据镜像架构、默认配置、容器配置等属于逻辑概念不存在对应的物理镜像文件。layer镜像层构成镜像单个 layer 可被多个镜像共享。3. Overlay2 分层结构lowerdir只读镜像层存放基础镜像文件示例file1、file2、file3。upperdir容器读写层保存容器运行时的修改、新增文件示例中覆盖file2、新增file4。merged联合挂载后的统一视图容器内可见整合后的完整文件file1~file4。原理底层只读镜像层 上层可写容器层合并对外提供完整文件系统。4. 元数据Metadata元数据即文件的属性信息包括名称如abc文件大小文件权限创建时间文件类型文件所有者5. 为什么下载慢、删除快下载慢需要完整拉取镜像各层数据数据量大。删除快删除的只是数据的元数据索引只要未被覆盖写入数据就不易真正丢失因此删除很快。6. OverlayFS 与 overlay2 的区别rootharbor:~# docker info | grep overlay Storage Driver: overlayfs Network: bridge host ipvlan macvlan null overlay思考为什么显示的不是overlay2overlayfs和overlay2有什么区别简单来说OverlayFSLinux 内核中的一个文件系统提供联合挂载union mount功能。overlay2Docker 基于 OverlayFS 实现的一个存储驱动storage driver。docker info中Storage Driver: overlayfs表示 Docker 正在使用基于 OverlayFS 的存储驱动实际上就是overlay2。核心区别overlay旧版vsoverlay2新版对比维度overlay旧版overlay2新版镜像层支持仅支持单层 lowerdir多层时靠目录 硬链接模拟效率低原生支持多层 lowerdir最多 128 层Inode 利用效率低容器/镜像多时易耗尽 inode效率高显著减少 inode 压力内核要求3.184.0RHEL/CentOS 7 需 3.10.0-514稳定性与性能早期实现相对有限更好尤其多层镜像与频繁写操作官方推荐不推荐用于生产首选、默认为什么新版显示overlayfs较新版本 Docker尤其是使用较新 containerd 的版本术语发生了变化官方将 Linux 内核驱动称为OverlayFS将 Docker 存储驱动称为overlay2。从 Docker Engine 29.0 起overlay2被视为「经典legacy」驱动被新的overlayfscontainerd snapshotter 取代因此新系统显示Storage Driver: overlayfs是正常且符合预期的。小结概念区分OverlayFS是内核功能overlay/overlay2是 Docker 存储驱动。历史演进overlay2是为解决旧版overlay在多镜像层与 inode 使用上的缺陷而设计。当前状态显示overlayfs即使用了最新基于 OverlayFS 的存储实现是官方推荐方式无需额外操作。三、镜像层文件查找与 chainID 计算1. 查找镜像指定层文件内容思路获取镜像短 ID ——docker images通过短 ID 获取长 ID —— 在 overlay 目录下的repositories.json中查找获取镜像分层 ID ——.../sha256/获取分层缓存 ID ——cache-id根据缓存 ID 定位分层文件内容2. 完整操作流程步骤 1获取镜像短 IDdocker images步骤 2通过短 ID 获取镜像长 ID路径/var/lib/docker/image/overlay2/cat repositories.json | grep 短ID步骤 3根据镜像长 ID 获取镜像分层 ID路径/var/lib/docker/image/overlay2/imagedb/content/sha256/长IDcat /var/lib/docker/image/overlay2/imagedb/content/sha256/长ID步骤 4通过分层 ID 获取分层缓存 ID路径layerdb/sha256/分层ID/cache-idcat layerdb/sha256/分层ID/cache-id步骤 5查看该分层实际文件存储目录路径/var/lib/docker/overlay2/缓存ID/diff/ls /var/lib/docker/overlay2/缓存ID/diff/3. 镜像底层与中间层查找规则查找目标找到镜像层最底层再依次查找各中间层。Docker 内容寻址机制Docker 依据文件内容索引镜像与镜像层通过 rootfs 中的diff_id计算chainID依靠chainID查询 layer 信息最终定位镜像层文件。chainID 计算规则最底层镜像层diff_idchainID可直接通过 diff_id 找到对应文件。中间层镜像层chainID(n) SHA256(chainID(n-1) diffID(n))需基于上一层 chainID 与当前层 diffID 计算。查看镜像 diff_ids 示例cat /var/lib/docker/image/overlay2/imagedb/content/sha256/22bd1541745359072c06a72a23f4f6c52dbb685424e0d5b29008ae4eb2683698rootfs 分层 diff_ids 字段示例rootfs:{type:layers,diff_ids:[ sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3, sha256:cff9e7c67fbb49f4a3d39a66187b50cb525ac501d92b8a921b6877270b6f4ae5, sha256:c29414fee8ae39b813dd7a744a2acf3e6d755fc70b2ea2bff9b707171a9fd41b, sha256:05afaee498cfc72f71eb89da7586190efa6370883fbb51f1f8e1aab1942aa7a0, sha256:2649de4780441086779fb6d6f7645e257f90fb1729b0a36898b8b5faba0f7d86, sha256:215876b361535855516505977b46790e7f44f693f7473c1efaf8b2c7dac4f241a, sha256:f3cecf76da4f34560262476c610533206d0f8e3344f896cc2fb0e59efcc0516a ]}数组内顺序自上而下为底层 → 各中间层 → 顶层。4. 中间层 chainID 计算示例以「第 2 个中间层」为例分层数据底层 diff_idsha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3第 2 个中间层 diff_idsha256:cff9e7c67fbb49f4a3d39a66187b50cb525ac501d92b8a921b6877270b6f4ae5计算逻辑拼接上一层 chainID底层 diff_id与当前层 diff_id对拼接字符串做 sha256 哈希得到当前层 chainID。实操命令echo -n sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3 sha256:cff9e7c67fbb49f4a3d39a66187b50cb525ac501d92b8a921b6877270b6f4ae5 | sha256sum -输出结果该中间层 chainIDc48247a077eb9c2db74e784dce13198fac9ea62484b6073f1a553ab43feeb39b四、容器与镜像的关系Nginx Overlay 演示1. 启动 Nginx 容器# 后台运行 nginx 镜像 docker run -d nginx:latest # 查看运行中的 nginx 容器 docker ps | grep nginx输出示例容器 ID381b3e88e2092. 查看容器 overlay 挂载信息mount | grep overlay挂载字段拆解挂载点/var/lib/docker/overlay2/缓存ID/mergedlowerdir以:分隔的目录列表对应镜像所有只读分层底层 各中间层upperdir容器专属读写层目录所有容器内修改都保存至此workdirOverlayFS 工作目录用于执行 copy_up 复制操作3. Overlay 联合文件系统四层结构lowerdir只读层镜像的所有镜像分层仅可读、不可修改。upperdir读写层容器独立可写层容器内新增、修改、删除文件全部记录在此不改动底层镜像。workdir工作层OverlayFS 内部临时目录实现 copy_up 机制读取只读层文件并复制到 upperdir 再修改。merged联合视图挂载点对容器进程展示统一合并后的文件视图即容器内看到的完整文件系统。4. 查看只读层短 ID重点查看容器 lowerdir 镜像只读层ls /var/lib/docker/overlay2/l/输出一堆层短 ID 字符串。cd /var/lib/docker/overlay2/l/ # 第 1 个短 ID 是初始化层名称对应目录带 -init ls -l IJGJLS2P7M4G6NRVRHZHT72YZQ lrwxrwxrwx 1 root root 77 7月 19 21:44 IJGJLS2P7M4G6NRVRHZHT72YZQ - ../9f48c74e6e6b93df22db6474adc950b3bb1dd00cccf68df16f44cda1b1aa3635c-init/diff ls -l 2J0F24V5EE3R50XZNGLKVPWW3E lrwxrwxrwx 1 root root 72 7月 18 07:23 2J0F24V5EE3R50XZNGLKVPWW3E - ../a18c4a00e8aa368aaf13844e20213bb4029ef4cf8f315dc3d00fb5c9f9b6f33c/diff目录内文件均为软链接指向各层真实 diff 目录带-init的为容器初始化底层其余为普通镜像只读层。IJGJLS2P7M4G6NRVRHZHT72YZQ映射容器的初始化层init该层包含与容器配置相关的文件内容是只读的。其余 ID 分别对应镜像各层文件内容映射到镜像层的 diff 目录。5. 容器内写文件测试启动容器后Docker 将镜像内容 mount 到容器中。若在容器内修改文件是否会影响镜像结论由 overlay2 分层结构可知容器内写文件会写入upperdir读写层不会修改lowerdir底层镜像。注本次演示容器只有一层镜像因此展示较为直观。