解讀三組容易混淆的Dockerfile指令

有態度的小碼甲發表於2020-06-07

長話短說,今天分享三組容易混淆的Dockerfile指令, 幫助大家編寫更優雅的Dockfile檔案、構建更純淨的Docker映象。

COPY vs ADD

COPY、ADD主體功能類似:從指定位置拷貝檔案到Docker映象。

COPY <src>... <dest>
ADD <src>... <dest>

COPY 接收src、dest引數,只允許從Docker Engine主機上拷貝檔案到Docker映象;
ADD也能完成以上工作,但是ADD支援另外兩種src:

  1. 檔案源可以是URL
  2. 可以從src直接解壓tar檔案到目的地
ADD http://foo.com/bar.go /tmp/main.go
# 從指定地址下載檔案,新增到映象檔案系統的/tmp/main.go位置
ADD http://foo.com/bar.go /tmp/
# 因為以/結尾,將會引用url中的檔名新增到指定的目錄下


ADD /foo.tar.gz /tmp/
# 自動解壓主機檔案到指定目錄

有趣的是,URL下載和自動解壓功能不能同時生效: 任何通過URL下載的壓縮包檔案不會自動解壓。

  • 如果拷貝本地檔案到映象,通常使用COPY,因為含義更明確
  • ADD支援URL檔案、自動解壓到指定目錄,這2個特性也很棒

ARG vs ENV

ARG、ENV也讓人很疑惑的,都是Dockerfile中定義變數的指令。

ARG用於映象構建階段,ENV用於將來執行的容器

  • 生成映象後,ARG值不可用,正在執行的容器將無法訪問ARG變數值。
ARG  VAR_NAME 5
# 構建映象時,可提供--build-arg  VAR_NAME=6修改ARG值。
  • ENV主要是為容器環境變數提供預設值,正在執行的容器可訪問環境變數(這是將配置傳遞給應用的好方法):
ENV VAR_NAME_2 6
# 啟動容器時,可通過docker run -e "VAR_NAME_2=7"或docker-compose.yml提供新的環境變數值來覆蓋Dockerfile中設定的ENV值。

一個小技巧: 構建映象時不能使用命令列引數重寫ENV,但是你可以使用ARG動態為ENV設定預設值:

# You can set VAR_A while building the image or leave it at the default
ARG VAR_A 5
# VAR_B gets the (overridden) value of VAR_A
ENV VAR_B $VAR_A

RUN vs ENTRYPOINT vs CMD

  1. RUN 在新層中執行命令併產生新映象,主要用於安裝新軟體包。
  2. ENTRYPOINT 執行程式的啟動命令,當您想將容器作為可執行檔案執行時使用。
  3. CMD和ENTRYPOINT 都可以提供程式的啟動命令;CMD另外一個作用是為執行中的容器提供預設值
  • CMD ["executable","param1","param2"] (可執行形式,最常見)
  • CMD command param1 param2 (指令碼形式)
CMD echo "Hello world"
# run -it <image> 輸出 Hello world

但是當容器以命令啟動,docker run -it /bin/bash, CMD命令會被忽略,bash解析器將會執行:root@98e4bed87725:/#

  • CMD ["param1","param2"] (作為ENTRYPOINT指令預設值,此時必須提供ENTRYPOINT指令,且ENTRYPOINT也必須以Json Array形式)
ENTRYPOINT ["/bin/echo", "Hello"]  
CMD ["world"]  

# run -it <image> 將會輸出 Hello world;
# run -it <image> earth 將會輸出 Hello earth

當打算構建一個可執行的且常駐的映象,最好選用ENTRYPOINT
如果需要提供預設命令引數(可在容器執行時從命令列覆蓋),請選擇CMD

Reference

相關文章