天天看點

Dockerfile檔案指令

Dockerfile 檔案類似于一個配置檔案,Docker 可以通過讀取其中的指令來自動建構鏡像,官網位址:[url=https://docs.docker.com/engine/reference/builder/]https://docs.docker.com/engine/reference/builder/[/url]。

Dockerfile的内容格式如下:

# comment

# INSTRUCTION arguments

雖然 Dockerfile 并不區分大小寫,不過按照慣例,一般指令都大寫,以與參數部分區分。

類似于 shell 腳本開頭中的“#!/bin/bash”寫法,Dockerfile 開頭也可有相應的解析指令,其格式如下:

# directive=value (注:不允許跨行)

目前官網上列出的解析指令僅有“escape”,是用來自定義轉義字元的,預設是“\”。

下面開始介紹 Dockerfile 檔案中各個指令的用法。

* FROM

格式:

FROM image[:tag] 或者 FROM [email protected]

關于 FROM 指令,需要注意以下幾點:

(1) FROM 為随後的指令設定了一個基礎鏡像,是以必須在 Dockerfile 的第一個非注釋行。

(2) FROM 可以出現多次,以便建立多個鏡像。

(3) 當忽略掉 tag 或 digest 時,預設會以 latest 來代替。

* RUN

RUN 指令可用來在目前鏡像中執行任意指令,并把執行結果傳給 Dockerfile 中的下一步。RUN 指令的格式為:

RUN command 或者 RUN ["executable", "param1", "param2"]

其中,前一種屬于“shell”形式,運作指令的 shell 在 Linux 上預設是“/bin/sh -c”,在 Windows 上預設是“cmd /S /C”。運作 shell 是可以通過指令改變的,比如:

RUN /bin/bash -c 'echo $HOME'

後一種屬于“exec”形式(它會被解析成 JSON 數組,是以必須用雙引号),它可以避免整理 shell 字元串,使用了一個沒有包含指定運作 shell 的基礎鏡像來運作指令。它也可以通過類似下面的指令來使用不同的運作 shell:

RUN ["/bin/bash", "-c", "echo $HOME"]

另外,在“exec”形式中是不會調用指令 shell 的,是以運作 RUN ["echo", "$HOME"]不會對 $HOME 進行變量替換(除非使用類似 RUN ["sh", "-c", "echo $HOME"] 來直接執行shell),因為執行環境變量擴充是 shell 而非 docker 的工作。除此之外,對反斜杠“\”進行轉移也是必須的,尤其是在 Windows 類系統上。

RUN 的緩存不會自動失效,除非使用了類似“docker build --no-cache”的指令或使用了 ADD 指令(見下面 ADD 指令部分)。

* CMD

CMD 指令設定了啟動鏡像後預設要運作的指令,它有以下三種形式:

CMD ["executable", "param1", "param2"] # exec 形式,推薦

CMD ["param1", "param2"] # 預設作為 ENTRYPOINT 指令的參數

CMD command param1 param2 # shell 形式

在一個 Dockerfile 檔案中隻能有一個 CMD 指令。如果有多個,則隻有最後一個生效。

如果使用者在運作“docker run”指令時含有參數,則會覆寫掉 CMD 設定的預設對應參數。

* LABEL

LABEL 指令可以為一個鏡像建立中繼資料資訊。其格式為:

LABEL key1=value1 key2=value2 ...

其中,當 key 或 value 中含有空格時,應該用引号引起來。另外,LABEL 也支援使用轉義符來進行跨行定義。

* EXPOSE

EXPOSE 指令用于向 Docker 表明容器運作時要監聽的網絡端口。其格式為:

EXPOSE port [port ...]

注意,外部主機是無法通路容器中的端口的,必須使用“docker run”指令的“-p”或“-P”來指定映射端口。

* ENV

該指令可用來設定環境變量。格式為:

ENV key value

ENV key=value ...

當一個容器在鏡像中運作時,它的環境變量就會一直存在。使用者可以使用指令“docker inspect”來檢視環境變量資訊,還可使用“docker run --env key=value”來修改。然而,變量持續存在也會帶來一些副作用。比如,在 Debian 類的基鏡像中使用設定“ENV DEBIAN_FRONTEND noninteractive”就可能造成“apt-get”指令的混亂。要為單個指令設定值,可以使用“RUN key=value command”的形式。

* ADD

ADD 指令可用于複制本地或遠端的檔案或目錄(包括中繼資料)到鏡像中。格式如下:

ADD src1 src2 ... dest

ADD ["src1", ..., "dest"] # 路徑中含有空格時

當指定多個 src(包括含有通配符的情況) 時,必須相對于要建構的上下文原目錄。

dest 是一個絕對路徑或是相對于 WORKDIR 的路徑。所有新建立的檔案的 UID 和 GID 都是 0。當 src 是一個遠端位址時,目标檔案的權限将會為 600。

如果鏡像是通過傳遞 Dockerfile 檔案給标準輸入中“docker build”指令建構而成,此種情況是沒有建構上下文的,這就要求 Dockerfile 中隻能含有一個 URL 類的 ADD 指令。另外,也可傳遞壓縮檔案給“docker build”,不過要求 Dockerfile 位于壓縮包中的根目錄下,然後剩餘的内容就會被當作建構的上下文。

ADD 指令不支援檔案權限認證,是以當遠端檔案受權限保護時,應先用“RUN wget”或者“RUN curl”之類的工具認證掉相應的權限。

當 src 的内容變動時,第一個解析到的 ADD 指令會使随後指令的緩存失效,其中就包括了 RUN 指令。

另外,ADD 遵循下面這些規則:

(1) src 路徑要在要建構的上下文中,不能使用類似于“ADD ../something dest”的寫法,因為“docker build”的第一步就是發送建構上下文目錄給 docker 背景程序。

(2) 如果 src 是一個遠端位址,并且 dest 沒有以“/”結尾,那麼遠端檔案就會先被下下來,然後再複制到 dest;否則就直接複制到 dest 目錄下。

(3) 當 src 是本地壓縮檔案時,複制之前會先被解壓,而遠端壓縮檔案則不會。

(4) 如果 src 是一個其它類型的檔案,它就會與它的中繼資料一起被單獨複制。此時,如果 dest 以“/”結尾,它就會被當成是目錄,然後把 src 的内容寫到 dest/base(src) 中。

(5) 當指定多個 src (包括使用通配符的情況)時,dest 必須是已“/”結尾的目錄。

(6) 如果 dest 沒有以“/”結尾,那它就會被當成是普通檔案,然後 src 的内容就會直接寫到 dest 中。

(7) 當 dest 不存在時,它就會被遞歸建立。

* COPY

格式:

COPY src1 src2 ... dest

COPY ["src1", ..., "dest"] # 路徑中含有空格時

COPY 和 ADD 都可以複制 src 的内容到 dest,差別是 COPY 不能複制遠端檔案,然後其餘的規則和限制都一樣。

* ENTRYPOINT

ENTRYPOINT 可将容器配置成可執行檔案的形式。格式如下:

ENTRYPOINT ["executable", "param1", "param2"] # exec 形式,推薦

ENTRYPOINT command param1 param2 # shell 形式

“docker run image”後的指令行參數會被添加到“exec”形式的 ENTRYPOINT 中,并且會覆寫掉所有 CMD 指定的參數。比如,“docker run image -d”就會把“-d”傳給ENTRYPOINT。可以使用“docker run --entrypoint”來覆寫 ENTRYPOINT 指令。

ENTRYPOINT 的“shell”形式會阻止 CMD 和 run 指令行參數的執行,但缺點是會被當成“/bin/sh -c”的子指令,這就意味着容器的 PID 1 将不是該可執行檔案,并且也不能接收 UNIX 信号,是以也就不能接收到來自“docker stop container”的 SIGTERM 信号(但 stop 會在逾時後被迫發送一個 SIGKILL 信号來強制停止)。要想它能正确處理信号和作為 PID 1,需要在指令前加上“exec”,比如,“ENTRYPOINT exec top -b”。

另外,也隻有最後一個 ENTRYPOINT 會生效。

ENTRYPOINT 和 CMD 都定義了容器運作時要執行的指令,它們的互相關系如下:

(1) Dockerfile 至少要指定一個 CMD 或 ENTRYPOINT。

(2) 當要把容器當成可執行檔案時,應該定義 ENTRYPOINT。

(3) CMD 應該用來為 ENTRYPOINT 定義額外的預設參數,或要在容器中執行即席指令時使用。

(4) CMD 會被運作容器時指定的替代參數覆寫。

下表顯示了指定不同的 ENTRYPOINT 和 CMD 組合時實際執行的指令情況:

[img]http://dl2.iteye.com/upload/attachment/0125/5258/0ed2b24d-f89a-3666-b78f-09923cf35120.png[/img]

* VOLUME

該指令可用來建立具有指定名字的挂載點,還可用來儲存本地主機或其它容器的外部挂載卷。格式為:

VOLUME ["/data", ...]

VOLUME /data ...

“docker run”指令會初始化新建立的挂載點,并保留解析到 VOLUME 之前已存在或生成的資料。

關于 VOLUME 需要注意以下幾點:

(1) 當使用 Windows 類容器時,挂載點必須是 a) 不存在或者空目錄 b) 不為系統驅動盤 C: 的驅動盤 兩者之一。

(2) 在挂載點被聲明後又被随後的建構步驟改變的資料不會生效。

(3) 挂載點與主機相關,是在容器運作時聲明的。這是為了保持鏡像的可移植性,因為一個給定的主機在别的主機上不一定可用。是以,不能在 Dockerfile 中挂載一個主機目錄(即挂載點)。VOLUME 也不支援指定一個 host-dir 參數,你必須在建立或運作容器時指定挂載點。

* USER

該指令可用來設定運作鏡像和執行随後的 RUN、CMD 及 ENTRYPOINT 等指令時的使用者名和UID。格式為:

USER daemon

* WORKDIR

該指令可為随後執行的 RUN 和 CMD 等指令設定工作目錄(不存在則建立)。格式為:

WORKDIR /path/to/workdir

WORKDIR 可以指定多次,如果其中含有相對路徑,則是相對于其上一個 WORKDIR 而言的。另外,WORKDIR 隻能處理使用 ENV 明确設定的環境變量。

* ARG

ARG 指令定義了“docker build --build-arg varname=value”需要的變量,同時該選項設定的值又會反過來影響 Dockerfile 中的 ARG 定義的對應變量的值。格式為:

ARG varname[=defaultValue]

ARG 指令可被使用多次,以定義多個變量。

注意,應該避免使用該指令與“--build-arg”來合作接收敏感資訊,因為任意該鏡像的使用者都可使用“docker history”指令來檢視所有建構時的變量值。

ARG 和 ENV 指令定義的變量都可被 RUN 指令使用。ENV 定義的環境變量會覆寫掉之前 ARG定義的同名變量的值(包括“--build-arg”傳進來的指令行參數值)。兩者結合可産生有用的互動,比如下面這個 Dockerfile 檔案:

不同于 ARG,ENV 定義的變量是持久化的,是以可像上面這個例子一樣使用 ENV 來長期儲存 ARG 接收到的指令行參數到最終鏡像中。

Docker 中已經預定義了以下這些 ARG 變量(包括它們的大寫形式):

http_proxy, https_proxy, ftp_proxy, no_proxy

雖然 ARG 變量不能持久化,但如果跟以前建構時使用的值不一樣時,也還是會影響建構緩存的。

* ONBUILD

ONBUILD 指令可為一個鏡像添加觸發器指令,當把該鏡像作為另一建構過程的基時,就會執行這些觸發器指令。格式為:

ONBUILD INSTRUCTION

ONBUILD 的工作方式是這樣的:

(1) 當解析到 ONBUILD 指令時,建構器就把這個觸發器指令添加到目前正在建構的鏡像的中繼資料中,而并不影響目前的建構過程。

(2) 在建構末尾,觸發器指令清單就被存到鏡像中繼資料清單的“OnBuild”關鍵字之下,可使用“docker inspect”指令檢視到。

(3) 之後,可利用 FROM 指令把該鏡像當成另一建構過程的基使用。在下遊的建構器處理 FROM 指令時,就會按注冊順序依次執行這些觸發器指令。任意一個指令執行出錯都會造成建構過程的失敗。

(4) 建構成功後,觸發器就會從最終鏡像中移除,是以不能被孫子輩建構過程所繼承。

示例:

注意:使用 ONBUILD ONBUILD 來連結 ONBUILD 是不允許的,ONBUILD 指令也不會觸發 FROM 和 MAINTAINER 指令。

* STOPSIGNAL

STOPSIGNAL 指令設定了發送給容器以讓其終止的信号。格式為:

STOPSIGNAL signalNum/signalName

* HEALTHCHECK

該指令可用來測試一個容器是否正在工作。格式為:

HEALTHCHECK [options] CMD command # 運作容器中的指令來檢測容器的健康狀态

HEALTHCHECK NONE # 禁用繼承自基礎鏡像的 HEALTHCHECK

其中 CMD 前的 options 選項值有:

(1) --interval=DURATION (default: 30s)

(2) --timeout=DURATION (default: 30s)

(3) --retries=N (default: 3)

它可以檢測出一個運作中的 Web 伺服器是否出現異常導緻不能處理新的連接配接這類的情況。

當一個容器指定了一個 healthcheck 後,除了正常狀态外,它還有一個“健康狀态”,它初始時是“starting”。不管以前處于什麼狀态,隻要現在通過了健康檢查,它就被當作是“健康的”;而如果連續多次不通過,就被當作是“不健康的”。

在一個 Dockerfile 中,隻能存在一個 HEALTHCHECK 指令。

在 CMD 後的指令可以是“shell”形式,也可以是“exec”形式。

該指令的退出狀态表面了容器的健康狀态。可能的值有:

(1) 0:成功(容器是“健康的”,随時可用)

(2) 1:不健康的(容器不能正确地工作)

(3) 2:保留

下面是一個每隔 5 分鐘檢測一次某 Web 伺服器能否在 3 秒内正确服務首頁的示例:

為了幫助調試,任何指令輸出的内容都被存到了健康狀态之中,可使用“docker inspect”指令檢視。

當容器的健康狀态改變時,就會産生一個帶有新的狀态的“health_status”事件。

* SHELL

該指令可用來覆寫“shell”形式的指令的預設執行 shell(Linux 上的預設 shell 是 ["/bin/sh", "-c"],Windows 上的是["cmd", "/S", "/C"])。格式為:

SHELL ["executable", "param"]

SHELL 指令可以出現多次。每個都會覆寫先前的 SHELL,然後被當作随後其它指令的執行 shell。示例:

另外,SHELL 指令還可用來修改 shell 的操作方式。例如,在 Windows 上使用“SHELL cmd /S /C /V:ON|OFF”将會更改環境變量延遲擴充文法。