Dockerfile:ADD VS COPY

zhongzhong05發表於2018-03-12

這篇博文將幫助您理解兩個類似的Dockerfile指令(ADD和COPY)之間的區別,以及它們如何成為現在的樣子,以及我們對您應該使用哪條指令的建議。 (提示:不是ADD) 從Dockerfile構建Docker映象時,您可以選擇兩個指令將目錄/檔案新增到映象:ADD和COPY。兩條指令都遵循相同的基本形式,並完成了幾乎相同的事情:

ADD <src>... <dest>
COPY <src>... <dest>
複製程式碼

在這兩種情況下,都會複製目錄或檔案()並將其新增到指定的路徑的容器的檔案系統中。

因此,如果兩條指令都是相同的,為什麼它們都存在,您應該使用哪一條?請仔細閱讀,找出答案。

如果您對ADD和COPY的細微差別不感興趣,只想回答“我應該使用哪一個?”,您只需要知道:使用COPY。

故事起源

與COPY指令不同的是,ADD從一開始就是Docker的一部分,除了從構建上下文中複製檔案之外,還支援一些其他技巧。

ADD指令允許您使用URL作為引數。提供URL時,將從URL下載檔案並將其複製到。

ADD http://foo.com/bar.go /tmp/main.go
複製程式碼

上面的檔案將從指定的URL下載並新增到容器的檔案系統/tmp/main.go中。另一種形式可以讓你簡單地為下載的檔案指定目標目錄:

ADD http://foo.com/bar.go /tmp/
複製程式碼

由於引數以尾部"/"結尾,因此Docker會從URL中推斷出檔名並將其新增到指定的目錄中。在這種情況下,一個名為/tmp/bar.go的檔案將被新增到容器的檔案系統中。

ADD的另一個功能是能夠自動解壓縮壓縮檔案。如果引數是一個識別壓縮格式(tar,gzip,bzip2等)的本地檔案,那麼它將被解壓到容器檔案系統中的指定處。

ADD /foo.tar.gz /tmp/
複製程式碼

上面的命令會導致foo.tar.gz歸檔檔案的內容被解壓到容器的/ tmp目錄中。 有趣的是,URL下載和解壓功能不能一起使用。任何通過URL複製的壓縮檔案都不會自動解壓縮。

魔法

顯然,簡單的ADD指令後面有很多功能。雖然這使得ADD非常靈活,但並沒有使它具有特別的可預測性。以下是2013年12月針對ADD命令記錄的問題的一段引文:

在我看來,當前的ADD指令非常的神奇。它可以新增本地和遠端檔案。它有時會解壓一個檔案,它有時不會解壓檔案。如果某個檔案是要複製的tar包,則意外解壓縮它。如果該檔案是一個壓縮格式的tar包,需要解壓,則意外複製它。 - amluto

這個共識似乎是ADD試圖做得太多而且讓使用者感到困惑。顯然,沒有人想要破壞與ADD現有用法的向後相容性,所以決定新增一個更具可預測性的新指令。

類ADD,當更精簡

當版本1.0的Docker釋出時,包含了新的COPY指令。與ADD不同的是,COPY直接將檔案和資料夾從構建上下文複製到容器中。

COPY不支援URL作為引數,因此它不能用於從遠端位置下載檔案。任何想要複製到容器中的東西都必須存在於本地構建上下文中。

另外,COPY對壓縮檔案沒有特別的處理。如果您複製歸檔檔案,它將完全按照出現在構建上下文中的方式落入容器中,而不會嘗試解壓縮它。

COPY實際上只是ADD的精簡版本,旨在滿足大部分“複製檔案到容器”的使用案例而沒有任何副作用。

使用哪個?

如果現在還不明顯,Docker團隊的建議是在幾乎所有情況下都使用COPY。

真的,使用ADD的唯一原因是當你有一個壓縮檔案,你一定想自動解壓到映象中。理想情況下,ADD將被重新命名為EXTRACT之類的內容,以真正將這一點引入Docker生態(同樣,出於向後相容的原因,這不太可能發生)。 好的,但是從遠端URL獲取軟體包的方法不是仍然有用嗎?技術上,是的,但在大多數情況下,您可能會更好地執行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命令在單獨的映象層中,我們實際上並沒有在最終映象中節省任何空間(有關此現象的更詳細的解釋,請參閱我的優化docker映象文章)。

在這種情況下,你最好像下面這樣做:

RUN curl http://foo.com/package.tar.bz2 \
  | tar -xjC /tmp/package \
  && make -C /tmp/package

複製程式碼

這裡我們使用curl命令下載壓縮包,然後通過管道傳遞給tar命令解壓。這樣我們就不會在我們需要清理的檔案系統上留下壓縮檔案。

將遠端檔案新增到映象中可能仍有正當理由,但這應該是明確的決定,而不是您的預設選擇。

最終,規則是這樣的:使用COPY(除非你確定你需要ADD)。

原文地址:https://www.ctl.io/developers/blog/post/dockerfile-add-vs-copy/