«

Docker 镜像分层原理与构建优化

时间:2026-11-15 07:18     作者:emer     分类: 无


Docker 镜像分层原理与构建优化

一、镜像为什么是分层的

Docker 镜像不是一个单一文件,而是由多层只读文件系统叠加而成。Dockerfile 里每一条指令(FROM、RUN、COPY、ADD)通常都会生成一层。下层只做增量修改,构建时相同层可被多个镜像共享,这就是镜像复用、拉取提速的基础。

二、分层与联合文件系统

底层用联合挂载(UnionFS)把多层目录合并成一个统一视图,容器启动时在最顶层加一层可写层,所有运行时改动都写在这层。镜像层只读,容器层可写,删除容器时可写层随之消失。

FROM php:8.2-cli
RUN apt-get update && apt-get install -y libzip-dev
COPY ./app /var/www/html
CMD ["php", "-S", "0.0.0.0:8000", "/var/www/html"]

每一行对应一层,基础镜像的层被复用,只新增自己的改动层。

三、构建缓存如何工作

Docker 按 Dockerfile 顺序逐层构建,某一层的指令和上游层未变化时,直接复用已有缓存层,不必重新执行。这就是改了一行代码却不必重装依赖的原因。

四、优化一:把变化少的指令放前面

依赖安装基本不变,业务代码频繁变动。顺序反过来会导致每次改代码都重装依赖:

# 推荐:先装依赖(缓存稳定),再拷代码
FROM node:20
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
CMD ["npm", "start"]

COPY . . 每次代码变更都会让它之后的层失效,必须放在 npm ci 之后。

五、优化二:合并 RUN、清理缓存

RUN apt-get update \
    && apt-get install -y --no-install-recommends curl \
    && rm -rf /var/lib/apt/lists/*

多个 RUN 会产生多层且缓存残留无法删除;合并成一层并在同层清理安装缓存,镜像更小。

六、优化三:多阶段构建

编译产物和构建工具分开,最终镜像只留运行所需:

# 构建阶段
FROM golang:1.22 AS builder
WORKDIR /src
COPY . .
RUN go build -o app
# 运行阶段,只拷贝二进制
FROM alpine:latest
COPY --from=builder /src/app /app
CMD ["/app"]

最终镜像不带 Go 工具链,体积大幅下降。

七、其他实用技巧

八、常见误区

  1. 把 COPY . . 放在 RUN 安装依赖之前,缓存全失效;
  2. 每条 RUN 单独写,镜像层层叠加又删不掉缓存;
  3. 直接用超大基础镜像塞进编译工具;
  4. 忽略 .dockerignore,把源码和依赖目录一起打进镜像;
  5. 以为分层越多越好,其实多余层只增体积不增价值。

九、总结

镜像分层让相同层共享、构建可缓存;优化关键是稳定指令前置、合并 RUN 并清理、用多阶段构建只留运行产物、配合 .dockerignore 和小基础镜像。理解层与缓存机制,才能把镜像做小、构建做快。

标签: Docker 多阶段构建 镜像分层 容器优化