Docker镜像概述与生命周期

咱们做容器化,第一件事就是搞明白镜像是什么。

说白了,Docker 镜像就是一个轻量的、可执行的独立软件包。它包含了运行某个应用所需的一切——代码、运行时、系统工具、系统库、设置。我个人习惯把镜像理解成“一个文件系统的快照 + 一些元数据”。

你想想看,有了镜像,你在任何地方都能拉起一个一模一样的运行环境。这就是容器一致性的基础。

镜像 vs. 虚拟机镜像

很多新手问我:“Docker 镜像和 VM 镜像有啥区别?” 嗯,差别挺大的。我整理了一个表格,方便你对比:

特性 Docker 镜像 虚拟机镜像
大小 通常 MB ~ GB 级别 通常 GB ~ TB 级别
启动速度 秒级 分钟级
内核 共享宿主机内核 包含独立内核
分层结构 是(分层构建、复用) 否(通常为单层文件)
可移植性 极高(OCI 标准) 较低(依赖 Hypervisor)
隔离级别 进程级隔离 硬件级虚拟化

你看,Docker 镜像没有自己的内核,它就是一堆文件。这带来了极快的启动和极小的体积。我在项目中遇到过好几次,用 VM 镜像部署测试环境,光下载就得等半天。换成 Docker 镜像后,几秒钟就拉下来了。

镜像的核心生命周期

一个 Docker 镜像从出生到消亡,大致经历这些阶段:

  1. 构建 (Build):通过 Dockerfile 创建镜像。
  2. 保存 (Save/Load):将镜像导出为 tar 文件,或从 tar 文件导入。
  3. 推送 (Push):上传到镜像仓库。
  4. 拉取 (Pull):从仓库下载到本地。
  5. 运行 (Run):基于镜像创建并启动容器。
  6. 删除 (Rmi):从本地移除镜像层。

别小看这个流程。我曾经在一个生产事故里,就是因为没搞清楚“镜像层”和“容器层”的差异,导致日志丢了。后面我会细讲。

镜像的构成:分层文件系统

Docker 镜像是由一层层只读文件系统叠加而成的。每一层代表一个 Dockerfile 指令。

举个例子,看这个 Dockerfile:

FROM ubuntu:22.04
RUN apt-get update && apt-get install -y python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]

构建时,Docker 会为 FROM、RUN、COPY 各生成一层。这些层是只读的,并且可以复用。比如你本地已经有了 ubuntu:22.04 的层,下次构建时它就直接复用,不用再下载。

为什么要有分层?说白了就是为了节省空间和传输时间。你想想看,如果每个镜像都打成一个巨大的单体文件,那下载一个 MySQL 镜像就得重新下载整个操作系统,多浪费。

小技巧: 使用 docker history 命令可以查看镜像的分层信息和每层的大小。

docker history nginx:latest

注意: 镜像层是只读的。容器启动时会在镜像层之上挂载一个可写层(容器层)。你在容器内做的任何修改,比如创建文件、修改配置,都写入这个可写层。一旦容器被删除,这个可写层也会消失。所以重要的数据一定要用数据卷(Volume)持久化。

镜像的元数据

镜像不光有文件系统,还有元数据。这些信息记录了镜像的“身世”。

用 docker inspect 可以看到完整的元数据,包括:

  • 镜像 ID:唯一标识。
  • 创建时间:构建时间戳。
  • 架构/操作系统:例如 linux/amd64。
  • Entrypoint / Cmd:容器启动时执行的命令。
  • 环境变量:预置的 ENV。
  • 暴露端口:如 EXPOSE 80。
  • 数据卷配置:VOLUME 指令声明的挂载点。

这些信息对“校验”至关重要。我们后面会反复用到 docker inspect 来对比镜像与容器的一致性。

镜像仓库管理与标签规范

镜像光在本地不行,得上仓库。Docker Hub、私有 Registry、Harbor、AWS ECR 等等。

我个人经验是:一定要用有意义的标签,千万别用 latest 当版本号。我在一个项目里接手了一个用 latest 打标签的 CI/CD 系统,结果每次构建完,谁也不知道线上跑的是哪天的代码。后来我们统一规范了:

# 推荐格式
[仓库地址]/[项目名]/[镜像名]:[版本号]-[构建序号]
example.com/myapp/backend:v1.2.3-b45

# 或者使用 Git Commit SHA
example.com/myapp/backend:git-a1b2c3d
标签类型 例子 适用场景 风险
语义版本 v1.2.3 正式发布 低
Git SHA git-a1b2c3d CI/CD 构建产物 极低
latest latest 开发/演示 高(不可追踪)

镜像校验与一致性的关系

好,现在我们把视角拉回这门课的主题。

Docker 镜像校验收官是为了回答一个问题:“你正在运行的容器,真的是由你预期的那个镜像构建的吗?”

你可能会想:“这不废话嘛,我 pull 了 nginx:1.25,那容器就是 nginx:1.25 啊。” 不一定。镜像标签可以被覆盖,镜像内容可以被篡改,构建过程可能被打断。这些问题我都在生产环境里见过。

所以,我们需要一套方法——从镜像的 Digest(内容哈希)、元数据、层信息等多个维度,来校验镜像与容器是否真的“一致”。这就是整个 30 章课程要解决的问题。

核心结论: 容器一致性 = 镜像完整性 + 运行时配置可信。镜像校验是容器一致性的前提。

知识图谱

下面这张图概括了本章的核心逻辑:Docker 镜像的构成与生命周期,以及它如何导向后续的校验与一致性保障。

Docker镜像生命周期与校验切入点 Docker 镜像生命周期与校验切入点 Docker 镜像 (分层 + 元数据) Dockerfile 构建 Registry 拉取 docker load 导入 Docker commit 创建容器 启动/停止 删除容器 推送/拉取 校验切入点:Digest / 层哈希 / 元数据 / 配置

图里能看到,镜像可以通过多种方式进入本地(构建、拉取、导入、commit),然后被用来创建容器。我们后续的校验工作,就是在这些“输入”和“输出”环节,验证镜像的完整性。

本章小结

到这,我们已经搭好了基础框架:

  • 镜像是什么,它和虚拟机的区别。
  • 镜像分层和元数据的概念。
  • 镜像从构建到删除的完整生命周期。
  • 镜像仓库和标签管理的重要性。