Dockerfile ADD or COPY
今天來學習一下Dockerfile中ADD與COPY的區別,這兩個指令從字面上看意思非常相近所以很常搞混
先來看一下Docker最佳實踐
文中說明雖然兩個功能相近,但是最好優先使用COPY
COPY
只支援將本地文件複製到container內的功能ADD
同樣能做到本地複製,並且多了自動tar解包與URL遠端檔案下載功能
並且建議有需要用到自動解包tar時才使用ADD
那麼我們來做一下幾個測試
mkdir hello && cd $_
touch hello.txt
touch hello2.txt
chmod 666 hello2.txt
tar zcvf hello2.tar.gz hello2.txt
apk add curl
curl https://github.com/git/git/archive/refs/tags/v2.39.2.tar.gz -o v2.39.2.curl.tar.gz
vi Dockerfile
貼上以下內容
FROM ubuntu:latest
RUN mkdir -p /hello
COPY hello.txt /hello
ADD v2.39.2.curl.tar.gz /hello/
ADD https://github.com/git/git/archive/refs/tags/v2.39.2.tar.gz /hello/
ADD hello2.tar.gz /hello
建立Image
docker build -t imagetest .
可以看一下第五步驟:此處將去github下載一份tar.gz
這個部分也是ADD
的缺點之一,就是沒辦法使用cache
也就是說每次build時都需要重新下載,會大大影響build的速度
[node1] (local) root@192.168.0.18 ~/hello
$ docker build -t imagetest .
Sending build context to Docker daemon 4.608kB
Step 1/6 : FROM ubuntu:latest
latest: Pulling from library/ubuntu
677076032cca: Pull complete
Digest: sha256:9a0bdde4188b896a372804be2384015e90e3f84906b750c1a53539b585fbbe7f
Status: Downloaded newer image for ubuntu:latest
---> 58db3edaf2be
Step 2/6 : RUN mkdir -p /hello
---> Running in 025e153c6cbb
Removing intermediate container 025e153c6cbb
---> 054a0e9ff22d
Step 3/6 : COPY hello.txt /hello
---> 4e7f54ac7c7d
Step 4/6 : ADD v2.39.2.curl.tar.gz /hello
---> a58d4c534ac4
Step 5/6 : ADD https://github.com/git/git/archive/refs/tags/v2.39.2.tar.gz /hello/
Downloading 10.58MB
---> fe984824a91a
Step 6/6 : ADD hello2.tar.gz /hello
---> 1eacc3a644dc
Successfully built 1eacc3a644dc
Successfully tagged imagetest:latest
再重新build一次看一下第四步驟,這邊有趣的是我一開始就先把這個檔案下載下來,在使用ADD
指令將v2.39.2.curl.tar.gz
複製進container裡面
發現能夠正常的使用cache,而且功能也跟COPY
指令一樣
反而第五步驟還在重新下載
[node1] (local) root@192.168.0.18 ~/hello
$ docker build -t imagetest .
Sending build context to Docker daemon 4.608kB
Step 1/6 : FROM ubuntu:latest
---> 58db3edaf2be
Step 2/6 : RUN mkdir -p /hello
---> Using cache
---> 054a0e9ff22d
Step 3/6 : COPY hello.txt /hello
---> Using cache
---> 4e7f54ac7c7d
Step 4/6 : ADD v2.39.2.curl.tar.gz /hello
---> Using cache
---> a58d4c534ac4
Step 5/6 : ADD https://github.com/git/git/archive/refs/tags/v2.39.2.tar.gz /hello/
Downloading 10.58MB
---> Using cache
---> fe984824a91a
Step 6/6 : ADD hello2.tar.gz /hello
---> Using cache
---> 1eacc3a644dc
Successfully built 1eacc3a644dc
Successfully tagged imagetest:latest
接下來運行起一個container,並且進入到container內部環境
docker run -dit imagetest
docker attach ec79
這邊有個特別的地方就是hello2.txt
明明Dockerfile第六步驟是複製hello2.tar.gz
但是結果是出現hello2.txt
這就是之前提到的ADD
指令的自動解包功能
但是v2.39.2.curl.tar.gz
也是使用ADD
指令阿
怎麼沒有自動解壓呢,這個也是ADD
指令的內部規則
如果是網路下載的檔案並不會自動解包,還需要搭配RUN指令
並且會將權限設定成600,要更改權限也一樣要搭配RUN指令
所以這邊v2.39.2.tar.gz
權限才會是-rw-------
root@ec792359f99f:/hello# ls -l
total 10332
-rw-r--r-- 1 root root 0 Feb 19 11:35 hello.txt
-rw-rw-rw- 1 root root 0 Feb 19 11:35 hello2.txt
-rw-r--r-- 1 root root 0 Feb 19 11:35 v2.39.2.curl.tar.gz
-rw------- 1 root root 10579815 Jan 1 1970 v2.39.2.tar.gz
這邊先整一下ADD
的限制
- 網路下載的檔案並不會自動解包,下載完成要搭配RUN指令進行解包
- 解包完成的tar.gz檔案,要使用RUN指令將它移除不然會影響image的大小
- 網路下載的檔案會將權限設定成600,要更改權限也一樣要搭配RUN指令來修改
- 每次build時都需要重新下載,沒法使用cache
看到這些限制,你就會覺得乾脆就用curl
搭配COPY
就好了,反正最後還是要寫解包的指令還要調整權限
事實上Docker也知道這個問題,所以在最佳實踐裡面
這個段落的最後,官方也是推薦使用curl
搭配COPY
除非有使用到自動解包的功能在使用ADD
其他場合使用COPY
是最佳的作法
最後因為RUN
, COPY
, ADD
指令,Docker會幫我們創建一個layers
詳細可以看之前的文章Docker Certified Associate(DCA)認證考試學習-Docker Image Layer
所以可以將一些步驟寫在同一RUN底下,這樣可以大大減少layer的產生
RUN mkdir -p /usr/src/things \
&& curl -SL https://example.com/big.tar.xz \
| tar -xJC /usr/src/things \
&& make -C /usr/src/things all
但還是要注意經常修改的檔案最好還是自己獨立一個image,盡量多加利用cache的機制
Summary
今天我們學習了ADD
和 COPY
這兩個指令,以及他們的使用場合
依結論來看ADD
使用的場合真的挺少的,大部分的範例也都只有使用COPY
畢竟沒辦法使用cache還是最大的問題