長話短說,今天分享三組容易混淆的Dockerfile指令, 幫助大家編寫更優雅的Dockfile檔案、構建更純淨的Docker映象。
COPY vs ADD
COPY、ADD主體功能類似:從指定位置拷貝檔案到Docker映象。
COPY <src>... <dest>
ADD <src>... <dest>
COPY 接收src、dest引數,只允許從Docker Engine主機上拷貝檔案到Docker映象;
ADD也能完成以上工作,但是ADD支援另外兩種src:
- 檔案源可以是URL
- 可以從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
- RUN 在新層中執行命令併產生新映象,主要用於安裝新軟體包。
- ENTRYPOINT 執行程式的啟動命令,當您想將容器作為可執行檔案執行時使用。
- 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