第3章:Docker镜像(Docker Images)
一、导读
1.1 本章学习目标
镜像是容器的模板。本章深入讲解镜像的分层架构、UnionFS 的工作原理、镜像仓库的推拉机制、以及镜像安全。
本章的核心学习目标包括:
- 理解镜像的分层架构:每层对应 Dockerfile 的一条指令。
- 掌握 UnionFS 的工作原理:层与层之间是父子关系。
- 理解写时复制(CoW):容器修改文件时才复制。
- 掌握镜像仓库的使用:推拉镜像、标签管理。
- 了解镜像安全:漏洞扫描、基础镜像选择。
1.2 为什么本章如此重要
镜像的大小直接影响部署速度和存储成本。理解镜像分层,你才能编写高效的 Dockerfile、优化镜像大小、利用层缓存加速构建。
1.3 核心问题引导
镜像的"层"是什么?每层包含什么?
为什么多个容器可以共享同一个镜像的层?
写时复制(CoW)如何工作?有什么性能影响?
latest 标签有什么陷阱?为什么应该使用特定版本?
如何确保镜像的安全性?
二、核心概念详解
2.1 镜像分层
每条 Dockerfile 指令创建一层:
dockerfile
FROM ubuntu:22.04 # 第1层:基础镜像
RUN apt-get update # 第2层:apt 缓存
RUN apt-get install -y nodejs # 第3层:nodejs
COPY app.js /app/ # 第4层:应用代码层的特点:
- 每层是上一层的增量变更
- 层一旦创建就不可变
- 多个镜像可以共享相同的层
2.2 UnionFS
UnionFS 将多个层联合挂载为统一文件系统:
容器视图(联合挂载)
├── /app/app.js ← 第4层
├── /usr/bin/node ← 第3层
├── /var/lib/apt/ ← 第2层
└── /bin/bash ← 第1层2.3 写时复制(CoW)
容器修改文件时:
检查文件是否在可写层
如果不在,从只读层复制到可写层
在可写层修改
bash
# 查看容器的层
docker diff <container-id>
# C /app/app.js ← 修改的文件
# A /app/new.js ← 新增的文件
# D /app/old.js ← 删除的文件2.4 镜像仓库
bash
# 拉取镜像
docker pull nginx:1.25-alpine
# 标记镜像
docker tag nginx:1.25-alpine registry.example.com/nginx:1.25
# 推送镜像
docker push registry.example.com/nginx:1.25
# 查看镜像层
docker image history nginx:1.25-alpine2.5 镜像标签
bash
# 不推荐的标签方式
docker pull nginx # 默认 latest,内容不确定
# 推荐的方式
docker pull nginx:1.25.3-alpine # 特定版本2.6 多架构镜像
bash
# 查看镜像支持的架构
docker manifest inspect nginx:latest
# 可以看到 amd64、arm64 等不同架构的镜像
# 拉取指定架构
docker pull --platform linux/arm64 nginx:latest2.7 镜像安全
bash
# 使用 docker scout 扫描漏洞
docker scout cves nginx:1.25
# 使用 trivy 扫描
trivy image nginx:1.25
# 安全最佳实践
# 1. 使用官方基础镜像
# 2. 使用 alpine/distroless 减小攻击面
# 3. 定期更新基础镜像
# 4. 不以 root 用户运行
# 5. 不存储敏感信息三、实战案例
3.1 分析镜像层
bash
# 查看镜像层历史
docker image history node:18-alpine
# 使用 dive 分析
# dive node:18-alpine
# 可以看到:
# - 每层的文件变更
# - 层效率评分
# - 浪费的空间3.2 优化镜像大小
dockerfile
# 优化前:300MB
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip3 install flask
COPY . /app
# 优化后:50MB
FROM python:3.11-slim
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .四、本章小结
镜像由多层组成,每层是增量变更,层间共享。
UnionFS 将多层联合挂载为统一文件系统。
写时复制在需要时才复制文件到可写层。
使用特定版本标签,避免 latest 的不确定性。
镜像安全:使用小镜像、扫描漏洞、不存储敏感信息。
五、思考与练习
思考题
为什么删除文件不会减小镜像大小?如何真正减小镜像?
多阶段构建如何减小镜像大小?
alpine 镜像为什么比 ubuntu 小很多?有什么注意事项?
练习题
使用 docker image history 分析一个大型镜像的层结构。
使用 dive 工具查看镜像的层效率。
将一个单阶段构建改为多阶段构建,对比镜像大小。