7.2 COPY 复制文件
何时使用 COPY
COPY 是在构建镜像时,将构建上下文(Dockerfile 所在目录及其子目录)中的文件或目录复制到容器内的指令。它是处理应用代码、配置文件最常用的方式。
典型场景:
复制应用源码:
COPY . /app复制配置文件:
COPY nginx.conf /etc/nginx/nginx.conf复制静态资源:
COPY public /app/public
为什么 COPY 比 ADD 更值得推荐? 笔者建议在 90% 的情况下使用 COPY。原因是 COPY 的语义更清晰——它就是简单地复制文件。而 ADD 有额外的功能(自动解压、支持 URL),这些功能往往会带来意外的行为。除非你明确需要 ADD 的自动解压功能,否则用 COPY。详见 7.3 ADD 指令 中的详细对比。
7.2.1 基本语法
COPY [选项] <源路径>... <目标路径>
COPY [选项] ["<源路径1>", "<源路径2>", ... "<目标路径>"]COPY 指令将构建上下文中的文件或目录复制到镜像内。
7.2.2 基本用法
复制单个文件
复制多个文件
复制目录
⚠️ 注意:复制目录时,复制的是目录的 内容,不包含目录本身。
7.2.3 通配符规则
COPY 支持 Go 的 filepath.Match 通配符规则:
*
匹配任意字符序列
*.json
?
匹配单个字符
config?.json
[abc]
匹配括号内任一字符
[abc].txt
[a-z]
匹配范围内字符
file[0-9].txt
7.2.4 目标路径
绝对路径
相对路径:基于 WORKDIR
自动创建目录
如果目标目录不存在,Docker 会自动创建:
7.2.5 修改文件所有者
使用 --chown 选项设置文件的用户和组:
💡 结合
USER指令使用,确保应用以非 root 用户运行。
7.2.6 保留文件元数据
COPY 会保留源文件的元数据:
读、写、执行权限
修改时间
这对于脚本文件特别重要:
7.2.7 COPY vs ADD
复制本地文件
✅
✅
自动解压 tar
❌
✅
支持 URL
❌
✅(不推荐)
推荐程度
✅ 推荐
⚠️ 特殊场景使用
笔者建议:除非需要自动解压 tar 文件,否则始终使用 COPY。明确的行为比隐式的魔法更好。
7.2.8 多阶段构建中的 COPY
从其他构建阶段复制
使用 --link 优化缓存
--link 的优势:
更高效利用构建缓存
并行化构建过程
加速多阶段构建
⚠️ 注意:使用
--link需要满足以下条件:
启用 BuildKit(Docker Engine 23.0+ 默认启用)
Dockerfile 语法版本 1.4 或更高(在首行声明
# syntax=docker/dockerfile:1)目标路径在前序指令中应不存在或为空目录
7.2.9 dockerignore
使用 .dockerignore 排除不需要复制的文件:
这可以:
减小构建上下文大小
加速构建
避免复制敏感文件
7.2.10 最佳实践
1. 利用缓存,先复制依赖文件
2. 使用 .dockerignore
3. 明确复制路径
🔥 踩坑实录
某公司在优化 Node.js 应用的 Docker 镜像时,发现构建出来的镜像体积超过了 2GB,远远超过生产部署的需求。排查发现,Dockerfile 中使用了
COPY . .把整个构建上下文复制进镜像,导致node_modules/、.git/目录和大量测试数据全部被打包进镜像。最初他们没有创建.dockerignore文件,默认会复制所有文件。解决方案是添加一个.dockerignore文件,排除这些不必要的目录,使镜像缩小到了 200MB。这个教训深刻地说明了:.dockerignore和.gitignore一样重要,应该在项目初始化时就创建,而不是等到出现问题时才想起来。建议的标准做法是先复制package.json和package-lock.json安装依赖,再复制应用代码,同时在.dockerignore中明确列出node_modules、.git、test 目录等。
最后更新于