Dockerfile指令詳解

什麼是Dockerfile

dockerfile其實就是記錄'火箭發射'步驟的文件,它記載了從一個鏡像建立另外一個新鏡像的步驟。撰寫好Dockerfile文件以後,咱們就能夠垂手可得的使用docker build命令來建立鏡像了。java

Dockerfile 是一個文本文件,其內包含了一條條的指令(Instruction),每一條指令構建一層,所以每一條指令的內容,就是描述該層應當如何構建。有了 Dockerfile,當咱們須要定製本身額外的需求時,只需在 Dockerfile 上添加或者修改指令,從新生成 image 便可,省去了敲命令的麻煩。python

下面是一個dockerfile文件的例子:linux

FROM openjdk:8-jdk-alpine
MAINTAINER Kurisu "makise_kurisuu@outlook.jp"
LABEL maintainer="makise_kurisuu@outlook.jp" VOLUME /tmp ARG JAR_FILE=target/alice-server.jar
COPY ${JAR_FILE} app.jar ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] 複製代碼

Dockerfile 的組成部分

部分 命令
基礎鏡像信息 FROM
維護者信息 MAINTAINER
鏡像操做指令 RUN、COPY、ADD、EXPOSE、WORKDIR、ONBUILD、USER、VOLUME等
容器啓動時執行指令 CMD、ENTRYPOINT

DockerFile命令詳解

  • FROM
    構建的鏡像設置基礎鏡像golang

    FROM <image> [AS <name>]
    FROM <image>[:<tag>] [AS <name>]
    FROM <image>[@<digest>] [AS <name>]
    複製代碼

    FROM指令初始化新的構建階段,併爲後續指令設置基礎鏡像,e.g: FROM openjdk:8-jdk-alpine。所以,Dockerfile文件必須以FROM指令開頭。 而指定的鏡像可使任何有效的鏡像(推薦使用公共倉庫的鏡像,由於拉取更爲容易)。docker

    • 在Dockerfile文件中ARG是惟一一個能夠用於FROM以前的指令。
    ARG  CODE_VERSION=latest
    FROM base:${CODE_VERSION}
    CMD /code/run-app    
    FROM extras:${CODE_VERSION}
    CMD /code/run-extras 複製代碼
    • 一個Dockerfile文件能夠有多個FROM指令,來建立多個鏡像或者使用其中一個階段做爲另外一個階段的依賴項。以最後一個鏡像的ID爲輸出值。e.g:
    FROM golang:1.10.3 
    COPY server.go /build/ WORKDIR /build RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOARM=6 go build -ldflags '-w -s' -o server ENTRYPOINT ["/build/server"] 複製代碼
    • 咱們能夠經過在FROM指令中添加AS 名稱 來指定一個名稱給後續階段的FROMCOPY --from=<name|index>使用。
    • tag和digest是可選的,若是不提供則使用latest。
  • RUN
    在鏡像的構建過程當中執行特定的命令,並生成一箇中間鏡像。好比安裝一些軟件、配置一些基礎環境,可以使用\來換行。shell

    RUN <command> (shell格式)
    RUN ["executable", "param1", "param2"] (exec格式)
    複製代碼

    要注意的是,executable是命令,後面的param是參數
    採用exec格式指令將會被解析成json格式因此不能使用單引號,而且使用反斜槓也是必需要轉移的,這在windows上尤其重要。json

  • CMD
    指定容器運行時的默認參數。ubuntu

    CMD ["executable","param1","param2"](exec格式,首選)
    CMD ["param1","param2"](給ENTRYPOINT提供默認參數)
    CMD command param1 param2(shell格式)
    複製代碼

    注意:RUN是在構建的時候執行,並生成一個新的鏡像,CMD在構建時不進行任何操做,在容器運行的時候執行。
    若是CMD用於爲ENTRYPOINT指令提供缺省參數,那麼CMDENTRYPOINT指令都應該使用JSON數組格式。windows

  • LABEL
    給構建的鏡像打標籤。數組

    LABEL <key>=<value> <key>=<value> <key>=<value> ...
    複製代碼

    標籤是鍵值對格式,要在標籤中包含空格則需轉義或用引號"括起來。e.g:

    LABEL "com.example.vendor"="ACME Incorporated" LABEL com.example.label-with-value="foo" LABEL version="1.0" LABEL description="This text illustrates \ that label-values can span multiple lines." 複製代碼

    一個鏡像能夠有多個標籤,若是基礎鏡像也有標籤則繼承,名字相同的話則會覆蓋。若是使用多個標籤,建議合併成一個標籤指令,若是使用多個標籤指令, 則每一個標籤指令都會生成一個圖層,這會致使鏡像生成效率低下。舉個栗子:

    LABEL multi.label1="value1" multi.label2="value2" other="value3" 複製代碼

    也能夠寫成:

    LABEL multi.label1="value1" \ multi.label2="value2" \ other="value3" 複製代碼
  • MAINTAINER(已棄用)
    設置做者信息。

    MAINTAINER <name>
    複製代碼

    LABELMAINTAINER更靈活,推薦使用LABEL,棄用MAINTAINER

    LABEL maintainer="makise_kurisuu@outlook.jp"
    複製代碼
  • EXPOSE
    爲構建的鏡像設置監聽端口。

    EXPOSE <port> [<port>/<protocol>...]
    複製代碼

    EXPOSE指令讓docker容器在運行的時候監聽指定的端口,能夠指定端口是upd仍是tcp協議,若是沒有指定則默認tcp協議。
    EXPOSE指令並不會發佈端口,若是發佈端口,則須要在docker run時使用-p來發布和映射一個或多個容器端口、或者使用-P來發布全部公開的端口 並將它們映射到高階端口。

  • ENV
    在構建的鏡像中設置環境變量,在後續的Dockerfile指令中能夠直接使用,也能夠固化在鏡像裏,在容器運行時仍然有效。 ENV指令有兩種格式:

    1. ENV :把第一個空格以後的全部值都當作的值,沒法在一行內設定多個環境變量。
    2. ENV = ...:能夠設置多個環境變量,若是中存在空格,須要轉義或用引號"括起來。
    ENV myName John Doe
    ENV myDog Rex The Dog
    ENV myCat fluffy
    複製代碼

    或者

    ENV myName="John Doe" myDog=Rex\ The\ Dog \
        myCat=fluffy
    複製代碼

    推薦使用第二種,一樣的這樣能減小圖層提升效率。

    注意:能夠在容器運行時指定環境變量,替換鏡像中的已有變量,docker run --env <key>=<value>
    使用ENV可能會對後續的Dockerfile指令形成影響,若是隻須要對一條指令設置環境變量,可使用這種方式:RUN <key>=<value> <command>

  • ADD
    構建鏡像時,複製上下文中的文件到鏡像內。

    ADD <src>... <dest>
    ADD ["<src>",... "<dest>"](路徑包含空格的必須使用這種格式)
    複製代碼

    <src>能夠是文件、目錄,也能夠是文件URL。可使用模糊匹配(wildcards,相似shell的匹配),能夠指定多個<src>,必須是在上下文目錄和子目錄中, 沒法添加../a.txt這樣的文件。若是<src>是個目錄,則複製的是目錄下的全部內容,但不包括該目錄。若是<src>是個可被docker識別的壓縮包, docker會以tar -x的方式解壓後將內容複製到<desct><dest>能夠是絕對路徑,也能夠是相對WORKDIR目錄的相對路徑。 全部文件的UID和GID都是0。

    若是docker發現文件內容被改變,則接下來的指令都不會再使用緩存。
    關於複製文件時須要處理的/,基本跟正常的copy一致。

  • COPY
    將主機的文件複製到鏡像內,若是目的位置不存在,Docker會自動建立全部須要的目錄結構,可是它只是單純的複製,並不會去作文件提取和解壓工做。

    COPY <src>... <dest>
    COPY ["<src>",... "<dest>"](路徑包含空格的必須使用這種格式)
    複製代碼

    注意:須要複製的目錄必定要放在Dockerfile文件的同級目錄下。
    由於構建環境將會上傳到Docker守護進程,而複製是在Docker守護進程中進行的。任何位於構建環境以外的東西都是不可用的。 COPY指令的目的的位置則必須是容器內部的一個絕對路徑。
    COPY指令

  • ENTRYPOINT
    指定鏡像的執行程序。ENTRYPOINT指令有兩種格式:

    ENTRYPOINT ["executable", "param1", "param2"] (執行格式,首選)
    ENTRYPOINT command param1 param2 (shell格式)
    複製代碼

    詳細參考:ENTRYPOINT指令

    CMDENTRYPOINT至少得使用一個。ENTRYPOINT應該被當作docker的可執行程序,CMD應該被當作ENTRYPOINT的默認參數。 docker run <image> <arg1> <arg2> ...會把以後的參數傳遞給ENTRYPOINT,覆蓋CMD指定的參數。能夠用docker run --entrypoint 來重置默認的ENTRYPOINT

    No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT ["exec_entry", "p1_entry"]
    No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
    CMD ["exec_cmd", "p1_cmd"] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
    CMD ["p1_cmd", "p2_cmd"] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
    CMD exec_cmd p1_cmd CMD exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd
  • VOLUME
    指定鏡像內的目錄爲數據卷。

    VOLUME ["/data"]
    複製代碼

    在容器運行的時候,docker會把鏡像中的數據卷的內容複製到容器的數據卷中去。 若是在接下來的Dockerfile指令中,修改了數據卷中的內容,則修改無效。

  • USER
    爲接下來的Dockerfile指令指定用戶。受影響的指令有:RUNCMDENTRYPOINT

    USER <user>[:<group>] or
    USER <UID>[:<GID>]
    複製代碼

    注意:當用戶沒有主要組時,鏡像(或下一條指令)將與該root組一塊兒運行。

  • WORKDIR
    爲接下來的Dockerfile指令指定當前工做目錄,可屢次使用,若是使用的是相對路徑,則相對的是上一個工做目錄,相似shell中的cd命令。

    WORKDIR /path/to/workdir
    複製代碼

    受影響的指令有:RUNCMDENTRYPOINTCOPYADD。 能夠在Dockerfile中屢次使用WORKDIR指令。若是提供了相對路徑,則它將相對於上一個WORKDIR指令的路徑。例如:

    WORKDIR /a WORKDIR b WORKDIR c RUN pwd 複製代碼

    此Dockerfile中pwd指令將輸出 /a/b/c.
    WORKDIR指令能夠解析以前使用ENV設置的環境變量,只能使用Dockerfile中顯式設置的環境變量。例如:

    ENV DIRPATH /path
    WORKDIR $DIRPATH/$DIRNAME RUN pwd 複製代碼

    此Dockerfile中pwd指令將輸出 /path/$DIRNAME

  • ARG
    指定用戶在docker build --build-arg <varname>=<value>時可使用的參數。

    ARG <name>[=<default value>]
    複製代碼

    若是用戶指定了未在Dockerfile中定義的構建參數,則構建會輸出警告。

    [Warning] One or more build-args [foo] were not consumed.
    複製代碼

    構建參數在定義的時候生效而不是在使用的時候。以下面第三行開始的user纔是用戶構建參數傳遞過來的user:

    FROM busybox
    # 此處獲取不到用戶傳來的user
    USER ${user:-some_user}
    ARG user
    USER $user
    複製代碼

    您可使用ARGENV指令指定RUN指令可用的變量。使用ENV指令定義的環境變量始終覆蓋同名的ARG指令。

    FROM ubuntu
    ARG CONT_IMG_VER
    ENV CONT_IMG_VER v1.0.0
    # 始終是v1.0.0
    RUN echo $CONT_IMG_VER 複製代碼

    正確的用法:

    FROM ubuntu
    ARG CONT_IMG_VER
    ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
    RUN echo $CONT_IMG_VER 複製代碼

    要在多個階段中使用arg,每一個階段都必須包含該ARG指令。

    FROM busybox
    ARG SETTINGS
    RUN ./run/setup $SETTINGS 
    FROM busybox
    ARG SETTINGS
    RUN ./run/other $SETTINGS 複製代碼

    此外docker還內置了一批構建參數,能夠不用在Dockerfile中聲明:HTTP_PROXYhttp_proxyHTTPS_PROXYhttps_proxyFTP_PROXYftp_proxyNO_PROXYno_proxy

    注意:在使用構建參數(而不是在構建參數定義的時候)的指令中,若是構建參數的值發生了變化,會致使該指令發生變化,會從新尋找緩存。

  • ONBUILD
    向鏡像中添加一個觸發器,當以該鏡像爲基礎鏡像再次構建新的鏡像時,會觸發執行其中的指令。

    ONBUILD [INSTRUCTION]
    複製代碼

    好比咱們生成的鏡像是用來部署Python代碼的,可是由於有多個項目可能會複用該鏡像。你能夠這樣使用:

    [...]
    # 在下一次以此鏡像爲base image的構建中,執行ADD . /app/src,將項目代目添加到新鏡像中去
    ONBUILD ADD . /app/src # 而且build Python代碼
    ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
    複製代碼

    不容許ONBUILD使用連接指令ONBUILD ONBUILD
    ONBUILD只會繼承給子節點的鏡像,不會再繼承給孫子節點。
    ONBUILD不會觸發FROMMAINTAINER指令。

  • STOPSIGNAL
    觸發系統信號。

    STOPSIGNAL signal
    複製代碼

    STOPSIGNAL指令設置將發送到容器以退出的系統調用信號。此信號能夠是與內核的SysCall表中的位置匹配的有效無符號數字(例如9),也能夠是格式爲SIGNAME的信號名稱(例如SIGKILL)。

  • HEALTHCHECK
    增長自定義的心跳檢測功能,屢次使用只有最後一次有效。格式:

    HEALTHCHECK [OPTIONS] CMD command (經過在容器內運行命令來檢查容器運行情況)
    HEALTHCHECK NONE (禁用從基礎映像繼承的任何運行情況檢查)
    複製代碼

    可選的OPTION:

    1. --interval=DURATION(檢測間隔,默認值:30s)
    2. --timeout=DURATION(命令超時時間,默認值:30s)
    3. --start-period=DURATION(初始化後開始檢查時間,默認值:0s)
    4. --retries=N(連續N次失敗後標記爲不健康,默認值:3次)

    Start Period爲須要時間引導的容器提供初始化時間。在此期間的探測失敗將不計入最大重試次數。可是,若是運行情況檢查在開始期間成功,則容器將被視爲已啓動,而且全部連續失敗將計入最大重試次數。

    <command>能夠是shell腳本,也能夠是exec格式的json數組。 docker以<command>的退出狀態碼來區分容器是否健康,這一點同shell一致:

    • 0:命令返回成功,容器健康
    • 1:命令返回失敗,容器不健康
    • 2:保留狀態碼,不要使用 舉個栗子:每5分鐘檢測本地網頁是否可訪問,超時設爲3秒:
    HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1 複製代碼

    你可使用docker inspect命令查看健康狀態。
    當容器的運行情況發生更改時,將生成帶有新狀態的health_status事件。

  • SHELL
    更改後續的Dockerfile指令中所使用的shell。默認的shell是["bin/sh", "-c"]。可屢次使用,每次都只改變後續指令。

    SHELL ["executable", "parameters"] 複製代碼
相關文章
相關標籤/搜索