Dockervile是一個文本格式的配置檔案,使用者可以使用Dockerfile來快速建立自定義鏡像。
1.基本結構
Dockerfile由一行行指令語句組成,并且支援以#開頭的注釋行。
一般而言,Dockerfile分為四部分:基礎鏡像資訊、維護者資訊、鏡像操作指令和容器啟動時執行指令。
一開始必須指明所基于的鏡像名稱,接下來一般是說明維護者資訊。後面則是鏡像操作指令,例如RUN指令,RUN指令将對鏡像執行跟随的指令。每運作一條RUN指令,鏡像就添加新的一層,并送出。最後是CMD指令,用來指定運作容器時的操作指令。
2.指令說明
(1)FROM
指定所建立鏡像的基礎鏡像,如果本地不存在,則預設會去Docker Hub下載下傳指定鏡像。
格式為FROM<image>,或FROM<image>:<tag>,或FROM<image>@<digest>。
任何Dockerfile中的第一條指令必須為FROM指令。并且,如果在同一個Dockerfile中建立多個鏡像,可以使用多個FROM指令(每個鏡像一次)。
2.MAINTAINER
指定維護者資訊,格式為MAINTAINER<name>。例如:
MAINTAINER [email protected]
該資訊會寫入生成鏡像的Author屬性域中。
3.RUN
運作指定指令。
格式為RUN<command>或RUN["executable","param1","param2"]。注意,後一個指令會被解析為Json數組,是以必須用雙引号。
前者預設将在shell終端中運作指令,即/bin/sh -c;後者則使用exec執行,不會啟動shell環境。
指定使用其他終端類型可以通過第二種方式實作,例如RUN["/bin/bash","-c","echo hello"]。
每條RUN指令将在目前鏡像的基礎執行指定指令,并送出為新的鏡像。當指令較長時可以使用\來換行。
4.CMD
CMD指令用來指定啟動容器時預設執行的指令,它支援三種格式:
CMD["executable","param1","param2"]使用exec執行,是推薦使用的方式;
CMD command param1 param2在/bin/sh中執行,提供給需要互動的應用;
CMD ["param1","param2"]提供給ENTRYPOINT的預設參數。
每個Dockerfile隻能有一條CMD指令。如果指定了多條指令,隻有最後一條會被執行。
如果使用者啟動容器時手動指定了運作的指令(作為run的參數),則會覆寫掉CMD指定的指令。
5.LABEL
LABEL指令用來指定生成鏡像的中繼資料标簽資訊。
格式為LABEL<key>=<value> <key>=<value> <key>=<value>...。
6.EXPOSE
聲明鏡像内服務所監聽的端口。
格式為EXPOSE<port>[<port>...]。
例如:
EXPOSE 22 80 8443
注意,該指令隻是起到聲明作用,并不會自動完成端口映射。
在啟動容器時需要使用-P,Docker主機會自動配置設定一個主控端的臨時端口轉發到指定的端口;使用-p,則可以具體指定哪個主控端的本地端口會映射過來。
7.ENV
指定環境變量,在鏡像生成過程中會被後續RUN指定使用,在鏡像啟動的容器中也會存在。
格式為ENV<key><value>或ENV<key>=<value>...。
指令指定的環境變量在運作時可以被覆寫掉,如docker run --env<key>=<value> built_image
8.ADD
該指令将複制指定的<src>路徑下的内容到容器中的<dest>路徑下。
格式為ADD<src><dest>。
其中<src>可以是Dockerfile所在目錄的一個相對路徑(檔案或目錄),也可以是一個URL,還可以是一個tar檔案(如果為tar檔案,會自動解壓到<dest>路徑下。<dest>可以是鏡像内的的絕對路徑,或者相對于工作目錄(WORKDIR)的相對路徑。
路徑支援正則格式,例如:
ADD *.c /code/
9.COPY
格式為COPY <src> <dest>
複制本地主機的<src>(為Dockerfile所在目錄的相對路徑、檔案或目錄)下的内容到鏡像中的<dest>下。目标路徑不存在時,會自動建立。
路徑同樣支援正則格式。
當使用本地目錄為源目錄時,推薦使用COPY。
10.ENTRYPOINT
指定鏡像的預設入口指令,該入口指令會在啟動容器時作為根指令執行,所有傳入值作為該指令的參數。
支援兩種格式:
ENTRYPOINT ["executable","param1","param2"](exec調用執行);
ENTRYPOINT command param1 param2(shell中執行)。
此時,CMD指令指定值将作為根指令的參數。
每個Dockerfile中隻能有一個ENTRYPOINT,當指定多個時,隻有最後一個有效。
在運作時,可以被--entrypoint參數覆寫掉,如docker run --entrypoint。
11.VOLUME
建立一個資料卷挂載點。
格式為VOLUME["/data"]
可以從本地主機或其他容器挂載資料卷,一般用來存放資料庫和需要儲存的資料等。
12.USER
指定運作容器時的使用者名或UID,後續的RUN等指令也會使用指定的使用者身份。
格式為USER daemon。
當服務不需要管理者權限時,可以通過該指令 指定運作使用者,并且可以在之前建立所需要的使用者,例如:
RUN groupadd -r postgres && useradd -r -g postgres postgres
要臨時擷取管理者權限可以使用gosu會sudo。
13.WORKDIR
為後續的RUN、CMD和ENTRYPOINT指令配置工作目錄。
格式為WORKDIR /path/to/workdir。
可以使用多個WORKDIR指令,後續指令如果參數是相對路徑,則會基于之前的指令指定的路徑,例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
則最終路徑為/a/b/c。
14.ARG
指定一些鏡像内使用的參數(例如版本号資訊等),這些參數在執行docker build指令時才以--build-arg<varname>=<value>格式傳入。
格式為ARG<name>[=<default value>]。
則可以用docker build --build-arg<name>=<value>.來指定參數值。
15.ONBUILD
配置當所建立的鏡像作為其他鏡像的基礎鏡像時,所執行的建立操作指令。
格式為ONBUILD
使用ONBUILD指令的鏡像,推薦在标簽中注明,例如ruby:1.9-onbuild。
16.STOPSIGNAL
指定所建立鏡像啟動的容器接收退出的信号值。例如:
STOPSIGNAL signal
17.HEALTHCHECK
配置所啟動容器進行健康檢查(如何判斷健康與否),自Docker1.12開始支援。
格式有兩種:
HEALTHCHECK [OPTIONS] CMD command:根據執行指令傳回值是否為0來判斷;
HEADTHCHECK NONE:禁止基礎鏡像中的健康檢查。
OPTION支援:
--interval=DURATION(預設為:30s):過多久檢查一次;
--timeout=DURATION(預設為:30s):每次檢查等待結果的逾時;
--retires=N(預設為:3):如果失敗了,重試幾次才最終确定失敗。
18.SHELL
指定其他指令使用shell時的預設shell類型。
SHELL["executable","parameters"]
預設值為["/bin/sh","-c"]
注意:對于windows系統,建議在Dockerfile開頭添加#escape=`來指定轉義資訊。
3.建立鏡像
編寫完Dockfile之後,可以通過docker build指令來建立鏡像。
基本的格式為docker build[選項]内容路徑,該指令将讀取指定路徑下(包括子目錄)的Dockerfile,并将該路徑下的所有内容發送給Docker服務端,由服務端來建立鏡像。
是以除非生成鏡像需要,否則一般建議放置Dockerfile的目錄為空目錄。有兩點經驗:
(1)如果使用非内容路徑下的Dockerfile,可以通過-f選項來指定其路徑。
(2)要指定生成鏡像的标簽資訊,可以使用-t選項。
例如,指定Dockerfile所在路徑為/tmp/docker_builder/,并且希望生成鏡像标簽為build_repo/first_image /tmp/docker_builder/
4.使用.dockerignore檔案
可以通過.dockerignore檔案(每一行添加一條比對模式)來讓Docker忽略比對模式路徑下大的目錄和檔案。例如:
#comment
*/temp*
*/*/temp*
tmp?
_*
5.最佳實踐
所謂最佳實踐,實際上就是從需求出發,來定制适合自己,高效友善的鏡像。
首先,要盡量吃透每個指令的含義和執行效果,自己多編寫一些簡單的例子進行測試,弄清楚在撰寫正式的Dockerfile。此外,Docker Hub官方倉庫中提供了大量的優秀鏡像和對應的Dockerfile,可以通過閱讀它們來學習如何撰寫高效的Dockerfile。
如何完善生成鏡像?
(1)精簡鏡像用途:盡量讓每個鏡像的用途都比較集中、單一,避免構造大而複雜、多功能的鏡像;
(2)選用合适的基礎鏡像:過大的基礎鏡像會造成生成臃腫的鏡像,一般推薦較為小巧的debian鏡像;
(3)提供足夠清晰的指令注釋和維護者資訊:Dockerfile也是一種代碼,需要考慮友善後續拓展和他人使用;
(4)正确使用版本号:使用明确的版本号資訊,如1.0,2.0,而非latest,将避免内容不一緻可能引發的慘案;
(5)減少鏡像層數:如果希望所生成鏡像的層數盡量少,則要盡量合并指令,例如多個RUN指令開業合并為一條;
(6)及時删除臨時檔案和緩存檔案:特别是在執行apt-get指令後,/var/cache/apt 下面會緩存一些安裝包;
(7)提高生成速度:如合理使用緩存,減少内容目錄下的檔案,内容不變的指令盡量放在前面,這樣可以盡量複用;
(8)減少外部源的幹擾:如果确實要從外部引入資料,需要指定持久的位址,并帶有版本資訊,讓他人可以重複而不出錯。