在Docker中,docker add copy有什么区别?
在 Dockerfile 中,COPY
和 ADD
都是用于将宿主机文件/目录复制到镜像文件系统中的指令,但它们的功能和适用场景有明显区别。核心差异体现在对压缩文件和URL 资源的处理上,以及功能的“透明度”。
1. 基本功能对比
特性 | COPY |
ADD |
---|---|---|
核心功能 | 仅复制本地文件/目录到镜像 | 复制本地文件/目录 + 额外处理压缩包和URL |
语法 | COPY <源路径> <目标路径> |
ADD <源路径> <目标路径> |
对本地文件的支持 | 支持(必须在构建上下文内) | 支持(必须在构建上下文内) |
对压缩文件的处理 | 仅原样复制(不解压) | 自动解压本地 tar 压缩包(如 .tar、.tar.gz 等) |
对 URL 的支持 | 不支持(无法从网络下载文件) | 支持(可通过 URL 下载文件到镜像) |
2. 关键区别详解
(1)对压缩文件的处理(最核心区别)
-
COPY
:仅将压缩文件(如test.tar.gz
)原样复制到镜像的目标路径,不会解压。
示例:# 将宿主机的 test.tar.gz 原样复制到镜像的 /app 目录 COPY test.tar.gz /app/ # 镜像中 /app/test.tar.gz 仍是压缩包,未解压
-
ADD
:如果源路径是本地的 tar 格式压缩包(如.tar
、.tar.gz
、.tgz
、.tar.bz2
等),会自动解压为目录,复制到目标路径。
示例:# 将宿主机的 test.tar.gz 复制到镜像的 /app 目录,并自动解压 ADD test.tar.gz /app/ # 镜像中 /app 目录下会直接出现解压后的文件(而非压缩包)
⚠️ 注意:
ADD
仅自动解压本地压缩包,对网络下载的压缩包(通过 URL)不会解压,只会原样保存。
(2)对 URL 资源的处理
-
COPY
:完全不支持 URL,只能复制宿主机本地的文件/目录(且必须在构建上下文内,即docker build
命令执行的目录及其子目录)。
若尝试使用 URL,会报错:COPY failed: stat /var/lib/docker/tmp/docker-builderxxx/https://xxx: no such file or directory
。 -
ADD
:支持以 URL 作为源路径,会自动从网络下载文件并复制到镜像的目标路径。
示例:# 从 URL 下载文件到镜像的 /tmp 目录 ADD https://example.com/test.txt /tmp/ # 镜像中 /tmp/test.txt 是下载后的文件
⚠️ 注意:官方不推荐用
ADD
下载网络文件,原因是:- 下载的文件权限可能不符合预期(默认由 root 拥有);
- 无法灵活控制下载过程(如断点续传、超时设置);
推荐替代方案:用RUN
结合curl
或wget
(需先安装对应工具),例如:
RUN apt-get install -y curl && \ curl -o /tmp/test.txt https://example.com/test.txt && \ rm -rf /var/lib/apt/lists/*
(3)功能透明度与最佳实践
COPY
:功能单一且明确,仅负责“复制本地文件”,行为可预测,不易产生意外。ADD
:功能更复杂(包含复制、解压、下载),可能导致意外结果(例如误将普通文件当作压缩包解压)。
因此,Docker 官方推荐优先使用 COPY
,仅在需要“自动解压本地压缩包”时使用 ADD
。
3. 相同点
- 两者都只能复制构建上下文内的文件/目录(无法访问宿主机的绝对路径如
/root/test.txt
,除非该路径在构建上下文内)。 - 若源路径是目录,两者都会复制目录下的所有内容(包括子目录)到目标路径,而非目录本身(除非目标路径以
/
结尾并指定目录名)。 - 若目标路径不存在,会自动创建父目录。
总结
场景需求 | 推荐指令 | 原因分析 |
---|---|---|
复制本地文件/目录到镜像 | COPY |
功能明确,无副作用 |
解压本地 tar 压缩包到镜像 | ADD |
唯一支持自动解压的指令 |
从网络下载文件到镜像 | RUN + curl/wget |
更灵活控制下载过程,避免 ADD 的局限性 |
希望镜像构建逻辑更清晰、可维护 | COPY |
行为可预测,降低意外风险 |