1. 程式人生 > >Dockerfile: ADD vs COPY

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)