github编辑

镜像

一句话理解镜像

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

如果用一个类比:镜像就像是一张光盘或 ISO 文件。你可以用同一张光盘在不同电脑上安装系统,而光盘本身不会被修改。同样,一个镜像可以创建多个容器,而镜像本身保持不变。

镜像与操作系统的关系

我们都知道,操作系统分为内核用户空间

┌─────────────────────────────────────────────────────────────┐
│                      用户空间                                │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  应用程序、工具、库、配置文件...                       │   │
│  │  (这部分被打包成 Docker 镜像)                        │   │
│  └─────────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────────┤
│                      Linux 内核                             │
│             (容器共享宿主机的内核)                          │
└─────────────────────────────────────────────────────────────┘

对于 Linux 而言,内核启动后会挂载 root 文件系统来提供用户空间支持。Docker 镜像本质上就是一个 root 文件系统。

例如,官方镜像 ubuntu:24.04 包含了一套完整的 Ubuntu 24.04 最小系统的 root 文件系统——但不包含 Linux 内核(因为容器共享宿主机的内核)。

镜像包含什么?

Docker 镜像是一个特殊的文件系统,包含:

内容类型
示例

程序文件

应用二进制文件、Python/Node 解释器

库文件

libc、OpenSSL、各种依赖库

配置文件

nginx.conf、my.cnf 等

环境变量

PATH、LANG 等预设值

元数据

启动命令、暴露端口、数据卷定义

关键特性

  • ✅ 镜像是只读

  • ✅ 镜像不包含动态数据

  • ✅ 镜像构建后内容不会改变

分层存储:镜像的核心设计

为什么需要分层?

笔者认为,分层存储是 Docker 最巧妙的设计之一。

假设你有三个应用,都基于 Ubuntu 运行:

分层是如何工作的?

笔者用一个实际的 Dockerfile 来解释分层:

构建后的镜像结构:

每一层的特点:

  • 只读:构建完成后不可修改

  • 可共享:多个镜像可以共享相同的层

  • 有缓存:未变化的层不会重新构建

分层存储的"陷阱"

⚠️ 笔者特别提醒:理解这一点可以帮你避免构建出臃肿的镜像。

关键原理:每一层的文件变化会被记录,但删除操作只是标记,不会真正减小镜像体积

查看镜像的分层

镜像的标识

Docker 镜像有多种标识方式:

1. 镜像名称和标签

格式:[仓库地址/]仓库名[:标签]

2. 镜像 ID(Content-Addressable)

每个镜像有一个基于内容计算的唯一 ID:

3. 镜像摘要(Digest)

更精确的标识,基于镜像内容的 SHA256 哈希:

💡 笔者建议:在生产环境使用镜像摘要而非标签,因为标签可以被覆盖,但摘要是不可变的。

镜像的来源

Docker 镜像可以通过以下方式获取:

方式
说明
示例

从 Registry 拉取

最常用的方式

docker pull nginx

从 Dockerfile 构建

自定义镜像

docker build -t myapp .

从容器提交

保存容器状态(不推荐)

docker commit

从文件导入

离线传输

docker load < image.tar

本章小结

概念
要点

镜像是什么

只读的应用模板,包含运行所需的一切

分层存储

多层叠加,共享基础层,节省空间

只读特性

构建后不可修改,保证一致性

层的陷阱

删除操作只是标记,不减小体积

理解了镜像,接下来让我们学习容器——镜像的运行实例。

延伸阅读

最后更新于