Dockerfile常用指令

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容器與容器雲》

Tags: