天天看點

Dockerfile指令詳解

博文大綱: dockerfile基本結構 dockerfile常用指令 FROM——指定基礎鏡像 MAINTAINER——指定維護者資訊 RUN——運作指令 COPY——複制檔案\目錄 ADD——更進階的複制檔案\目錄 ENV——設定環境變量 ARG——建構參數 EXPOSE——暴露端口 CMD——容器啟動指令 ENTRYPOINT——入口點 ENTRYPOINT和CMD組合使用 VOLUME——定義匿名卷 USER——指定目前使用者 WORKDIR——指定工作目錄 ONBUILD——為他人做嫁衣

Dockerfile由一行行指令語句組成,并且支援以#開頭的注釋行。

一般Dockerfile分為四部分:基礎鏡像資訊、維護者資訊、鏡像操作指令和容器啟動時執行指令。如下:

其中,一開始必須指明所基于的鏡像,接下來推薦說明維護者資訊,再接下來就是鏡像操作的指令,如RUN、COPY等。每運作一條指令,就會為鏡像添加新的一層并送出,注:一個鏡像最多不允許超過127層。最後時CMD指令,是指定運作容器時的操作指令。

格式為:FROM <image>或者 FROM <image>:<tag>。

第一條指令必須為FROM指令,如果在同一個dockerfile中建立多個鏡像時,可以使用多個FROM指令(每個鏡像一次,但是一般不會這麼做)。

格式為:MAINTAINER <name> <email>。用來指定維護者資訊。

格式為:RUN <command> 或者RUN ["executable", "param1", "param2"]。

前者将在 shell 終端中運作指令,即 /bin/sh -c;後者則使用 exec 執行。指定使用其它終端可以通過第二種方式實作,例如 RUN ["/bin/bash", "-c", "echo hello"]。

每條 RUN 指令将在目前鏡像基礎上執行指定指令,并送出為新的鏡像。當指令較長時可以使用 \ 來換行。(注:如果覺得鏡像的層數可能過多,可以一個RUN指令後面接多條指令,中間使用&&進行拼接即可)。

格式為:格式為 COPY <src> <dest>。

作用:複制本地的<src> (源檔案/目錄必須要與Dockerfile在相同的目錄中)到容器中的<dest>。

當使用本地目錄為源目錄時,推薦使用COPY。

使用COPY時,所指定的源檔案/目錄,也可以是其他鏡像中的檔案,格式如下:

格式為:ADD <src> <dest>。它和COPY很相似,同樣需要源檔案和Dockerfile位于相同目錄中,或者是一個URL。它比COPY更為人性化些。

該指令将複制指定的 <src> 到容器中的 <dest>。 其中 <src> 可以是Dockerfile所在目錄的一個相對路徑;也可以是一個 URL(自動下載下傳URL所對應的檔案);還可以是一個 tar 檔案(自動解壓為目錄)。

在使用該指令的時候還可以加上 --chown=<user>:<group> 選項來改變檔案的所屬使用者及所屬組。

ADD 指令會令鏡像建構緩存失效,進而可能會令鏡像建構變得比較緩慢。

但在某些情況下,如果我們真的是希望複制個壓縮檔案進去,而不解壓縮,這時就不可以使用 ADD 指令了。

是以在 COPY 和 ADD 指令中選擇的時候,可以遵循這樣的原則,所有的檔案複制均使用 COPY 指令,僅在需要自動解壓縮的場合使用 ADD。

格式為 ENV <key> <value>。 指定一個環境變量,會被後續 RUN 指令使用,并在容器運作時保持。

舉個栗子:

格式:ARG <參數名>[=<預設值>]

建構參數和 ENV 的效果一樣,都是設定環境變量。所不同的是,ARG 所設定的建構環境的環境變量,在将來容器運作時是不會存在這些環境變量的。但是不要是以就使用 ARG 儲存密碼之類的資訊,因為 docker history 還是可以看到所有值的。

Dockerfile 中的 ARG 指令是定義參數名稱,以及定義其預設值。該預設值可以在建構指令 docker build 中用 --build-arg <參數名>=<值> 來覆寫。

在 1.13 之前的版本,要求 --build-arg 中的參數名,必須在 Dockerfile 中用 ARG 定義過了,換句話說,就是 --build-arg 指定的參數,必須在 Dockerfile 中使用了。如果對應參數沒有被使用,則會報錯退出建構。從 1.13 開始,這種嚴格的限制被放開,不再報錯退出,而是顯示警告資訊,并繼續建構。這對于使用 CI 系統,用同樣的建構流程建構不同的 Dockerfile 的時候比較有幫助,避免建構指令必須根據每個 Dockerfile 的内容修改。

格式為:EXPOSE <port> [<port>...]。

該指令的作用是告訴docker服務端容器暴露的端口号,供互聯系統使用,在啟動容器時需要通過-P,docker主機會自動配置設定一個端口轉發到指定的端口。

它支援以下三種格式: CMD ["executable","param1","param2"] 使用 exec 執行,推薦方式; CMD command param1 param2 在 /bin/sh 中執行,提供給需要互動的應用; CMD ["param1","param2"] 提供給 ENTRYPOINT 的預設參數;

作用是指定啟動容器時執行的指令,每個dockerfile隻有一條CMD指令,如果指定了多條,那麼前面的會被覆寫,隻有最後一條指令生效。

如果使用者啟動容器時指定了運作的指令,則會覆寫掉CMD指定的指令。

如下:

一般我将CMD和ENTRYPOINT結合使用。也就是上面的第三種格式。

它支援下面兩種格式: ENTRYPOINT ["executable", "param1", "param2"]; ENTRYPOINT command param1 param2(shell中執行)。

配置容器啟動後執行的指令,并且不可被docker run提供的參數覆寫。

每個dockerfile中隻能有一個ENTRYPOINT ,當指定多個時,隻有最後一個起效。

使用舉例:

在某種情況下,ENTRYPOINT和CMD組合使用能發揮更大的作用。

組合使用ENTRYPOINT和CMD, ENTRYPOINT指定預設的運作指令, CMD指定預設的運作參數。

檢視容器最後一條執行的指令如下:

Dockerfile指令詳解

上面執行的指令是ENTRYPOINT和CMD指令拼接而成. ENTRYPOINT和CMD同時存在時, docker把CMD的指令拼接到ENTRYPOINT指令之後, 拼接後的指令才是最終執行的指令. 但是由于上文說docker run指令行執行時, 可以覆寫CMD指令的值. 如果你希望這個docker鏡像啟動後不是ping localhost, 而是ping其他伺服器,, 可以這樣執行docker run:

Dockerfile指令詳解

下表列出了如果把Shell表示法和Exec表示法混合, 最終得到的指令行, 可以看到如果有Shell表示法存在, 很難得到正确的效果:

從上面看出, 隻有ENTRYPOINT和CMD都用Exec表示法, 才能得到預期的效果。

容器運作時應該盡量保持容器存儲層不發生寫操作,對于資料庫類需要儲存動态資料的應用,其資料庫檔案應該儲存于卷(volume)中,為了防止運作時使用者忘記将動态檔案所儲存目錄挂載為卷,在 Dockerfile 中,可以事先指定某些目錄挂載為匿名卷,這樣在運作時如果使用者不指定挂載,其應用也可以正常運作,不會向容器存儲層寫入大量資料。

指令格式為:VOLUME ["/data"]。

作用:/data 目錄就會在運作時自動挂載為匿名卷,任何向 /data 中寫入的資訊都不會記錄進容器存儲層,進而保證了容器存儲層的無狀态化。當然,運作時可以覆寫這個挂載設定。比如:

在這行指令中,就使用了 mydata 這個命名卷挂載到了 /data 這個位置,替代了 Dockerfile 中定義的匿名卷的挂載配置。

這種方式是docker manager volumes資料持久化方式,不支援Bind mount挂載方式(也就是不支援指定本地的目錄)。

在基于鏡像運作容器後,可以通過指令“docker inspect container_name”檢視容器的詳細資訊,在傳回的結果中,檢視MOUNT字段可以看到容器内對應的本地目錄位置,如下:

傳回的結果如下:

Dockerfile指令詳解

指令格式為:USER <使用者名>[:<使用者組>]。

指定運作容器時的使用者名或 UID,後續的 RUN 也會使用指定使用者。

USER 指令和 WORKDIR 相似,都是改變環境狀态并影響以後的層。WORKDIR 是改變工作目錄,USER 則是改變之後層的執行 RUN, CMD 以及 ENTRYPOINT 這類指令的身份。

當然,和 WORKDIR 一樣,USER 隻是幫助你切換到指定使用者而已,這個使用者必須是事先建立好的,否則無法切換。

如果以 root 執行的腳本,在執行期間希望改變身份,比如希望以某個已經建立好的使用者來運作某個服務程序,不要使用 su 或者 sudo,這些都需要比較麻煩的配置,而且在 TTY 缺失的環境下經常出錯。建議使用 gosu。

格式為:WORKDIR /path/to/workdir。

為後續的 RUN、CMD、ENTRYPOINT 指令配置工作目錄。

可以使用多個 WORKDIR 指令,後續指令如果參數是相對路徑,則會基于之前指令指定的路徑。例如

則最終路徑為 /a/b/c。

格式為:ONBUILD [INSTRUCTION]。

配置當所建立的鏡像作為其它新建立鏡像的基礎鏡像時,所執行的操作指令。

例如,Dockerfile 使用如下的内容建立了鏡像 image-A。

如果基于 image-A 建立新的鏡像時,新的Dockerfile中使用 FROM image-A指定基礎鏡像時,會自動執行ONBUILD 指令内容,等價于在後面添加了兩條指令。

使用 ONBUILD 指令的鏡像,推薦在标簽中注明,例如 ruby:1.9-onbuild。

———————— 本文至此結束,感謝閱讀 ————————