Docker 内容寻址存储(Content-Addressable Storage)

Docker 内容寻址存储(Content-Addressable Storage)

核心概念

Docker 使用内容寻址存储来管理镜像层。简单说:每一层的标识符(digest/hash)是该层内容的哈希值,而不是根据文件名、时间戳或序列号来标识。

# 内容寻址的本质:内容是身份的来源
sha256:abc123def456... = 这串特定的二进制内容
# 内容变了 → 哈希变了 → 身份变了 → 新的层
# 内容不变 → 哈希不变 → 身份不变 → 复用已有层

对比:位置寻址 vs 内容寻址

graph TB
    subgraph 位置寻址(传统方式)
        P1[/var/data/layer5.tgz] --> P2[文件名: layer5]
        P3[改名  找到不同的文件]
        P4[同文件复制到不同目录  重复存储]
    end

    subgraph 内容寻址(Docker 方式)
        C1[sha256:abc...] --> C2[通过哈希定位内容]
        C3[哈希不变  内容不变  定位不变]
        C4[相同哈希  只存一份]
    end

Docker 中内容寻址的具体实现

1. 层(Layer)的寻址

# 查看镜像层的 digest
docker inspect nginx:latest --format '{{.RootFS.Layers}}'
# [sha256:7e718b9f9f6f8b1f924898f2e6470e7a4bf8a9c42f0f3650a8a0b7e1c3a5d1e0
#  sha256:9f3b8c1d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9]

# 查看这个 layer 在磁盘上的位置
# 不是通过文件名,而是通过哈希目录定位
ls /var/lib/docker/overlay2/
# 7e718b9f9f6f8b1f924898f2e6470e7a4bf8a9c42f0f3650a8a0b7e1c3a5d1e0
# 9f3b8c1d2e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9
# (注意:实际目录名是截断后的哈希值)

2. Registry 中的寻址

# 在 Registry 中,层通过 digest 标识
# Push 层时
PUT /v2//blobs/uploads/
Content: 层的 tar.gz 数据

# Registry 计算 digest,如果已存在则直接引用
# 这就是为什么相同基础镜像不需要重复 Push

内容寻址的三大好处

好处一:天然去重

graph LR
    subgraph 10Python应用
        A[应用1: FROM python:3.11]
        B[应用2: FROM python:3.11]
        C[应用3: FROM python:3.11]
    end

    subgraph 物理存储
        D[python:3.11 基础层<br/>sha256: xxx<br/>只存1]
        E[应用层各存各的]
    end

    A & B & C --> D
    A --> A1[应用1]
    B --> B1[应用2]
    C --> C1[应用3]

如果不使用内容寻址:

# 每个镜像单独存一个完整副本
10  Python 应用 × 120MB = 1.2GB

使用内容寻址:

# 基础层去重
120MB(共享基础层)+ 1KB × 10(应用层)≈ 120MB
# 节省 90% 以上空间!

好处二:完整性校验

每个层的 digest 是内容的安全哈希(SHA256),天然具备完整性验证能力:

# Pull 镜像时,Docker 会自动校验
docker pull nginx:latest

# 底层发生了什么:
# 1. 下载 Manifest → 得到各层 digest
# 2. 下载层数据
# 3. 计算下载内容的 SHA256
# 4. 对比 Manifest 中的 digest
# 5. 不一致则报错

# 手动校验
docker image inspect nginx:latest --format '{{.Id}}'
# sha256:xxxx...

好处三:不可变性

一旦层的内容被创建,它的 digest 就永远固定了。这带来了可重现构建(reproducible builds)的基础:

# 基于确切 digest 构建,保证可重现
FROM ubuntu@sha256:abc123def456...
# 而不是 FROM ubuntu:latest (latest 会变)

Docker 中内容寻址的完整链路

graph TB
    subgraph 构建阶段
        DF[Dockerfile 指令] --> EXEC[执行指令]
        EXEC --> CONTENT[产生文件变更]
        CONTENT --> HASH[计算 SHA256]
        HASH --> LAYER[存储新层<br/>目录名 = 哈希]
    end

    subgraph 推拉阶段
        PUSH[Push 镜像] --> MANIFEST[生成 Manifest<br/>包含层 digest]
        PUSH --> UPLOAD[上传层数据<br/>通过 digest 标识]

        PULL[Pull 镜像] --> GET_MANIFEST[获取 Manifest]
        GET_MANIFEST --> GET_LAYERS[ digest 下载层]
        GET_LAYERS --> VERIFY[校验 digest]
    end

    subgraph 运行阶段
        START[启动容器] --> LOCATE[ digest 找到层]
        LOCATE --> MOUNT[OverlayFS 挂载]
        MOUNT --> RUN[容器运行]
    end

内容寻址在 Docker 生态中的具体应用

镜像层存储

# 本地存储层的目录结构
/var/lib/docker/overlay2/
├── l/                              # 符号链接层   ├── ABCXYZ -> ../7e718b9f.../diff
│   └── DEFUVW -> ../9f3b8c1d.../diff
├── 7e718b9f9f6f8b1f9248.../       # 以哈希截断命名的目录   ├── diff/                       # 层的实际内容   ├── link                        # 链接到 l/ 中的短名   ├── lower                      # 下层信息   └── merged                     # 合并视图
└── 9f3b8c1d2e4f5a6b7c8d.../

Registry 存储

# Registry 中的 blob 存储也是内容寻址
/var/lib/registry/docker/registry/v2/
└── blobs/
    └── sha256/
        ├── ab/
           └── abc123...          # 以 digest 为路径
        └── 7e/
            └── 7e718b9f...        # 另一层的 digest

镜像引用

# 通过 digest 精确引用镜像
docker pull myapp@sha256:abc123def456...

# digest 可以像 tag 一样使用
docker run myapp@sha256:abc123def456...

# 构建时引用基础镜像
FROM node:18@sha256:xyz789...

面试追问

问:内容寻址会不会有哈希碰撞?

答:理论上 SHA256 有碰撞可能,但概率极低(约 1/2^256)。在实际工程中可认为不会发生。Docker 和整个容器生态都依赖这个假设。

问:内容寻址与 Git 的寻址方式类似吗?

答:非常类似。Git 也是内容寻址——每次提交的 SHA1 哈希就是内容的标识。Docker 层的 digest 就像是 Git 的 commit hash。

总结

特性 位置寻址 内容寻址(Docker)
标识方式 文件名 + 路径 内容哈希
去重能力 需要手动管理 天然去重
完整性 无自动校验 SHA256 自动校验
不可变性 可随意修改 内容不可变(Digest 永久不变)
分布式友好 需额外同步机制 哈希天然可分布式

一句话总结:内容寻址让 Docker 做到了「同名文件可能不同、同内容注定相同」——用内容的哈希值作为唯一标识,实现了自动去重、完整性校验和不可变性三大特性。

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容