Dockerfile: ADD vs COPY
本文將幫助你理解兩個相似的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)