Dockerfile常用指令

尹瑞星發表於2021-06-27

1、映象構建過程

包含Dockerfile目錄的所有內容稱為上下文,上下文通過docker build命令傳入到Docker daemon後,便開始按照Dockerfile中的內容一層層構造映象。

為了提高映象構建的速度,Docker daemon會快取構建過程中的中間映象。當從一個已在快取中的基礎映象開始構建新映象時,會將Dockerfile中的下一條指令和基礎映象的所有子映象做比較,如果有一個子映象是由相同指令生成的,則命中快取,直接使用該映象(COPY/ADD指令還會比較檔案內容),一旦快取失效,則後續的指令都將生成新的映象,不在使用快取。

2、Dockerfile指令

ENV

為映象建立出來的容器宣告環境變數,還可以被dockerfile後面的指令使用。

ENV <key> <value>
ENV <key=value>

FROM

為後面的指令提供基礎映象,一個Dockerfile可以有多個FROM指令,這樣會構建多個映象。在每個映象構建完成後,Docker命令列介面會輸出該映象的ID。

FROM <image>:<tag>

COPY

複製檔案或目錄新增到新映象中。

COPY <src> <dest>

可以有多個,但必須是上下文根目錄的相對路徑,可以使用萬用字元。

可以是檔案或目錄(/結尾),但必須是目標映象中的絕對路徑或者相對於WORKDIR的相對路徑。

ADD

和COPY一樣,但可以是一個只想網路檔案的URL

還可以只想本地的壓縮歸檔檔案,該檔案複製到容器中時會被解壓提取

RUN

在前一條命令建立的映象基礎上建立一個容器,並在容器中執行命令,命令結束後commit容器為新映象,該映象被Dockerfile中的下一條指令使用。

RUN <command> (shell格式)
RUN ["executable","param1","param2"] (exec格式,推薦)

shell格式,命令通過/bin/sh -c執行。

exec格式,命令直接執行,引數會被當成JSON陣列被Docker解析,所以必須使用雙引號,因為exec不會在shell中執行,所以環境變數的引數不會被替換。例如當執行 CMD ["echo","$HOME"]時候,$HOME不會做變數的替換,可以改寫為 CMD ["sh","-c","echo","$HOME"]。

CMD

提供容器執行時的預設值,預設值可以是一條指令,可以是一些引數。

CMD <command> (shell格式)
CMD ["executable","param1","param2"] (exec格式,推薦)
CMD ["param1","param2"] (為ENTRYPOINT指令提供引數)

一個Dockerfile中可以有多條CMD指令,但只有最後一條有效。

CMD vs RUN

RUN指令在構建映象時執行命令,並生成新的映象;CMD指令在構建映象時並不執行命令,而是在容器啟動時預設將CMD指令作為第一條執行的命令。

如果使用者在命令列介面執行docker run命令時指定了命令引數,則會覆蓋CMD指令中的命令。

ENTRYPOINT

和CMD類似,讓容器在每次啟動時候執行相同的命令。

ENTRYPOINT <command> (shell格式)
ENTRYPOINT ["executable","param1","param2"] (exec格式,推薦)

一個Dockerfile中可以有多條ENTRYPOINT指令,但只有最後一條有效。

使用shell格式,ENTRYPOINT會忽略任何CMD指令和docker run命令引數,並且會執行在/bin/sh -c中,意味著該指令程式為/bin/sh -c的子程式,程式在容器中的PID不是1,且不能接受UNIX訊號。即當使用docker stop 命令時,命令程式接收不到SIGTERM訊號。

exec格式,docker run傳入的引數會覆蓋CMD指令的內容,但不會覆蓋ENTRYPOINT

ONBUILD

新增一個將來執行的觸發器指令到映象中

3、實踐心得

  • 使用標籤

    docker build -t="image:v1"
    
  • 謹慎選擇基礎映象

    儘量選擇官方映象,linux映象大小關係:busybox < debian < centos < ubuntu

    構建映象只安裝使用必須的包。

    FORM指令應該包含引數tag

  • 充分利用快取

    Docker daemon會順序執行Dockerfile中的指令,為了有效利用快取,儘量將所有Dockerfile檔案中相同的部分都放到前面,不同的部分放到後面

  • 正確使用ADD和COPY指令

    首選COPY。

    當在Dockerfile中的不同部分需要用到不同檔案時,不要一次性地將這些檔案都新增到映象中去,而是在需要時候逐個新增,這樣也有利於充分利用快取

    考慮映象大小問題,使用ADD獲取遠端URL壓縮包不是推薦做法,應該使用RUN wget或RUN curl代替。

  • RUN指令

    為了Dockerfile易讀,使用比較長的RUN指令時可以使用\分隔多行。

    不要在一行中單獨使用RUN apt-get update。當軟體源更新後,會引起快取問題,導致RUN apt-get install失敗。應該改為:RUN apt-get updata && apt-get install。

    提交映象是廉價的,不要害怕映象的層數過多,因此,不要將所有命令寫在一個RUN指令中。

  • 不要在Dockerfile中做埠對映

    使用EXPOSE指令會破壞Docker的可移植性

參考連結:

《Docker容器與容器雲》

相關文章