云计算百科
云计算领域专业知识百科平台

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

文章目录

  • 容器镜像与 Overlay2 存储
    • 一、容器镜像概述
      • 1. Docker 镜像
      • 2. 联合文件系统(UnionFS)
    • 二、Docker Overlay2 存储驱动
      • 1. 存储驱动说明
      • 2. 核心概念
      • 3. Overlay2 分层结构
      • 4. 元数据(Metadata)
      • 5. 为什么下载慢、删除快?
      • 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. 查看只读层短 ID
      • 5. 容器内写文件测试

容器镜像与 Overlay2 存储

一、容器镜像概述

1. Docker 镜像

  • Docker 镜像是只读的容器模板,是容器运行的基础。
  • 为容器提供静态文件系统运行环境(rootfs)。
  • 镜像 = 容器的「静止状态」;容器 = 镜像的「运行状态」。

2. 联合文件系统(UnionFS)

  • 联合文件系统是实现「联合挂载」技术的文件系统。
  • 联合挂载可以在一个挂载点同时挂载多个文件系统,将挂载点原目录与被挂载内容整合,最终呈现整合后的各层文件和目录。
  • Docker 镜像基于该技术实现分层下载与分层存储。

二、Docker Overlay2 存储驱动

1. 存储驱动说明

容器文件系统有多种存储驱动实现:aufs(联合文件系统)、devicemapper(设备映射)、overlay、overlay2 等。本文以 overlay2 为例说明。

2. 核心概念

  • registry / repository:registry 是 repository 的集合,repository 是镜像的集合。
  • image:存储镜像元数据(镜像架构、默认配置、容器配置等),属于逻辑概念,不存在对应的物理镜像文件。
  • layer(镜像层):构成镜像,单个 layer 可被多个镜像共享。
  • 3. Overlay2 分层结构

    • lowerdir:只读镜像层,存放基础镜像文件(示例 file1、file2、file3)。
    • upperdir:容器读写层,保存容器运行时的修改、新增文件(示例中覆盖 file2、新增 file4)。
    • merged:联合挂载后的统一视图,容器内可见整合后的完整文件(file1~file4)。

    原理:底层只读镜像层 + 上层可写容器层,合并对外提供完整文件系统。

    4. 元数据(Metadata)

    元数据即文件的属性信息,包括:

    • 名称(如 abc)
    • 文件大小
    • 文件权限
    • 创建时间
    • 文件类型
    • 文件所有者

    5. 为什么下载慢、删除快?

    • 下载慢:需要完整拉取镜像各层数据,数据量大。
    • 删除快:删除的只是数据的元数据(索引),只要未被覆盖写入,数据就不易真正丢失,因此删除很快。

    6. OverlayFS 与 overlay2 的区别

    root@harbor:~# docker info | grep overlay
    Storage Driver: overlayfs
    Network: bridge host ipvlan macvlan null overlay

    思考:为什么显示的不是 overlay2?overlayfs 和 overlay2 有什么区别?

    简单来说:

    • OverlayFS:Linux 内核中的一个文件系统,提供联合挂载(union mount)功能。
    • overlay2:Docker 基于 OverlayFS 实现的一个存储驱动(storage driver)。

    docker info 中 Storage Driver: overlayfs 表示 Docker 正在使用基于 OverlayFS 的存储驱动,实际上就是 overlay2。

    核心区别:overlay(旧版)vs overlay2(新版)

    对比维度overlay(旧版)overlay2(新版)
    镜像层支持 仅支持单层 lowerdir,多层时靠目录 + 硬链接模拟,效率低 原生支持多层 lowerdir,最多 128 层
    Inode 利用 效率低,容器/镜像多时易耗尽 inode 效率高,显著减少 inode 压力
    内核要求 3.18+ 4.0+(RHEL/CentOS 7 需 3.10.0-514+)
    稳定性与性能 早期实现,相对有限 更好,尤其多层镜像与频繁写操作
    官方推荐 不推荐用于生产 首选、默认

    为什么新版显示 overlayfs?

    较新版本 Docker(尤其是使用较新 containerd 的版本)术语发生了变化:官方将 Linux 内核驱动称为 OverlayFS,将 Docker 存储驱动称为 overlay2。从 Docker Engine 29.0 起,overlay2 被视为「经典(legacy)」驱动,被新的 overlayfs containerd 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:获取镜像短 ID

    docker 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/长ID

    cat /var/lib/docker/image/overlay2/imagedb/content/sha256/长ID

    步骤 4:通过分层 ID 获取分层缓存 ID

    路径:layerdb/sha256/分层ID/cache-id

    cat 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_id = chainID,可直接通过 diff_id 找到对应文件。
  • 中间层镜像层:chainID(n) = SHA256(chainID(n-1) + diffID(n)),需基于上一层 chainID 与当前层 diffID 计算。
  • 查看镜像 diff_ids 示例:

    cat /var/lib/docker/image/overlay2/imagedb/content/sha256/22bd1541745359072c06a72a23f4f6c52dbb685424e0d5b29008ae4eb2683698

    rootfs 分层 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_id:sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3
    • 第 2 个中间层 diff_id:sha256:cff9e7c67fbb49f4a3d39a66187b50cb525ac501d92b8a921b6877270b6f4ae5
  • 计算逻辑:拼接上一层 chainID(底层 diff_id)与当前层 diff_id,对拼接字符串做 sha256 哈希,得到当前层 chainID。

  • 实操命令

  • echo -n "sha256:1bb35e8b4de116e84b2ccf614cce4e309b6043bf2cd35543d8394edeaeb587e3 sha256:cff9e7c67fbb49f4a3d39a66187b50cb525ac501d92b8a921b6877270b6f4ae5" | sha256sum –

  • 输出结果(该中间层 chainID):c48247a077eb9c2db74e784dce13198fac9ea62484b6073f1a553ab43feeb39b
  • 四、容器与镜像的关系(Nginx Overlay 演示)

    1. 启动 Nginx 容器

    # 后台运行 nginx 镜像
    docker run -d nginx:latest
    # 查看运行中的 nginx 容器
    docker ps | grep nginx

    输出示例容器 ID:381b3e88e209

    2. 查看容器 overlay 挂载信息

    mount | grep overlay

    挂载字段拆解:

  • 挂载点:/var/lib/docker/overlay2/缓存ID/merged
  • lowerdir:以 : 分隔的目录列表,对应镜像所有只读分层(底层 + 各中间层)
  • upperdir:容器专属读写层目录,所有容器内修改都保存至此
  • workdir:OverlayFS 工作目录,用于执行 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 底层镜像。

    注:本次演示容器只有一层镜像,因此展示较为直观。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 【DOCKER进阶】-2 容器镜像的分层
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!