3Docker 深度探索

Docker 镜像

容器的模板

镜像分层UnionFS

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第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-alpine

2.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:latest

2.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 工具查看镜像的层效率。

将一个单阶段构建改为多阶段构建,对比镜像大小。

3/8Dock
0%