Docker7-使用 Dockerfile 創(chuàng)建鏡像

Dockerfile 是一個(gè)文本格式的配置文件, 用戶可以使用 Dockerfile 來(lái)快速創(chuàng)建自定義的鏡像.

基本結(jié)構(gòu)

Dockerfile 由一行行命令語(yǔ)句組成, 并且支持以 # 開頭的注釋行.
一般而言, Dockerfile 分為四部分: 基礎(chǔ)鏡像信息 維護(hù)者信息 鏡像操作指令和容器啟動(dòng)時(shí)執(zhí)行指令. 例如:

FROM centos:latest
MAINTAINER docker_user docker_user@email.com
RUN yum -y update
RUN yum -y install systemd systemd-libs
RUN yum clean all;
CMD ["/usr/sbin/init"]

其中, 一開始必須指明所基于的鏡像名稱, 接下來(lái)一般是說(shuō)明維護(hù)者信息. 后面則是鏡像操作指令, 例如 RUN 指令, RUN 指令將對(duì)象執(zhí)行跟隨的命令. 每運(yùn)行一條 RUN 指令, 鏡像就添加新的一層, 并提交. 最后是 CMD 指令, 用來(lái)指定運(yùn)行容器時(shí)的操作命令.


命令詳解

1.FROM
指定所創(chuàng)建鏡像的基礎(chǔ)鏡像, 如果本地不存在, 則默認(rèn)會(huì)去 Docker Hub 下載指定鏡像.

格式為 FROM<image> 或 FROM<image>:<tag> 或 FROM<image>@<digest>

任何 Dockerfile 中的第一條指令必須為 FROM 指令. 并且, 如果在同一個(gè) Dockerfile 中創(chuàng)建多個(gè)鏡像, 可以使用多個(gè) FROM 指令(每個(gè)鏡像一次).

2. MAINTAINER
指定維護(hù)者信息, 格式為 MAINTAINER<name>. 例如:

MAINTAINER docker_user@email.com

該信息會(huì)寫入生成鏡像的 Author 屬性域中.

3. RUN
運(yùn)行指定命令.
格式為 RUN<command> 或 RUN ["executable", "param1", "param2"]. 注意, 后一個(gè)指令會(huì)被解析為 Json 數(shù)組, 因此必須用雙引號(hào).

前者默認(rèn)在 shell 終端中運(yùn)行命令, 即 /bin/sh -c; 后者則使用 exec 執(zhí)行, 不會(huì)啟動(dòng) shell 環(huán)境.

指定使用其他終端類型可以通過(guò)第二種方式實(shí)現(xiàn), 例如 RUN ["/bin/bash", "-c", "echo hello"].

每條 RUN 指令將在當(dāng)前鏡像的基礎(chǔ)上執(zhí)行指定命令, 并提交為新的鏡像. 當(dāng)命令較長(zhǎng)時(shí)可以使用 \ 來(lái)?yè)Q行.例如:

RUN apt-get update \
        && apt-get install -y libsnappy-dev zlib1g-dev libbz2-dev \
        && rm -rf /var/cache/apt

4.CMD
CMD 指令用來(lái)指定啟動(dòng)容器時(shí)默認(rèn)執(zhí)行的命令. 它支持三種格式:
1.CMD ["executable", "param1", "param2"] 使用 exec 執(zhí)行, 是推薦使用的方式.
2.CMD command param1 param2/bin/sh 中執(zhí)行, 提供給需要交互的應(yīng)用.
3.CMD ["param1", "param2"] 提供給 ENTRYPOINT 的默認(rèn)參數(shù).

每個(gè) Dockerfile 只能一個(gè) CMD 命令. 如果指定了多條命令, 只有最后一條會(huì)被執(zhí)行.

如果用戶啟動(dòng)容器時(shí), 手動(dòng)指定了運(yùn)行的命令(作為 run 的參數(shù)), 則會(huì)覆蓋掉 CMD 指定的命令.

5.LABEL
LABEL 指令用來(lái)指定生成鏡像的元數(shù)據(jù)標(biāo)簽信息.
格式為 LABEL <key>=<value> <key>=<value> <key>=<value>...
例如:

LABEL version="1.0"
LABEL description=""

6.EXPOSE
聲明鏡像內(nèi)服務(wù)所監(jiān)聽的端口.
格式為EXPOSE <port> [<port>...]

EXPOSE 22 80 8080

注意, 該指令只是起到聲明作用, 并不會(huì)自動(dòng)完成端口映射.
在啟動(dòng)容器時(shí)需要使用 -P, Docker 主機(jī)會(huì)自動(dòng)分配一個(gè)宿主機(jī)的臨時(shí)端口轉(zhuǎn)發(fā)到指定的端口; 使用 -p, 則可以具體指定哪個(gè)宿主機(jī)的本地端口會(huì)映射過(guò)來(lái).

7.ENV
指定環(huán)境變量, 在鏡像生成過(guò)程中會(huì)被后續(xù) RUN 指令使用, 在鏡像啟動(dòng)的容器中也會(huì)存在.
格式為: ENV<key><value> 或 <key>=<value>....
例如:

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN .....
ENV ....

指令指定的環(huán)境變量在運(yùn)行時(shí)可以被覆蓋掉, 如 docker run --env <key>=<value> built_image.

8.ADD
該指令將復(fù)制指定的 <src> 路徑下的內(nèi)容到容器中的 <dest> 路徑下.
格式為 ADD <src> <dest>

其中 <src> 可以是 Dockerfile 所在目錄的一個(gè)相對(duì)路徑(文件或目錄), 也可以是 URL, 還可以是一個(gè) tar 文件(如果為 tar 文件, 會(huì)自動(dòng)解壓到 <dest> 路徑下). <dest> 可以是鏡像內(nèi)的絕對(duì)路徑, 或者相對(duì)于工作目錄(WORKDIR) 的相對(duì)路徑.
路徑支持正則格式, 例如:

ADD *.c /code/

9.COPY
格式為COPY <src> <dest>
復(fù)制本地主機(jī)的 <src>(為 Dockerfile 所在目錄的相對(duì)路徑 文件或目錄) 下的內(nèi)容到鏡像中的 <dest> 下. 目標(biāo)路徑不存在時(shí), 會(huì)自動(dòng)創(chuàng)建.
路徑同樣支持正則格式.
當(dāng)使用本地目錄為源目錄時(shí), 推薦使用 COPY.

10.ENTRYPOINT
指定鏡像的默認(rèn)入口命令, 該入口命令會(huì)在啟動(dòng)容器時(shí)作為根命令執(zhí)行, 所有傳入值作為該命令的參數(shù).
支持兩種格式:

ENTRYPOINT ["executable", "param1", "param2"](exec 調(diào)用執(zhí)行)
ENTRYPOINT command param1 param2(shell 中執(zhí)行)

每個(gè) Dockerfile 中只能有一個(gè) ENTRYPOINT, 當(dāng)指定多個(gè)時(shí), 只有最后一個(gè)有效.

在運(yùn)行時(shí), 可以被 --entrypoint 參數(shù)覆蓋掉, 如 docker run --entrypoint.

11.VOLUME
創(chuàng)建一個(gè)數(shù)據(jù)卷掛載點(diǎn).
格式為 VOLUME ["/data"]
可以從本地主機(jī)或其他容器掛載數(shù)據(jù)卷, 一般用來(lái)存放數(shù)據(jù)庫(kù)和需要保存的數(shù)據(jù)等.

12.USER
指定運(yùn)行容器時(shí)的用戶名或 UID, 后續(xù)的 RUN 等指令也會(huì)使用指定的用戶身份.
格式為 USER daemon

當(dāng)服務(wù)不需要管理員權(quán)限時(shí), 可以通過(guò)該命令指定運(yùn)行用戶, 并且可以在之前創(chuàng)建需要的用戶. 例如:

RUN groupadd -r postgres && useradd -r -g postgres postgres

要臨時(shí)獲取管理員權(quán)限可以使用 gosu 或 sudo.

13.WORKDIR
為后續(xù)的 RUN CMD 和 ENTRYPOINT 指令配置工作目錄.
格式為 WORKDIR /path/to/workdir
可以使用多個(gè) WORKDIR 指令, 后續(xù)命令如果參數(shù)是相對(duì)路徑, 則會(huì)基于之前命令指定的路徑. 例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

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

14.ARG
指定一些鏡像內(nèi)使用的參數(shù)(例如版本號(hào)信息等), 這些參數(shù)在執(zhí)行 docker build 命令時(shí)才以 --build-arg<varname>=<value> 格式傳入.
格式為 ARG<name>[=<defaults value>]
則可以用 docker build --build-arg<varname>=<value>. 來(lái)指定參數(shù)值.

15.ONBUILD
配置當(dāng)所創(chuàng)建的鏡像作為其他鏡像的基礎(chǔ)鏡像時(shí), 所執(zhí)行的創(chuàng)建操作命令.
格式為 ONBUILD [INSTRUCTION]
例如, Dockerfile 使用如下的內(nèi)容創(chuàng)建了鏡像 image-A

[...]
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src
[...]

如果基于 image-A 創(chuàng)建新的鏡像時(shí), 新的 Dockerfile 中使用 FROM image-A 指定基礎(chǔ)鏡像, 會(huì)自動(dòng)執(zhí)行 ONBUILD 指令的內(nèi)容, 等價(jià)于在后面添加了兩條指令:

FROM image-A

#Automatically run the following
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src

使用 ONBUILD 指令的鏡像, 推薦在標(biāo)簽中注明, 例如 ruby:1.9-onbuild

16.STOPSIGNAL
指定所創(chuàng)建鏡像啟動(dòng)的容器接收退出的信號(hào)值. 例如:

STOPSIGNAL signal

17.HEALTHCHECK
配置所啟動(dòng)容器如何進(jìn)行健康檢查(如何判斷健康與否), 自 Docker 1.12 開始支持.
格式有兩種:

HEALTHCHECK [OPTIONS] CMD command: 根據(jù)所執(zhí)行命令返回值是否為0來(lái)判斷.
HEALTHCHECK NONE: 禁止基礎(chǔ)鏡像中的健康檢查.

OPTION 支持:

--interval=DURATION(默認(rèn)為: 30s): 過(guò)多久檢查一次;
--timeout=DURATION(默認(rèn)為: 30s): 每次檢查等待結(jié)果的超時(shí);
--retries=N(默認(rèn)為: 3): 如果失敗了, 重試幾次才最終確定失敗.

18.SHELL
指定其他命令使用 shell 時(shí)的默認(rèn) shell 類型.
SHELL ["executable", "parameters"]
默認(rèn)值為 ["/bin/sh", "-c"]

注意: 對(duì)于 Windows 系統(tǒng), 建議在 Dockerfile 開頭添加 # escape =`來(lái)指定轉(zhuǎn)義信息.


創(chuàng)建鏡像

編寫完成 Dockerfile 之后, 可以通過(guò) docker build命令來(lái)創(chuàng)建鏡像.
基本的格式為 docker build[選項(xiàng)] 內(nèi)容路徑, 該命令將讀取指定路徑下(包括子目錄)的 Dockerfile, 并將該路徑下的所有內(nèi)容發(fā)送給 Docker 服務(wù)器, 由服務(wù)器來(lái)創(chuàng)建鏡像.

因?yàn)槌巧社R像需要, 否則一般建議放置在 Dockerfile 的目錄為空目錄. 有兩點(diǎn)經(jīng)驗(yàn):
1.如果使用非內(nèi)容路徑下的 Dockerfile, 可以通過(guò) -f 選項(xiàng)來(lái)指定其路徑.
2.要指定生成鏡像的標(biāo)簽信息, 可以使用 -t 選項(xiàng).

例如, 指定 Dockerfile 所在路徑為 /tmp/docker_builder/, 并且希望生成鏡像標(biāo)簽為 build_repo/first_image, 可以使用下面的命令:

docker build -t build_repo/first_image /tmp/docker_builder/

使用 .dockerignore 文件

可以通過(guò) .dockerignore 文件(每一行添加一條匹配模式) 來(lái)讓 Docker 忽略匹配模式路徑下的目錄和文件. 例如:

# comment
    */temp*
    */*/temp*
    tmp?
    ~*

最佳實(shí)踐

所謂最佳實(shí)踐, 實(shí)際上是從需求出發(fā), 來(lái)定制適合自己 高效方便的鏡像.

首先, 要盡量吃透每個(gè)指令的含義和執(zhí)行結(jié)果, 自己多編寫一些簡(jiǎn)單的例子進(jìn)行測(cè)試, 弄清除了在撰寫正式的 Dockerfile. 此外, Docker Hub 官方倉(cāng)庫(kù)中提供了大量的優(yōu)秀鏡像和對(duì)應(yīng)的 Dockerfile, 通過(guò)閱讀他們來(lái)學(xué)習(xí)如何撰寫高效的 Dockerfile.

建議初學(xué)者在生成鏡像過(guò)程中, 嘗試從如下角度進(jìn)行思考, 完善所生成的鏡像.

**精簡(jiǎn)鏡像用途: **盡量讓每個(gè)鏡像的用途都比較集中 單一, 避免構(gòu)造大而復(fù)雜 多功能的鏡像.

**選用合適的基礎(chǔ)鏡像: **過(guò)大的基礎(chǔ)鏡像會(huì)造成臃腫的鏡像, 一般推薦比較小巧的 debian 鏡像.

**提供足夠清晰的命令注釋和維護(hù)者的信息: ** Dockerfile 也是一種代碼, 需要考慮方便后續(xù)擴(kuò)展和他人使用.

**正確使用版本號(hào): **使用明確的版本號(hào)信息, 如1.0, 2.0, 而非 latest, 將避免內(nèi)容不一致可能引發(fā)的慘案.

**減少鏡像層數(shù): **如果希望所生成鏡像層數(shù)盡量少, 則要盡量合并命令, 例如多個(gè) RUN 指令可以合并為一條.

**及時(shí)刪除臨時(shí)文件和緩存文件: **特別是在執(zhí)行 apt-get 指令后, /var/cache/apt 下面會(huì)緩存一些安裝包.

**高度生成速度: **合理使用緩存, 減少內(nèi)容目錄下的文件, 或使用 .dockerignore 文件指定等.

**調(diào)整合理的指令順序: **在開啟緩存的情況下, 內(nèi)容不變的指令盡量放在前面, 這樣可以盡量復(fù)用.

**減少外部源的干擾: **如果確實(shí)要從外部引入數(shù)據(jù), 需要指定持久的地址, 并帶有版本信息, 讓他人可以重復(fù)而不出錯(cuò).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容