构建 Docker 镜像时安装依赖包,核心是分清“谁需要、什么时候装、怎么装干净”,即明确运行时、构建时、开发时三类依赖的用途与生命周期;按分类隔离安装、控制层级顺序以利用缓存、用多阶段构建精准分离、锁定基础镜像与依赖版本确保可复现性。

构建 Docker 镜像时安装依赖包,核心是分清“谁需要、什么时候装、怎么装干净”,而不是把所有包一股脑塞进去。
按用途分类安装依赖
不同依赖在镜像生命周期中角色不同,混装会增大体积、降低安全性、破坏可复现性:
-
运行时依赖:必须保留,比如 Node.js 应用的
express、Python 的requests、系统级的ca-certificates和libc -
构建时依赖:只用于编译或打包(如
gcc、make、python-dev、node-gyp),运行时完全不需要,应严格隔离 -
开发时依赖:测试工具(
jest)、格式化工具(prettier)、.git 目录等,绝不能进入生产镜像
控制安装时机和层级顺序
Docker 构建是分层缓存机制,顺序错一步,后续所有层缓存失效:
- 把 不变或低频变更的内容放前面:例如先
COPY package.json .或COPY requirements.txt .,再RUN npm ci或pip install -r requirements.txt - 把 高频变更内容放后面:比如源码
COPY . .应该在依赖安装之后 - 同一层内合并命令,减少冗余层:
RUN apt-get update && apt-get install -y curl jq && rm -rf /var/lib/apt/lists/*
用多阶段构建精准分离依赖
这是最推荐的方式,尤其适合 Go、Java、Node.js 前端构建等场景:
-
第一阶段(builder):用完整工具链镜像(如
node:18-alpine、golang:1.21)安装构建依赖、执行编译或npm run build -
第二阶段(runtime):切换到极简镜像(如
alpine:latest、debian:slim),只COPY --from=builder复制产出物(dist/、binary、.jar),不带源码、编译器、文档 - 效果:最终镜像体积通常能缩小 60%–90%,且无构建残留风险
确保来源可控与版本锁定
避免因上游变动导致构建失败或行为异常:
- 基础镜像用具体标签,不用
:latest,例如FROM python:3.11-slim - 依赖文件需锁定版本:
requirements.txt含 pinned 版本;package-lock.json或pnpm-lock.yaml必须提交;npm ci替代npm install - 国内环境建议在构建阶段显式换源(如阿里云、清华源),但仅限于 apt/yum/pip/npm 等命令内部,不污染全局配置


















