Dockerfile 最佳实践常说“能用 COPY 就不要用 ADD”。ADD 到底多做了什么?这篇用同一组本地压缩包和一个本地 HTTP 服务逐项验证:自动解压的范围、权限与属主、远程 URL 的行为,以及 --checksum 能不能挡住被篡改的下载。
构建退出码 0 [COPY 的结果 /copy] /copy /copy/pack.tar /copy/pack.tar.gz /copy/pack.zip [ADD 的结果 /add] /add /add/hello /add/hello/a.txt /add/hello/b.txt /add/pack.zip
本地的 pack.tar 与 pack.tar.gz 被 ADD 自动解压到目标目录(得到 /add/hello/a.txt 等),pack.zip 不会;COPY 三者都原样复制。所以“把压缩包放进镜像”用 COPY,“展开一个 tar”才用 ADD——而且最好明确写出来,避免有人把 tar 当成普通文件复制却被悄悄解压。
-rw-r----- 1 0 0 2 Oct 10 07:19 /a/dir/x.txt -rw-r----- 1 0 0 2 Oct 10 07:19 /c/dir/x.txt -rwxr-xr-x 1 0 0 18 Oct 10 07:19 /c/run.sh -rw------- 1 1000 1000 18 Oct 10 07:19 /c/run600.sh COPY dir 与 ADD dir 的内容完全相同
ADD dir 与 COPY dir 得到完全相同的内容(diff -r 验证)。权限默认保留源文件的,COPY --chmod、--chown 可以显式指定,实验里得到 -rw------- 与 1000:1000。
构建退出码 0; total 8 -rw------- 1 0 0 1200 Oct 10 07:19 data.txt -rw------- 1 0 0 132 Oct 10 07:19 remote.tar.gz --- 1f 8b 08 08 [--checksum 正确] 退出码 0 [--checksum 错误] 退出码 1;#5 [2/2] ADD --checksum=sha256:0000000000000000000000000000000000000000000000000000000000000000 http://host.docker.internal:9700/data.txt /bad.txt | #5 ERROR: digest mismatch sha256:457f243108297082e9e2d67120646e041f1b5fc7162b8210ebce759dbe47dfff: sha256:00000
URL 由守护进程(构建器)去下载,不是客户端。下载的文件权限是 0600、属主 root,压缩包不会被解压(开头是 gzip 的 1f 8b)。加 --checksum=sha256:… 可以校验内容,写错摘要构建以 digest mismatch 失败。本文的 URL 指向宿主机上的本地服务,没有测真实的外网下载。