← [ BACK_TO_NOTES ]

Docker 多阶段构建

多阶段构建让编译工具与运行镜像分离;用明确的工作目录、产物路径和依赖锁文件组织构建与缓存。

#concept #growing #ops #docker

[!info] related notes

Docker 多阶段构建

核心思想

一个 Dockerfile 多个 FROM:builder 阶段包含编译工具和依赖,runtime 阶段只复制编译产物。

# Builder: Node.js + 源码 + 依赖 → 构建产物
FROM node:24-slim AS builder
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

# Runtime: 只有 nginx + 静态文件
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html

本例假设项目提交 package-lock.json,build 产出静态站点 dist/;SSR 服务或仍需 Node 运行时的应用不能直接用 nginx 替代。这里的镜像标签用于示例,实际发布应固定并维护基础镜像版本/摘要。

镜像体积边界

运行镜像不会继承未复制的 builder 文件,但仍包含运行基础镜像和所复制产物。减小幅度取决于项目、架构、基础镜像及统计口径,不能把 1.2GB→30MB 当作保证;应比较实际镜像及其各层。

分层缓存优化

以下是 pnpm 项目的构建阶段片段:需先设置 WORKDIR,并安装/激活项目固定版本的 pnpm;不能假设 Node 基础镜像一定自带可用 pnpm。

# 1. 先复制依赖声明(变化少)
COPY package.json pnpm-lock.yaml ./

# 2. 安装依赖(这层被缓存)
RUN pnpm install --frozen-lockfile

# 3. 后复制源码(变化多)
COPY . .

# 4. 构建(源码变了才重新执行)
RUN pnpm build

只有该层指令、先前层、基础镜像以及复制的所有输入(包括锁文件)等缓存条件未变且缓存仍可用时,依赖安装层才可复用。workspace、补丁或 .npmrc 等影响安装的文件也需在这一层前复制,不能只检查 package.json。

Go 后端的多阶段构建

FROM golang:1.26-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /out/server ./cmd/server

FROM alpine:3.19
COPY --from=builder /out/server /usr/local/bin/server
ENTRYPOINT ["/usr/local/bin/server"]

本例要求存在 go.mod/go.sum 且 ./cmd/server 是 main 包。按包路径构建可包含同目录其他源文件;只指定 main.go 可能遗漏它们。CGO_ENABLED=0 适用于不依赖 cgo 的程序,但运行时仍可能需要 CA 证书、时区数据或配置文件。最终大小需实测;示例保留的 alpine:3.19 是旧版本引用,部署前应替换为受支持并经验证的基础镜像,不作为当前推荐版本。

常见错误

Windows 原生绑定

跨平台构建失败可能涉及原生依赖、可选包、包管理器版本或不完整锁文件。先在目标平台用锁定版本和冻结锁文件安装复现,再按依赖工具规则修复并提交锁文件;不要默认在 Dockerfile 中手动补包来掩盖依赖漂移。

.dockerignore 没配

确保排除 node_modules、.git、.env、已有构建产物等非构建输入;保留真正需要的源码和锁文件。只在最终阶段不复制秘密,并不意味着构建上下文和缓存里从未出现秘密。

创建于 2026/6/25 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本