Dockerfile由一行行命令語句組成,并且支持以#開頭的注釋行。 一般的,Dockerfile 分為四部分:基礎鏡像信息、維護者信息、鏡像操作指令和容器啟動時執行指令。 Dockerfile的指令是忽略大小寫的,建議使用大寫,使用 # 作為注釋,每一行只支持一條指令,每條指令可以攜帶多個參數。 Dockerfile的指令根據作用可以分為兩種:構建指令和設置指令。 ? 構建指令用于構建image,其指定的操作不會在運行image的容器上執行; ? 設置指令用于設置image的屬性,其指定的操作將在運行image的容器中執行。 可以在目錄下創建.dockerignore文件,讓Docker忽略路徑下的文件和目錄。 DockerFile的每一個指令都會新構建一層。 UnionFS是有最大層數限制的,比如AUFS,曾經是最大不能超過42層,現在是最大不能超過127層。所以,對于一些編譯、軟件的安裝、更新等操作,無需分成好幾層來操作,這樣會使得鏡像非常臃腫,擁有非常多的層,不僅僅增加了構建部署的時間,也很容易出錯!! |
指令 | 描述 | 格式 |
from | 構建指令。 指定基礎鏡像,它是最重要的一個且必須為dokefile文件開篇的第一個非注釋行,用于為鏡像文件構建過程中指定基礎鏡像,后續的指令運行于此基準鏡像所提供的運行環境 默認,docke會在本機尋找指定的鏡像,找不到的時候則從docke hub registery拉取所需鏡像,如果會找不到,則報錯返回報錯信息 如果在同一個Dockerfile中創建多個鏡像時,可以使用多個 FROM 指令。 DockerFile還存在一個特殊的鏡像srcatch ,這個鏡像是一個虛擬的概念,并不實際存在,它表示一個空白的鏡像。 如果你以scratch 作為基礎鏡像,意味著你將不使用任何鏡像為基礎,接下來你所寫的指令將作為第一層開始存在。不以任何系統為基礎,直接將可執行文件復制進鏡像的做法并不罕見。如swarm 、coreos/etcd 。對Linux下靜態編譯的程序來說,并不需要其他操作提供其運行時支持,所需的一切庫都在可執行文件里了,因此使用scratch 作為基礎,可以使鏡像的體積更加小巧 | from? <repository>[:<tag>]或者 from <repository>@<digest> repository為基礎鏡像名稱? ?tag為鏡像標簽為可選項,省略時為latest該image的最后修改的版本 |
MAINTAINER | 構建指令 用于為docke提供作者信息,無順序限制 用于將image的制作者相關的信息寫入到image中。當我們對該image執行docker inspect命令時,輸出中有相應的字段記錄該信息。 此命令已經過時,可以使用LABEL maintainer=xxx 來替代,定義多個LABEL時,可以使用 【\】反劃線來跨行 |   |
copy | 用于從docker主機復制文件至創建的新鏡像文件,但不會自動解壓,不能從【 遠端URL 】 復制。 目標路徑是容器內的絕對路徑,也可以是工作目錄下的相對路徑,工作目錄可以使用WORKDIR 指令進行指定。 使用COPY 指令會將源路徑的文件的所有元數據都拷貝,比如讀、寫、指定全選、時間變更等。 <源路徑> 可以是多個,甚至可以是通配符,其通配符規則要滿足 Go 的 filepath.Match 規則 目標路徑不需要事先創建,如果目錄不存在會在復制文件前先行創建缺失目錄 在使用該指令的時候還可以加上 --chown=<user>:<group> 選項來改變文件的所屬用戶及所屬組。 文件復制準則:  |  1 COPY [--chown=<user>:<group>] <源路徑>... <目標路徑>
2 COPY [--chown=<user>:<group>] ["<源路徑1>",... "<目標路徑>"] |
add |  構建指令 ADD 指令和COPY 的格式和性質基本一致,只不過是在COPY 的基礎上增加了一些功能。 如果是一個目錄,那么會將該目錄下的所有文件添加到container中,不包括目錄; 如果<src>是文件且<dest>中不使用斜杠結束,則會將<dest>視為文件,<src>的內容會寫入<dest>; 如果<src>是文件且<dest>中使用斜杠結束,則會<src>文件拷貝到<dest>目錄下。 目標路徑為一個URL時,會將其自動下載到目標路徑下,但是其權限被自動設置成了600 ,如果這并不是你想要的權限,那么你還需要額外增加一層RUN 命令進行更改,另外,如果下載的是一個壓縮包,同樣你還需要額外增加一層RUN 命令進行解壓縮。所以,在這種情況下,你還不如指定只用一層RUN ,使用curl 或者wget 工具進行下載,并更改權限,然后進行解壓縮,最后清理無用文件! 當你的源路徑為壓縮文件并且不想讓Docker引擎將其自動解壓縮,這個時候就不可以使用ADD 命令,你可以使用COPY 命令進行完成 |  |
run | 構建指令。 每條?RUN ?指令將在當前鏡像基礎上執行指定命令,并提交為新的鏡像。當命令較長時可以使用?\ ?來換行 RUN可以運行任何被基礎image支持的命令。如基礎image選擇了ubuntu,那么軟件管理部分只能使用ubuntu的命令 | shell格式RUN <command> ?或 exec格式RUN ["executable", "param1", "param2"] 前者將在 shell 終端中運行命令,即?/bin/sh -c ;后者則使用?exec ?執行。指定使用其它終端可以通過第二種方式實現,例如?RUN ["/bin/bash", "-c", "echo hello"] 。 |
volume | 設置指令 用于構建鏡像時定義匿名卷。 容器存儲層應該保持無狀態化,容器運行時應盡量保持容器內不發生任何寫入操作,對于需要保存動態數據的應用,其數據文件應該將其保存在數據卷中。 容器匿名卷目錄指定可以通過docker run 命令中指定-v 參數來進行覆蓋。 如果掛載點目錄下此前存在文件,docker run命令會在卷掛載完成之后將此前的所有文件復制到新掛載的卷中 運行通過該Dockerfile生成image的容器, /tmp/data 目錄中的數據在容器關閉后,里面的數據還存在。 例如另一個容器也有持久化數據的需求,且想使用上面容器共享的 /tmp/data 目錄,那么可以運行下面的命令啟動一個容器: docker run -t -i - rm ?-volumes-from container1 image2 bash 其中:container1為第一個容器的ID,image2為第二個容器運行image的名字。 | - VOLUME <路徑>
- VOLUME [“<路徑1>”, “<路徑2>”, …]
|
expose | 設置指令 EXPOSE 指令是聲明運行時容器服務端口,這只是一個聲明,在運行時并不會因為這個聲明應用就會開啟這個端口的服務。 在Dockerfile中這樣聲明有兩個好處:一個是幫助鏡像使用者更好的理解這個鏡像服務的守護端口,另一個作用則是在運行時使用隨機端口映射時,也就是docker run -p 命令時,會自動隨機映射EXPOSE 端口。 要將EXPOSE 和在運行時使用-p <宿主>:<容器端口> 區分開來,-p 是映射宿主端口和容器端口,換句話說,就是將容器的對應端口服務公開給外界訪問,而EXPOSE 僅僅是聲明端口使用什么端口而已,并不會自動在宿主進行端口映射 EXPOSE指令可以一次設置多個端口號,相應的運行容器的時候,可以配套的多次使用-p選項。 | EXPOSE 端口號 EXPOSE 端口號/協議 默認協議為TCP |
env | 設置指令 指定環境變量,它可以被其后的add、copy等調用 可以通過docker inspect查看這個環境變量,也可以通過在docker run -- env ?key=value時設置或修改環境變量 如果你要設置多個環境變量,為了美觀,你可以使用\ 來進行換行。多個環境變量的隔開,使用空格進行隔開的,如果某個環境變量的值是由一組英文單詞構成,那么你可以將其使用"" 進行圈起來 值得注意的是,如果你想通過CMD 或者ENTRYPOINT 指令的exec格式來打印環境 CMD ["echo", $MODE] CMD ["echo", "$MODE"] 上面這樣都是不能正確輸出環境變量的值的,你可以改成exec格式來執行shell命令,如下 CMD ["sh", "-c", "echo $MODE"] |  調用格式$name或者${name}  |
wokrdir | 設置指令 使用WORKDIR 指令來制定工作目錄(或者稱為當前目錄),以后各層操作的當前目錄就是為指定的目錄,如果該目錄不存在,WORKDIR 會自動幫你創建目錄 WORKDIR 指令可以通過docker run 命令中的-w 參數來進行覆蓋 |  |
user | 設置指令 指令用于將會用以什么樣的用戶去運行默認為root 可以指定用戶名或者UID,組名或者GID,或者兩者的結合 USER 指令可以在docker run 命令中的-u 參數進行覆蓋 后續的?RUN ?也會使用指定用戶。 當服務不需要管理員權限時,可以通過該命令指定運行用戶。并且可以在之前創建所需要的用戶,例如:RUN groupadd -r postgres && useradd -r -g postgres postgres 。要臨時獲取管理員權限可以使用?gosu ,而不推薦?sudo | |
healthcheck | 告訴Docker該如何判斷容器的狀態是否正常,這是1.12引入的新指令 在沒有HEALTHCHECK 指令之前,Docker引擎只可以通過容器內主進程是否退出來判斷容器狀態是否異常。很多情況下這沒有問題,但是如果程序進入了死鎖狀態,或者死循環狀態,應用進程并不退出,但是該容器已經無法繼續提供服務了。在1.12之前,Docker引擎不會檢測到容器的這種狀態,從而不會重新調度,導致可能容器已經無法提供服務了卻仍然還在接收用戶的請求。 HEALTHCHECK 指令只可以出現一次,如果有多個HEALTHCHECK 指令,那么只有最后一個才會生效 | HEALTHCHECK [options] CMD <命令>:檢查容器健康狀態的命令 HEALTHCHECK NONE:如果基礎鏡像有健康檢查指令,這一行將會屏蔽掉其健康檢查指令 HEALTHECHECK支持下列選項: ? ? ?–interval=<間隔>:兩次檢查的時間間隔,默認為30s ? ? ?–timeout=<時長>:健康檢查命令運行超時時間,如果超過這個時間,本次健康檢查將會判定? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 為失敗,默認為30s ? ? ? –retries=<次數>:當連續失敗指定次數之后,則將容器狀態視為unhealthy ,默認為3次 |
onbuild | ONBUILD 是一個特殊的指令,它后面跟著的是其他指令,比如COPY 、RUN 等,而這些命令在當前鏡像被構建時,并不會被執行。只有以當前鏡像為基礎鏡像去構建下一級鏡像時,才會被執行 | ONBUILD <其他指令> |
shell | 指定Dockerfile中 【 shell form 】命令的默認shell。 Linux中默認shell為 【 “/bin/sh”, “-c”】 | |
arg | 構建參數ARG 和ENV 指令一樣,都是設置環境變量。與之不同的是,ARG 設置的環境變量只是在鏡像構建時所設置的,在將來容器運行時是不會存在這些環境變量的。但是不要因此就用ARG 來保存密碼之類的信息,因為通過docker history 還是能夠看得到的。ARG 指令與ENV 指令的使用類似 ARG 構建參數可以通過docker run 命令中的--build-arg 參數來進行覆蓋 | |
cmd | 設置指令。 Docker不是虛擬機,容器就是進程。既然是進程,那么在啟動容器的時候,就需要指定運行的程序及參數。CMD 就是指定默認的容器主進程的啟動命令的 每個 Dockerfile 只能有一條?CMD ?命令。如果指定了多條命令,只有最后一條會被執行。 如果用戶啟動容器時候指定了運行的命令,則會覆蓋掉?CMD ?指定的命令 這里邊包括參數的一定要用雙引號,就是",不能是單引號。千萬不能寫成單引號。 原因是參數傳遞后,docker解析的是一個JSON array 一些命令在加上sh -c 之后,有可能會發生意想不到的錯誤,因此在Dockerfile中使用RUN 指令時,更加推薦使用exec 格式!最后需要牢記,使用docker run 命令指定要執行的命令可以覆蓋RUN 指令,如果我們的docker run 中指定了我們將要執行的命令,并且在Dockerfile中也指定了CMD命令 | exec格式CMD ["executable","param1","param2"] ? 使用?exec ?執行,推薦方式; shell格式CMD command param1 param2 ?在?/bin/sh ?中執行,提供給需要交互的應用。 CMD ["param1","param2"] ?提供給?ENTRYPOINT ?的默認參數,如果CMD指令使用上面的形式,那么Dockerfile中必須要有配套的ENTRYPOINT |
entrypoint | 設置指令 指定容器運行程序及參數 配置容器啟動后執行的命令,并且不可被?docker run ?提供的參數覆蓋。 每個 Dockerfile 中只能有一個?ENTRYPOINT ,當指定多個時,只有最后一個起效 ENTRYPOINT 也更加推薦使用exec 格式,ENTRYPOINT 在docker run 命令中同樣也可以進行指定,只不過比CMD 指令來的繁瑣一些,需要指定--entrypoint 參數。同樣,在docker run 命令中指定了--entrypoint 參數的話,會覆蓋Dockerfile中ENTRYPOINT 上的指令。 該指令的使用分為兩種情況,一種是獨自使用,另一種和CMD指令配合使用。 當獨自使用時,如果你還使用了CMD命令且CMD是一個完整的可執行的命令,那么CMD指令和ENTRYPOINT會互相覆蓋,只有最后一個CMD或者ENTRYPOINT有效。 CMD echo ?“Hello, World!”? ENTRYPOINT? ls ?-l? 另一種用法和CMD指令配合使用來指定ENTRYPOINT的默認參數,這時CMD指令不是一個完整的可執行命令,僅僅是參數部分; ENTRYPOINT指令只能使用JSON方式指定執行命令,而不能指定參數。 CMD [ "-l" ]? ENTRYPOINT [ "/usr/bin/ls" ]? | exec格式ENTRYPOINT ["executable", "param1", "param2"] shell格式ENTRYPOINT command param1 param2 (shell中執行) |
| | |
| | |
| | |