本文将帮助你理解两个相似的Dockerfile 指令的区别——ADD 和 COPY。它们是什么样的,以及我们更推荐你使用哪一种(提示:当然不是ADD)
当从Dockerfile 中 build Docker 镜像时候,你可以选择两种指令来添加本地的目录或者文件到你的镜像中:ADD和COPY。这两种指令格式基本相同并且基本是同样的东西
ADD <src>... <dest>
COPY <src>... <dest>
在这两种情况中,目录或者文件(<src>)被复制并添加到容器的文件系统中的指定路径(<dest
>)
所以,如果这两种指令相等的话,那为什么还要同时存在呢以及你应该选择哪一种使用呢?继续读会有答案的。
当然如果你对他们之间的微小差别不感兴趣的话,只是想知道“我应该使用哪一个”,那么你只要知道:使用COPY即可。
最初
不像COPY指令,ADD从一开始就是Docker 的一部分,并且支持一些传统的技巧,而不仅仅是从build 上下文中复制文件。
ADD指令可以让你使用URL作为<src>参数。当遇到URL时候,可以通过URL下载文件并且复制到<dest>。
ADD http://foo.com/bar.go /tmp/main.go
以上文件会通过制定的URL下载下来,并且添加到容器的文件系统中的/tmp/main.go路径中。另外一种形式是让你简单地制定目的目录为下载文件:
ADD http://foo.com/bar.go /tmp/
因为<dest>以 / 结尾。Docker 会从URL推断文件名,并且添加到指定目录。在这个案例中,一个名叫/tmp/bar.go的文件会被添加到容器的文件系统。
ADD的另外一个特性是有能力自动解压文件。如果<src>参数是一个可识别的压缩格式(tar, gzip, bzip2, etc)的本地文件(所以实现不了同时下载并解压),就会被解压到指定容器文件系统的路径<dest>。
ADD /foo.tar.gz /tmp/
上述指令会使foo.tar.gz压缩文件解压到容器的/tmp目录。
有趣的是,URL下载和解压特性不能一起使用。任何压缩文件通过URL拷贝,都不会自动解压。
很明显,在简单的ADD 指令背后,有许多功能。这里有一段引用:
Currently the ADD command is IMO far too magical. It can add local and remote files. It will sometimes untar a file and it will sometimes not untar a file. If a file is a tarball that you want to copy, you accidentally untar it. If the file is a tarball in some unrecognized compressed format that you want to untar, you accidentally copy it. - amluto
意思是:目前ADD指令有点让人迷惑,有时候解压文件,有时候不解压文件,如果你想拷贝一个压缩文件,你会以为地解压。如果文件是某种不能识别的压缩文件,如果你想解压,你又会意外地复制它。
这种解释似乎是ADD尝试做的太多了,让用户有些疑惑。很明显,没人想要打破向后兼容性。所以决定新增一个行为更加明确的指令。
和ADD相似,但是功能少一些。
在Docker 1.0发布时候,包括了新指令COPY。不像是ADD,COPY 更加直接了当,只复制文件或者目录到容器里。
COPY不支持URL,也不会特别对待压缩文件。如果build 上下文件中没有指定解压的话,那么就不会自动解压,只会复制压缩文件到容器中。
COPY是ADD的一种简化版本,目的在于满足大多数人“复制文件到容器”的需求。
使用哪个?
假如目前还不明显的话,那Docker 团队的建议是在大多数情况下使用COPY。
真的,使用ADD的唯一原因就是你有一个压缩文件,你想自动解压到镜像中。
OK,但是如果想要从远程URLS 中获取包的话,ADD还是没用么?技术上来说,是的。但是在大多数情况下,你更有可能运行curl或者wget。看看下面的例子吧:
ADD http://foo.com/package.tar.bz2 /tmp/
RUN tar -xjf /tmp/package.tar.bz2 \
&& make -C /tmp/package \
&& rm /tmp/package.tar.bz2
这里我们有一个ADD指令,用于解析URL的压缩包,紧接着是RUN指令,用于解压这个压缩包。然后编译并尝试删除下载的压缩包。
很不幸,当这个压缩包压缩后,rm命令处于独立的镜像层。。
在这个案例中,你组好这样做:
RUN curl http://foo.com/package.tar.bz2 \
| tar -xjC /tmp/package \
&& make -C /tmp/package
这里,我们curl 这个压缩包并且通过管道传给tar 命令解压。这样就在同一层镜像那么我们就可以删除压缩包了。
始终还是会有理由使用ADD 一个远程文件到你的镜像中,但是这个一个明确的决定,而不是默认的选择。
最后,只要认准一个原则:使用COPY(除非你明确你需要ADD)
所有评论(0)