找回密码
 立即注册

QQ登录

只需一步,快速开始

peUfSYR.png
查看: 30|回复: 0

Day 04 Docker镜像揭秘:从拉取到理解镜像分层

[复制链接]

876

主题

13

回帖

2808

积分

管理员

积分
2808
发表于 2026-3-29 16:16:38 | 显示全部楼层 |阅读模式

你是否好奇过:
  • 场景1:为什么下载一个 Ubuntu 镜像只需要几十秒,而安装一个真实的 Ubuntu 系统要几十分钟?
  • 场景2:为什么多个容器可以共享同一个镜像,却互不影响?
  • 场景3:为什么修改容器后重启,所有改动都消失了?

    如果这些问题也困扰着你,那么今天要介绍的 Docker镜像 将为你揭开容器技术的核心秘密。

    今天这篇文章,我将用最简单的语言,带你理解 Docker 镜像的本质和分层原理。读完后,你将彻底明白容器为什么如此轻量和高效。

    ━━━━━━━━━━━━━━━━━━━━

    什么是 Docker 镜像?

    一句话解释

    Docker 镜像是一个只读的文件系统模板,包含了运行应用所需的所有内容:代码、运行时、库、环境变量和配置文件。

    打个比方 📸

    让我用一个日常例子来解释:

    Docker 镜像就像手机系统的"备份文件"
  • 镜像 = 手机的完整备份(包含系统、应用、设置)
  • 容器 = 从备份恢复出来的手机实例
  • 镜像分层 = 备份时只保存变化的部分,节省空间

    你可以从同一个备份(镜像)恢复出多个手机(容器),每个手机可以独立使用,互不干扰。更重要的是,备份文件本身是只读的,不会因为手机使用而改变。

    对比理解 ⚖️

    | 传统虚拟机镜像 | Docker 镜像 |
    |--------------|------------|
    | 包含完整操作系统(几GB) | 只包含应用和依赖(几十MB) |
    | 启动需要几分钟 | 启动只需几秒 |
    | 每个镜像独立存储 | 共享公共层,节省空间 |
    | 难以版本管理 | 每层都有版本记录 |
    | 分发困难 | 可轻松分享和下载 |

    核心特点

  • 只读性:镜像一旦构建完成就不可修改,保证了一致性
  • 分层结构:像千层蛋糕一样,每层都是独立的文件系统
  • 复用性:多个镜像可以共享相同的底层,节省存储空间

    ━━━━━━━━━━━━━━━━━━━━

    Docker 镜像是如何工作的?

    简化模型

    让我们看看镜像和容器的关系:
    1. Docker 镜像(只读)
    2. ┌─────────────────────┐
    3. │  应用层 (App)       │ ← 最上层:你的应用
    4. ├─────────────────────┤
    5. │  依赖层 (Deps)      │ ← 中间层:运行时依赖
    6. ├─────────────────────┤
    7. │  基础层 (Base OS)   │ ← 底层:基础操作系统
    8. └─────────────────────┘
    9.          ↓ docker run
    10. ┌─────────────────────┐
    11. │  可写层             │ ← 容器的修改都在这里
    12. ├─────────────────────┤
    13. │  应用层 (只读)      │
    14. │  依赖层 (只读)      │
    15. │  基础层 (只读)      │
    16. └─────────────────────┘
    17.    运行中的容器
    复制代码

    工作流程

  • 拉取镜像:从 Docker Hub 或其他仓库下载镜像到本地
  • 创建容器:Docker 在镜像的只读层之上添加一个可写层
  • 运行应用:容器中的所有修改都发生在可写层,不影响原镜像
  • 停止容器:可写层保留,重启容器时恢复状态
  • 删除容器:可写层被删除,但镜像保持不变

    关键概念

  • 镜像层(Image Layer):只读的文件系统层,可以被多个容器共享
  • 容器层(Container Layer):可写的顶层,存储容器运行时的所有改变
  • 联合文件系统(Union FS):将多个层合并成一个统一的文件系统视图

    💡 小贴士:想象镜像是一本印刷好的书(只读),而容器是在书上夹的便签纸(可写)。你可以在便签上做笔记,但不会改变原书的内容。

    ━━━━━━━━━━━━━━━━━━━━

    什么时候用 Docker 镜像?

    适用场景 ✅

  • 应用分发:将应用及其依赖打包成镜像
  • 示例:开发了一个 Web 应用,打包成镜像后,团队成员可以直接运行,无需配置环境

  • 环境一致性:确保开发、测试、生产环境完全一致
  • 示例:本地测试用的 Node.js 16 镜像,部署到服务器也是同一个镜像

  • 快速部署:从镜像启动容器只需几秒
  • 示例:需要快速扩容 10 个 Nginx 实例,从同一个镜像启动即可

  • 版本管理:为应用的不同版本创建不同的镜像
  • 示例:应用 v1.0、v1.1、v2.0 各有一个镜像,可以随时回滚

    不适用场景 ❌

  • 需要持久化数据:镜像是只读的,数据应该存储在卷中
  • 频繁修改的内容:不要把经常变化的配置硬编码在镜像里
  • 敏感信息:密码、密钥不应该写入镜像(会被永久记录)

    💡 判断标准:如果某个文件或配置在应用运行过程中需要修改,就不应该写入镜像,而应该通过卷挂载或环境变量传入。

    ━━━━━━━━━━━━━━━━━━━━

    5分钟快速体验

    让我们通过实际操作,感受 Docker 镜像的拉取和分层结构。

    前置要求

  • 已安装 Docker(参考第2天文章)
  • 确保 Docker 服务正在运行

    操作步骤

    第1步:搜索镜像
    1. # 在 Docker Hub 上搜索 nginx 镜像
    2. docker search nginx
    复制代码

    预期结果
    1. NAME                              DESCRIPTION                                     STARS     OFFICIAL
    2. nginx                             Official build of Nginx.                        19000     [OK]
    3. linuxserver/nginx                 An Nginx container...                           180
    4. bitnami/nginx                     Bitnami nginx Docker Image                      150
    复制代码

    第2步:拉取镜像
    1. # 拉取官方 nginx 镜像(默认拉取 latest 标签)
    2. docker pull nginx
    复制代码

    预期结果
    1. Using default tag: latest
    2. latest: Pulling from library/nginx
    3. a2abf6c4d29d: Pull complete   ← 第1层
    4. a9edb18cadd1: Pull complete   ← 第2层
    5. 589b7251471a: Pull complete   ← 第3层
    6. 186b1aaa4aa6: Pull complete   ← 第4层
    7. b4df32aa5a72: Pull complete   ← 第5层
    8. a0bcbecc962e: Pull complete   ← 第6层
    9. Digest: sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
    10. Status: Downloaded newer image for nginx:latest
    11. docker.io/library/nginx:latest
    复制代码

    💡 注意:每个 "Pull complete" 代表下载了一层!

    第3步:查看镜像详情
    1. # 查看本地所有镜像
    2. docker images
    复制代码

    预期结果
    1. REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
    2. nginx        latest    605c77e624dd   2 weeks ago   141MB
    3. hello-world  latest    feb5d9fea6a5   2 years ago   13.3kB
    复制代码

    第4步:查看镜像的分层历史
    1. # 查看 nginx 镜像的构建历史
    2. docker history nginx
    复制代码

    预期结果
    1. IMAGE          CREATED       CREATED BY                                      SIZE      COMMENT
    2. 605c77e624dd   2 weeks ago   /bin/sh -c #(nop)  CMD ["nginx" "-g" "daemon…   0B
    3. <missing>      2 weeks ago   /bin/sh -c #(nop)  STOPSIGNAL SIGQUIT           0B
    4. <missing>      2 weeks ago   /bin/sh -c #(nop)  EXPOSE 80                    0B
    5. <missing>      2 weeks ago   /bin/sh -c #(nop)  ENTRYPOINT ["/docker-entr…   0B
    6. <missing>      2 weeks ago   /bin/sh -c set -x     && addgroup --system -…   61.1MB
    7. <missing>      2 weeks ago   /bin/sh -c #(nop)  ENV PKG_RELEASE=1~bookworm   0B
    8. <missing>      2 weeks ago   /bin/sh -c #(nop)  ENV NV_VERSION=1.24.0        0B
    9. <missing>      2 weeks ago   /bin/sh -c #(nop)  LABEL maintainer=NGINX Do…   0B
    10. <missing>      2 weeks ago   /bin/sh -c #(nop)  CMD ["bash"]                 0B
    11. <missing>      2 weeks ago   /bin/sh -c #(nop) ADD file:d261a6f6921acdd33…   74.8MB
    复制代码

    每一行代表一层,SIZE 列显示该层的大小。

    第5步:体验镜像分层的复用
    1. # 拉取另一个基于 nginx 的镜像
    2. docker pull nginx:alpine
    复制代码

    预期结果
    1. alpine: Pulling from library/nginx
    2. 4abcf2066143: Already exists   ← 这层已存在,直接复用!
    3. 8e7ac6c8107e: Pull complete    ← 只下载不同的层
    4. 96e8cbaf4e7e: Pull complete
    5. Digest: sha256:a5127daff3d6f4606be3100a252419bfa84fd6ee5cd74d0feaca1a5068f97dcf
    6. Status: Downloaded newer image for nginx:alpine
    复制代码

    💡 关键发现:"Already exists" 说明该层在之前下载 nginx:latest 时已经存在,Docker 智能复用了这一层!

    运行效果

    现在你已经:
  • ✅ 学会了搜索和拉取镜像
  • ✅ 看到了镜像的分层结构
  • ✅ 体验了层的复用机制

    🎉 恭喜!你已经掌握了 Docker 镜像的基本操作。

    ━━━━━━━━━━━━━━━━━━━━

    深入理解镜像分层

    为什么要分层?

    Docker 镜像采用分层结构有三大好处:

  • 节省存储空间 💾
  • 多个镜像可以共享相同的基础层
  • 例如:10个基于 Ubuntu 的镜像,Ubuntu 层只存储一份

  • 加快传输速度 🚀
  • 只下载改变的层,已存在的层直接复用
  • 推送镜像时,也只上传新增的层

  • 提高构建效率
  • 构建镜像时,未改变的层使用缓存
  • 只需重新构建改变的层及其之后的层

    分层的实际例子

    假设我们有这样一个 Dockerfile:
    1. FROM ubuntu:20.04                # 层1:基础系统 (80MB)
    2. RUN apt-get update               # 层2:更新包列表 (50MB)
    3. RUN apt-get install -y python3   # 层3:安装 Python (100MB)
    4. COPY app.py /app/                # 层4:复制应用代码 (1KB)
    5. CMD ["python3", "/app/app.py"]   # 层5:设置启动命令 (0B)
    复制代码

    存储结构
    1. ┌─────────────────────┐
    2. │ CMD (0B)            │ ← 层5:元数据
    3. ├─────────────────────┤
    4. │ app.py (1KB)        │ ← 层4:应用代码
    5. ├─────────────────────┤
    6. │ python3 (100MB)     │ ← 层3:Python环境
    7. ├─────────────────────┤
    8. │ apt-get update(50MB)│ ← 层2:包索引
    9. ├─────────────────────┤
    10. │ ubuntu:20.04 (80MB) │ ← 层1:基础系统
    11. └─────────────────────┘
    12. 总大小:约 230MB
    复制代码

    复用场景
  • 如果你构建另一个基于
    1. ubuntu:20.04
    复制代码
    的镜像,层1 直接复用(节省 80MB)
  • 如果只修改了
    1. app.py
    复制代码
    ,重新构建时只需重建层4和层5(节省几分钟)

    查看层的详细信息
    1. # 使用 inspect 命令查看镜像的层信息
    2. docker inspect nginx | grep -A 10 "Layers"
    复制代码

    预期输出
    1. "Layers": [
    2.     "sha256:e1caac4eb9d2ec3c6c3d0e88e8e3c5c6cf7c3a2e3d6c1e2d3c4b5a6e7d8c9d0e",
    3.     "sha256:a2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3",
    4.     "sha256:b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4"
    5. ]
    复制代码

    每个 sha256 哈希值代表一个不可变的层。

    ━━━━━━━━━━━━━━━━━━━━

    🤔 常见疑问

    Q1:镜像删除后,容器还能运行吗?
    A:可以!容器运行时已经将需要的层加载到内存,删除镜像不影响正在运行的容器。但如果容器停止后再启动,就会报错。

    Q2:为什么
    1. docker images
    复制代码
    显示的大小和实际占用空间不一样?

    A:因为多个镜像共享了某些层。使用
    1. docker system df
    复制代码
    可以查看实际占用空间。

    Q3:如何清理不用的镜像?
    A:使用
    1. docker image prune
    复制代码
    清理悬空镜像(没有标签的镜像),使用
    1. docker image prune -a
    复制代码
    清理所有未使用的镜像。

    Q4:镜像的
    1. latest
    复制代码
    标签是什么意思?

    A:
    1. latest
    复制代码
    只是一个默认标签,并不一定是最新版本。在生产环境中,应该使用具体的版本号(如
    1. nginx:1.24.0
    复制代码
    )而不是
    1. latest
    复制代码


    Q5:如何查看某个镜像占用了多少空间?
    A:使用
    1. docker images
    复制代码
    查看单个镜像大小,或使用
    1. docker system df -v
    复制代码
    查看详细的空间使用情况。

    ━━━━━━━━━━━━━━━━━━━━

    📚 本文总结

    今天我们深入学习了 Docker 镜像,让我们快速回顾一下要点:

  • 核心概念:Docker 镜像是一个只读的文件系统模板,包含运行应用所需的一切
  • 分层结构:镜像采用分层设计,每层独立且可复用,节省空间和时间
  • 工作原理:容器在镜像的只读层之上添加可写层,所有修改都发生在可写层
  • 实际应用:通过
    1. docker pull
    复制代码
    1. docker images
    复制代码
    1. docker history
    复制代码
    等命令管理镜像

    下一步学习建议

    掌握了 Docker 镜像的基础知识后,建议你:

  • 实践:亲手操作一遍文章中的所有命令,观察分层结构
  • 深入:关注下一篇文章《Day 5:容器生命周期管理》,学习如何从镜像创建和管理容器
  • 扩展:尝试拉取不同的镜像(如
    1. redis
    复制代码
    1. mysql
    复制代码
    ),观察它们的分层结构有何不同

    🔗 相关文章推荐

  • 上一篇:Day 3 - 第一个容器:Hello World 背后的秘密
  • 下一篇:Day 5 - 容器生命周期管理:创建、启动、停止、删除
  • 扩展阅读:Docker Hub 官方文档

    ━━━━━━━━━━━━━━━━━━━━

    💬 互动时间

    讨论话题:你在工作中遇到过"开发环境正常,生产环境出问题"的情况吗?现在你会如何用 Docker 镜像解决这个问题?欢迎在评论区分享你的经验!

    今日作业
  • 拉取 3 个不同的镜像(如
    1. nginx
    复制代码
    1. redis
    复制代码
    1. python
    复制代码

  • 使用
    1. docker history
    复制代码
    查看它们的分层结构
    1. docker system df
    复制代码
    查看实际占用空间,验证层复用

    如果这篇文章对你有帮助,请:
  • 👍 点个「赞」和「在看」
  • 🔄 分享给正在学习 Docker 的朋友
  • 💬 评论区告诉我你最感兴趣的镜像是哪个

    ━━━━━━━━━━━━━━━━━━━━

    📖 往期推荐

  • Day 1:Docker 是什么?5分钟看懂容器革命
  • Day 2:Docker 安装指南:Windows/Mac/Linux 全平台
  • Day 3:第一个容器:Hello World 背后的秘密

    ━━━━━━━━━━━━━━━━━━━━

    关于本系列

    这是「Docker 30天实战系列」的第 4 篇文章。本系列将用30天时间,带你从零基础到实战部署,系统掌握Docker容器技术。

    🔔 点击关注,不错过每一篇干货!



    ━━━━━━━━━━━━━━━━━━━━
  • 您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    扫码关注微信公众号

    Archiver|手机版|小黑屋|风叶林

    GMT+8, 2026-5-8 23:04 , Processed in 0.169339 second(s), 20 queries .

    Powered by 风叶林

    © 2001-2026 Discuz! Team.

    快速回复 返回顶部 返回列表