使用Dockerfile創建鏡像


Dockerfile是一個文本格式的配置文件,用戶可以使用Dockerfile來快速創建自定義的鏡像。

Dockerfile典型的基本結構和它支持的眾多指令,並具體講解通過這些指令來編寫定制鏡像的Dockerfile,以及如何生成鏡像。

最后介紹使用Dockerfile的一些最佳實踐經驗。

基本結構

Dockerfile由一行行命令語句組成,並且支持以#開頭的注釋行。

一般而言,Dockerfile分為四部分:基礎鏡像信息維護者信息鏡像操作指令容器啟動時執行指令

例如:

# This Dockerfile uses the ubuntu image

# VERSION 2 - EDITION 1

# Author: docker_user

# Command format: Instruction [arguments / command] ..

# Base image to use, this must be set as the first line

FROM ubuntu

# Maintainer: docker_user <docker_user at="" email.com="">(@docker_user)

MAINTAINER docker_user docker_user@email.com

# Commands to update the image

RUN echo "deb http://archive.ubuntu.com/ubuntu/ raring main universe" >> /etc/apt/sources.list

RUN apt-get update && apt-get install -y nginx

RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf

# Commands when creating a new container

CMD /usr/sbin/nginx

其中,一開始必須指明所基於的鏡像名稱,接下來一般是說明維護者信息。后面則是鏡像操作指令,例如RUN指令,RUN指令將對鏡像執行跟隨的命令。每運行一條RUN指令,鏡像就添加新的一層,並提交。最后是CMD指令,用來指定運行容器時的操作命令。

下面是Docker Hub上兩個熱門鏡像的Dockerfile的例子,可以幫助對Dockerfile結構有個基本的認識。

第一個例子是在debian:jessie基礎鏡像基礎上安裝Nginx環境,從而創建一個新的nginx鏡像

FROM debian:jessie

MAINTAINER NGINX Docker Maintainers "docker-maint@nginx.com"

ENV NGINX_VERSION 1.10.1-1

RUN apt-key adv --keyserver hkp://pgp.mit.edu:80 --recv-keys 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 \
&& echo "deb http://nginx.org/packages/debian/ jessie nginx" >> /etc/
apt/sources.list \
&& apt-get update \
&& apt-get install --no-install-recommends --no-install-suggests -y \
ca-certificates \
nginx=${NGINX_VERSION} \
nginx-module-xslt \
nginx-module-geoip \
nginx-module-image-filter \
nginx-module-perl \
nginx-module-njs \
gettext-base \
&& rm -rf /var/lib/apt/lists/*
# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/access.log \
&& ln -sf /dev/stderr /var/log/nginx/error.log
EXPOSE 80 443
CMD [
"nginx""-g""daemon off;"

指令說明

指令的一般格式為INSTRUCTION arguments,指令包括FROM、MAINTAINER、RUN等,參見表8-1。

1.FROM

指定所創建鏡像的基礎鏡像,如果本地不存在,則默認會去Docker Hub下載指定鏡像。

格式為FROM,或FROM:,或FROM@。

任何Dockerfile中的第一條指令必須為FROM指令。並且如果在同一個Dockerfile中創建多個鏡像,可以使用多個FROM指令(每個鏡像一次)。

2.MAINTAINER

指定維護者信息,格式為MAINTAINER。例如:

MAINTAINER image_creator@docker.com

該信息會寫入生成鏡像的Author屬性域中。

3.RUN

運行指定命令。格式為RUN或RUN["executable","param1","param2"]。

注意,后一個指令會被解析為Json數組,因此必須用雙引號。前者默認將在shell終端中運行命令,即/bin/sh-c;后者則使用exec執行,不會啟動shell環境。

指定使用其他終端類型可以通過第二種方式實現,例如RUN["/bin/bash","-c","echo hello"]。

每條RUN指令將在當前鏡像的基礎上執行指定命令,並提交為新的鏡像。當命令較長時可以使用\來換行。例如:

4.CMD

CMD指令用來指定啟動容器時默認執行的命令。它支持三種格式:

  1. CMD["executable","param1","param2"]使用exec執行,是推薦使用的方式;
  2. CMD command param1 param2在/bin/sh中執行,提供給需要交互的應用;
  3. CMD["param1","param2"]提供給ENTRYPOINT的默認參數。

每個Dockerfile只能有一條CMD命令。如果指定了多條命令,只有最后一條會被執行。

如果用戶啟動容器時手動指定了運行的命令(作為run的參數),則會覆蓋掉CMD指定的命令

5.LABEL

LABEL指令用來指定生成鏡像的元數據標簽信息。格式為LABEL = = =...。

例如:

LABEL version="1.0"

LABEL description="This text illustrates \ that label-values can span multiple lines."

6.EXPOSE

聲明鏡像內服務所監聽的端口

格式為EXPOSE[...]。

例如:EXPOSE 22 80 8443

注意,該指令只是起到聲明作用,並不會自動完成端口映射

在啟動容器時需要使用-P,Docker主機會自動分配一個宿主機的臨時端口轉發到指定的端口;使用-p,則可以具體指定哪個宿主機的本地端口會映射過來。

7.ENV

指定環境變量,在鏡像生成過程中會被后續RUN指令使用,在鏡像啟動的容器中也會存在。

格式為ENV或ENV=...。

指令指定的環境變量在運行時可以被覆蓋掉,如docker run --env=built_image。

8.ADD

該命令將復制指定的路徑下的內容到容器中的路徑下。格式為ADD。

其中可以是Dockerfile所在目錄的一個相對路徑(文件或目錄),也可以是一個URL,還可以是一個tar文件(如果為tar文件,會自動解壓到路徑下)。可以是鏡像內的絕對路徑,或者相對於工作目錄(WORKDIR)的相對路徑。路徑支持正則格式,例如:ADD *.c  /code/

9.COPY

復制本地主機的(為Dockerfile所在目錄的相對路徑、文件或目錄)下的內容到鏡像中的下。目標路徑不存在時,會自動創建。格式為COPY。

路徑同樣支持正則格式。當使用本地目錄為源目錄時,推薦使用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=格式傳入。格式為ARG[=]。

則可以用docker build --build-arg=.來指定參數值。

15.ONBUILD

配置當所創建的鏡像作為其他鏡像的基礎鏡像時,所執行的創建操作指令。格式為ONBUILD [INSTRUCTION]。

例如,Dockerfile使用如下的內容創建了鏡像image-A

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

如果基於image-A創建新的鏡像時,新的Dockerfile中使用FROM image-A指定基礎鏡像,會自動執行ONBUILD指令的內容,等價於在后面添加了兩條指令:

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

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

16.STOPSIGNAL

指定所創建鏡像啟動的容器接收退出的信號值。例如:STOPSIGNAL signal

17.HEALTHCHECK

配置所啟動容器如何進行健康檢查(如何判斷健康與否),自Docker 1.12開始支持。

格式有兩種:

HEALTHCHECK [OPTIONS] CMD command:根據所執行命令返回值是否為0來判斷;

HEALTHCHECK NONE:禁止基礎鏡像中的健康檢查。

OPTION支持:

  1. --interval=DURATION(默認為:30s):過多久檢查一次;
  2. --timeout=DURATION(默認為:30s):每次檢查等待結果的超時;
  3. --retries=N(默認為:3):如果失敗了,重試幾次才最終確定失敗。

18.SHELL

指定其他命令使用shell時的默認shell類型。默認值為["/bin/sh","-c"]。

對於Windows系統,建議在Dockerfile開頭添加#escape=`來指定轉義信息。

使用Dockerfile創建鏡像

編寫完成Dockerfile之后,可以通過docker build命令來創建鏡像

基本的格式為docker build [選項] 內容路徑,該命令將讀取指定路徑下(包括子目錄)的Dockerfile,並將該路徑下的所有內容發送給Docker服務端由服務端來創建鏡像。因此除非生成鏡像需要,否則一般建議放置Dockerfile的目錄為空目錄。

有兩點經驗:

  1. 如果使用非內容路徑下的Dockerfile,可以通過-f選項來指定其路徑。
  2. 要指定生成鏡像的標簽信息,可以使用-t選項。

例如,指定Dockerfile所在路徑為/tmp/docker_builder/,並且希望生成鏡像標簽為build_repo/first_image,

使用下面的命令:$ docker build -t build_repo/first_image /tmp/docker_builder/

使用.dockerignore文件

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

# comment  類似.gitignore
*/temp*
*/*/temp*
tmp?
~*

最佳實踐

所謂最佳實踐,實際上是從需求出發,來定制適合自己、高效方便的鏡像。

首先,要盡量吃透每個指令的含義和執行效果,自己多編寫一些簡單的例子進行測試,弄清楚了再撰寫正式的Dockerfile。此外,Docker Hub官方倉庫中提供了大量的優秀鏡像和對應的Dockefile,可以通過閱讀它們來學習如何撰寫高效的Dockerfile。

建議在生成鏡像過程中,嘗試從如下角度進行思考,完善所生成的鏡像。

  1. 精簡鏡像用途:盡量讓每個鏡像的用途都比較集中、單一,避免構造大而復雜、多功能的鏡像;
  2. 選用合適的基礎鏡像:過大的基礎鏡像會造成生成臃腫的鏡像,一般推薦較為小巧的debian鏡像
  3. 提供足夠清晰的命令注釋和維護者信息:Dockerfile也是一種代碼,需要考慮方便后續擴展和他人使用;
  4. 正確使用版本號:使用明確的版本號信息,如1.0,2.0,而非latest,將避免內容不一致可能引發的慘案;
  5. 減少鏡像層數:如果希望所生成鏡像的層數盡量少,則要盡量合並指令,例如多個RUN指令可以合並為一條
  6. 及時刪除臨時文件和緩存文件:特別是在執行apt-get指令后,/var/cache/apt下面會緩存一些安裝包;
  7. 提高生成速度:如合理使用緩存,減少內容目錄下的文件,或使用.dockerignore文件指定等;
  8. 調整合理的指令順序:在開啟緩存的情況下,內容不變的指令盡量放在前面,這樣可以盡量復用;
  9. 減少外部源的干擾:如果確實要從外部引入數據,需要指定持久的地址,並帶有版本信息,讓他人可以重復而不出錯。

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM