COPY --link 是什么
--link 让 COPY 复制的文件单独成为一层,不再与前面的指令绑在同一层里。好处在于层失效范围变小:只复制源码的那一层会在源码变化时重建,而它下面的依赖安装层仍然命中缓存。这个能力依赖较新的前端版本,也要构建环境支持独立层的合并机制,属于优化构建速度的手段,不改变镜像内容本身。
基本信息
| 语法 | COPY --link [--chown=用户:组] 源 目标 |
|---|---|
| 依赖 | dockerfile 1.4 及以上前端(首行需写 # syntax=docker/dockerfile:1) |
| 核心收益 | 复制层与前置指令解耦,层缓存命中率更高 |
| 副作用 | 层合并方式改变,极老的运行时环境可能不兼容 |
| 常见组合 | --link 与 --chown 同时使用,复制的同时完成授权 |
| 适用环境 | BuildKit 构建(docker buildx 或 Docker 23+ 默认) |
典型使用场景
- 源码频繁变动、依赖很少变动的项目:改代码不再重装依赖
- 多阶段构建的最终阶段:把编译产物独立成一层,便于缓存复用
- CI 中配合缓存导出导入,让远端缓存命中率更高
- 需要快速回滚验证:产物层独立后重建耗时更可控
- 镜像分层审计:产物层单独可见,便于对比不同版本差异
写法与效果
写法与效果
# syntax=docker/dockerfile:1
FROM node:20-alpine AS deps
WORKDIR /app
# 依赖清单单独复制,依赖层只在清单变化时重建
COPY --link package.json package-lock.json /app/
RUN npm ci --omit=dev
FROM node:20-alpine
WORKDIR /app
# 产物用独立层复制,源码更新不会牵连上面的依赖层
COPY --link --from=deps /app/node_modules /app/node_modules
COPY --link --chown=1000:1000 ./src /app/src验证缓存行为
验证缓存行为
# 用 plain 日志观察第二次构建时哪些层命中缓存
docker buildx build --progress=plain -t app/web:1.0 . 2>&1 | grep -E 'CACHED|COPY'
# 改动源码后重建:依赖层应显示 CACHED,只有复制层重建
# touch src/index.js && docker buildx build --progress=plain -t app/web:1.0 . 2>&1 | grep -E 'CACHED|COPY'
# 对比镜像层构成
docker history app/web:1.0 | head -20收益与代价
| 维度 | 使用 --link | 不使用 |
|---|---|---|
| 层失效范围 | 仅复制层 | 可能连带前置指令 |
| 缓存命中率 | 改源码不重装依赖 | 依赖层可能被一起作废 |
| 构建耗时 | 增量场景更快 | 全量重跑更多 |
| 环境要求 | 需较新前端与 BuildKit | 老环境也能构建 |
| 镜像体积 | 不减少内容体积 | 无影响 |
| 排查难度 | 层与指令对应关系变化 | 行为与老经验一致 |
--link 优化的是层缓存,不会让镜像变小。体积优化仍要靠精简基础镜像、多阶段构建与清理缓存目录等手段。
团队协作要注意最低构建环境:本地能用不代表 CI 或他人机器能用,容易出现在本机构建成功、流水线上报未知参数的情况。