天天看點

Docker實戰(六)之使用Dockerfile建立鏡像

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)減少外部源的幹擾:如果确實要從外部引入資料,需要指定持久的位址,并帶有版本資訊,讓他人可以重複而不出錯。