Docker Dockerfile詳解

dockerfike快速建立自定義的Docker鏡像html

基本語法格式:INSTRUCTION arguments (指令+參數)不分大小寫
註釋格式:# 註釋
第一個指令必須是FROM,標示使用什麼鏡像python

1、DockerFile結構 
DockerFile分爲四部分組成:基礎鏡像信、維護者信息、鏡像操做指令和容器啓動時執行指令。例如:linux

#第一行必須指令基於的基礎鏡像
From ubutu

#維護者信息
MAINTAINER docker_user  docker_user@mail.com

#鏡像的操做指令
apt/sourcelist.list

RUN apt-get update && apt-get install -y ngnix 
RUN echo "\ndaemon off;">>/etc/ngnix/nignix.conf

#容器啓動時執行指令
CMD /usr/sbin/ngnix

2、DockerFile指令詳解
一、From指令 :
FROM <image>
OR
FROM <image>:<tag>
OR
FROM <image>@<digest>nginx

DockerFile第一條必須爲From指令。若是同一個DockerFile建立多個鏡像時,可以使用多個From指令(每一個鏡像一次),鏡像能夠是任何有效的鏡像 - 經過從公共存儲庫拉取鏡像git

二、MAINTAINER 
格式爲maintainer ,指定維護者的信息github

三、RUN 
格式爲Run 或者Run [「executable」 ,」Param1」, 「param2」] ,RUN ["指令", "參數1", "參數2"...](json格式,必須雙引號)
前者在shell終端上運行,即/bin/sh -C,後者使用exec運行。例如:RUN [「/bin/bash」, 「-c」,」echo hello」] 
RUN指令將在當前鏡像之上的新層中執行任何命令,並提交結果。 生成的已提交映像將用於Dockerfile中的下一步。分層RUN指令和生成提交符合Docker的核心概念,其中提交很方便,能夠從鏡像歷史中的任何點建立容器,就像源代碼控制同樣。exec形式使得能夠避免shell字符串變化,以及使用不包含指定的shell可執行文件的基本映像來運行RUN命令。當命令比較長時,可使用\(反斜槓)將單個RUN指令繼續到下一行。golang

用於RUN指令的高速緩存在下一次構建期間不會自動失效。 用於諸如RUN apt-get dist-upgrade之類的指令的高速緩存將在下一次構建期間被重用。 能夠經過使用--no-cache標誌(例如docker build --no-cache)使用於RUN指令的高速緩存無效docker

四、CMD指令 
支持三種格式: 
CMD [「executable」 ,」Param1」, 「param2」]使用exec執行,推薦 
CMD command param1 param2,在/bin/sh上執行 
CMD [「Param1」, 「param2」] 提供給ENTRYPOINT作默認參數。shell

CMD的主要目的是爲執行容器提供默認值。 這些默認值能夠包括可執行文件,或者它們能夠省略可執行文件,在這種狀況下,您還必須指定ENTRYPOINT指令。每一個容器只能執行一條CMD命令,多個CMD命令時,只最後一條被執行。數據庫

五、EXPOSE

格式爲 EXPOSE […] 。

告訴Docker服務端容器暴露的端口號,供互聯繫統使用。在啓動Docker時,能夠經過-P,主機會自動分配一個端口號轉發到指定的端口。使用-P,則能夠具體指定哪一個本地端口映射過來

例如: 
EXPOSE 22 80 8443

六、ENV

格式爲 ENV 。 指定一個環境變量,會被後續 RUN 指令使用,並在容器運行時保持。

格式:ENV <key> <value> OR ENV <key>=<value> ...
ENV指令將環境變量<key>設置爲值<value>。 此值將在全部「descendant」Dockerfile命令的環境中,而且能夠在許多中被替換爲inline。
ENV指令有兩種形式。

第一種形式,ENV <key> <value>,將單個變量設置爲一個值。 第一個空格後面的整個字符串將被視爲<value> - 包括空格和引號等字符。
第二種形式,ENV <key> = <value> ...,容許一次設置多個變量。 注意,第二種形式在語法中使用等號(=),而第一種形式不使用。 與命令行解析相似,引號和反斜槓可用於在值中包含空格。

例如

ENV PG_MAJOR 9.3
ENV PG_VERSION 9.3.4
RUN curl -SL http://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH /usr/local/postgres-$PG_MAJOR/bin:$PATH

七、ADD

格式:ADD <src> <dest> OR ADD ["<src>", "<dest>"]
ADD指令從<src>複製新文件,目錄或遠程文件URL,並將它們添加到路徑<dest>的映像文件系統。其中 能夠是Dockerfile所在目錄的一個相對路徑;也能夠是一個URL;還能夠是一個tar文件(自動解壓爲目錄)。

ADD遵照如下規則:

  • <src>路徑必須在構建的上下文中; 你不能ADD ../something /東西,由於docker build的第一步是發送上下文目錄(和子目錄)到docker守護進程。
  • 若是<src>是URL而且<dest>不以尾部斜槓結尾,則從URL下載文件並將其複製到<dest>。
  • 若是<src>是URL而且<dest>以尾部斜槓結尾,則從URL中推斷文件名,並將文件下載到<dest> / <filename>。 例如,ADD http://example.com/foobar /會建立文件/ foobar。 該網址必須有一個非平凡的路徑,以便在這種狀況下能夠發現一個適當的文件名(http://example.com不會工做)。
  • 若是<src>是目錄,則複製目錄的所有內容,包括文件系統元數據。

將文件<src>拷貝到container的文件系統對應的路徑<dest>,全部拷貝到container中的文件和文件夾權限爲0755,uid和gid爲0,若是文件是可識別的壓縮格式,則docker會幫忙解壓縮

  • 若是要ADD本地文件,則本地文件必須在 docker build <PATH>,指定的<PATH>目錄下

  • 若是要ADD遠程文件,則遠程文件必須在 docker build <PATH>,指定的<PATH>目錄下。好比:

    docker build github.com/creack/docker-firefox
  • docker-firefox目錄下必須有Dockerfile和要ADD的文件

注意:使用docker build - < somefile方式進行build,是不能直接將本地文件ADD到container中。只能ADD url file.

ADD只有在build鏡像的時候運行一次,後面運行container的時候不會再從新加載了。

八、COPY

格式:COPY <src> <dest> OR COPY ["<src>", "<dest>"]
COPY指令從<src>複製新文件或目錄,並將它們添加到容器的文件系統,路徑<dest>。能夠指定多個<src>資源,但它們必須是相對於正在構建的源目錄 複製本地主機的 (爲Dockerfile所在目錄的相對路徑)到容器中的 。

COPY遵照如下規則:

  • <src>路徑必須在構建的目錄中; 你不能COPY ../something / something,由於docker build的第一步是將當前目錄(和子目錄)發送到docker守護進程。
  • 若是<src>是目錄,則複製目錄的所有內容,包括文件系統元數據。

當使用本地目錄爲源目錄時,推薦使用 COPY 。

九、ENTRYPOINT

兩種格式:

  • ENTRYPOINT [「executable」, 「param1」, 「param2」] 
  • ENTRYPOINT command param1 param2 (shell中執行)。 

ENTRYPOINT容許您配置將做爲可執行文件運行的容器。配置容器啓動後執行的命令,而且不可被 docker run 提供的參數覆蓋。 每一個Dockerfile中只能有一個 ENTRYPOINT ,當指定多個時,只有最後一個起效。

如:下面將啓動 nginx,監聽80端口
$ docker run -i -t --rm -p 80:80 nginx

docker run <image>的命令行參數將附加在exec形式的ENTRYPOINT中的全部元素以後,並將覆蓋使用CMD指定的全部元素。若是你結合CMD命令和ENTRYPOINT命令,你能夠從CMD命令中移除「application」而僅僅保留參數,參數將傳遞給ENTRYPOINT命令, 這容許將參數傳遞到入口點,即docker run <image> -d將把-d參數傳遞給入口點。 您可使用docker run --entrypoint標誌覆蓋ENTRYPOINT指令。

  1. Dockerfile 應該至少指定CMD或ENTRYPOINT其中的1個;
  2. 容器用做可執行的程序應用時應該用ENTRYPOINT;
  3. CMD應該用做ENTRYPOINT的默認參數來使用,或是在容器中執行臨時的命令;
  4. 啓動容器時若是傳遞參數將覆蓋dockerfile中指定的CMD參數;

下表列出了在CMD和ENTRYPOINT結合使用的狀況下,哪一個命令最終生效:

注意:若是從基礎鏡像中定義CMD,則設置ENTRYPOINT會將CMD重置爲空值。 在這種狀況下,必須在當前鏡像中定義CMD才能得到值。

十、VOLUME

格式爲 VOLUME [「/data」] 。

建立一個能夠從本地主機或其餘容器掛載的掛載點,通常用來存放數據庫和須要保持的數據等。

十一、USER

格式爲 USER daemon 。

指定運行容器時的用戶名或UID,後續的 RUN 也會使用指定用戶。

當服務不須要管理員權限時,能夠經過該命令指定運行用戶。而且能夠在以前建立所須要的用戶,例如: RUN groupadd -r postgres && useradd -r -g postgres postgres 。要臨時獲取管理員權限可使用 gosu ,而不推薦 sudo 。

十二、WORKDIR

格式爲 WORKDIR /path/to/workdir 。

爲後續的 RUN 、 CMD 、 ENTRYPOINT 指令配置工做目錄。

可使用多個 WORKDIR 指令,後續命令若是參數是相對路徑,則會基於以前命令指定的路徑。例如

WORKDIR /a 
WORKDIR b 
WORKDIR c 
RUN pwd 
則最終路徑爲 /a/b/c 。

1三、ONBUILD

格式爲 ONBUILD [INSTRUCTION] 。

配置當所建立的鏡像做爲其它新建立鏡像的基礎鏡像時,所執行的操做指令。

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

[…] 
ONBUILD ADD . /app/src 
ONBUILD RUN /usr/local/bin/python-build –dir /app/src 
[…] 
若是基於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 。

3、建立鏡像 
經過Docker Build 建立鏡像。 
命令讀取指定路徑下(包括子目錄)全部的Dockefile,而且把目錄下全部內容發送到服務端,由服務端建立鏡像。另外能夠經過建立.dockerignore文件(每一行添加一個匹配模式)讓docker忽略指定目錄或者文件

格式爲Docker Build [選項] 路徑 
須要制定標籤信息,可使用-t選項 
例如:Dockerfile路徑爲 /tmp/docker_build/,生成鏡像的標籤爲build_repo/my_images 
$dudo docker build -t build_repo/my_images /tmp/docker_build/

Dockerfile文件使用
docker build命令會根據Dockerfile文件及上下文構建新Docker鏡像。構建上下文是指Dockerfile所在的本地路徑或一個URL(Git倉庫地址)。構建上下文環境會被遞歸處理,因此,構建所指定的路徑還包括了子目錄,而URL還包括了其中指定的子模塊。

構建鏡像

將當前目錄作爲構建上下文時,能夠像下面這樣使用docker build命令構建鏡像:

$ docker build .
Sending build context to Docker daemon 6.51 MB
...

說明:構建會在Docker後臺守護進程(daemon)中執行,而不是CLI中。構建前,構建進程會將所有內容(遞歸)發送到守護進程。大多狀況下,應該將一個空目錄做爲構建上下文環境,並將Dockerfile文件放在該目錄下。

在構建上下文中使用的Dockerfile文件,是一個構建指令文件。爲了提升構建性能,能夠經過.dockerignore文件排除上下文目錄下,不須要的文件和目錄。

Dockerfile通常位於構建上下文的根目錄下,也能夠經過-f指定該文件的位置:

$ docker build -f /path/to/a/Dockerfile

構建時,還能夠經過-t參數指定構建成後,鏡像的倉庫、標籤等:

鏡像標籤

$ docker build -t shykes/myapp .

若是存在多個倉庫下,或使用多個鏡像標籤,就可使用多個-t參數:

$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .

在Docker守護進程執行Dockerfile中的指令前,首先會對Dockerfile進行語法檢查,有語法錯誤時會返回:

$ docker build -t test/myapp .
Sending build context to Docker daemon 2.048 kB
Error response from daemon: Unknown instruction: RUNCMD

緩存

Docker 守護進程會一條一條的執行Dockerfile中的指令,並且會在每一步提交併生成一個新鏡像,最後會輸出最終鏡像的ID。生成完成後,Docker 守護進程會自動清理你發送的上下文。

Dockerfile文件中的每條指令會被獨立執行,並會建立一個新鏡像,RUN cd /tmp等命令不會對下條指令產生影響。

Docker 會重用已生成的中間鏡像,以加速docker build的構建速度。如下是一個使用了緩存鏡像的執行過程:

$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1/4 : FROM alpine:3.2
 ---> 31f630c65071
Step 2/4 : MAINTAINER SvenDowideit@home.org.au
 ---> Using cache
 ---> 2a1c91448f5f
Step 3/4 : RUN apk update && apk add socat && rm -r /var/cache/
 ---> Using cache
 ---> 21ed6e7fbb73
Step 4/4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
 ---> Using cache
 ---> 7ea8aef582cc
Successfully built 7ea8aef582cc

構建緩存僅會使用本地父生成鏈上的鏡像。若是不想使用本地緩存的鏡像,也能夠經過--cache-from指定緩存。指定後將再不使用本地生成的鏡像鏈,而是從鏡像倉庫中下載。

以上內容參考官方文檔:
https://docs.docker.com/engine/reference/builder/#usage

附:Dockerfile 參考文檔

預覽目錄

Dockerfile

Dockerfile是由一系列命令和參數構成的腳本,一個Dockerfile裏面包含了構建整個image的完整命令。Docker經過docker build執行Dockerfile中的一系列命令自動構建image

Dockerfile其語法很是簡單,此頁面描述了您能夠在Dockerfile中使用的命令。 閱讀此頁面後,你能夠參閱Dockerfile最佳實踐

Usage

docker build命令從Dockerfilecontext構建image。contextPATHURL處的文件。PATH本地文件目錄。 URL是Git repository的位置。

context以遞歸方式處理。所以,PATH包括任何子目錄,URL包括repository及submodules。一個使用當前目錄做爲context的簡單構建命令:

$ docker build .
Sending build context to Docker daemon  6.51 MB
...

構建由Docker守護程序運行,而不是由CLI運行。構建過程所作的第一件事是將整個context(遞歸地)發送給守護進程。大多數狀況下,最好是將Dockerfile和所需文件複製到一個空的目錄,再到這個目錄進行構建。

警告:不要使用根目錄/做爲PATH,由於它會致使構建將硬盤驅動器的全部內容傳輸到Docker守護程序。

build時添加文件,經過Dockerfile引用指令中指定的文件,例如COPY指令。要增長構建的性能,請經過將.dockerignore文件添加到context目錄中來排除文件和目錄。有關如何建立.dockerignore文件的信息,請參閱此頁上的文檔。

通常的,Dockerfile位於context的根中。但使用-f標誌可指定Dockerfile的位置。

$ docker build -f /path/to/a/Dockerfile .

若是build成功,您能夠指定要保存新image的repository和tag:

$ docker build -t shykes/myapp .

要在構建後將image標記爲多個repositories,請在運行構建命令時添加多個-t參數:

$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .

Docker守護程序一個接一個地運行Dockerfile中的指令,若是須要,將每一個指令的結果提交到一個新image,最後輸出新映像的ID。Docker守護進程將自動清理您發送的context。

請注意,每一個指令獨立運行,並致使建立一個新image - 所以RUN cd / tmp對下一個指令不會有任何影響。

只要有可能,Docker將從新使用中間images(緩存),以顯着加速docker build過程。這由控制檯輸出中的使用緩存消息指示。(有關詳細信息,請參閱Dockerfile最佳實踐指南構建緩存部分):

$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1 : FROM alpine:3.2
 ---> 31f630c65071
Step 2 : MAINTAINER SvenDowideit@home.org.au
 ---> Using cache
 ---> 2a1c91448f5f
Step 3 : RUN apk update &&      apk add socat &&        rm -r /var/cache/
 ---> Using cache
 ---> 21ed6e7fbb73
Step 4 : CMD env | grep _TCP= | (sed 's/.*_PORT_\([0-9]*\)_TCP=tcp:\/\/\(.*\):\(.*\)/socat -t 100000000 TCP4-LISTEN:\1,fork,reuseaddr TCP4:\2:\3 \&/' && echo wait) | sh
 ---> Using cache
 ---> 7ea8aef582cc
Successfully built 7ea8aef582cc

構建成功後,就能夠準備Pushing a repository to its registry

Format

Dockerfile的格式以下:

# Comment
INSTRUCTION arguments

INSTRUCTION是不區分大小寫的,不過建議大寫。
Dockerfile中的指令第一個指令必需是FROM`,指定構建鏡像的Base Image

Dockerfile中以#開頭的行都將視爲註釋,除非是[Parser directives]()解析器指令。不支持連續註釋符。

# Comment
RUN echo 'we are running some # of cool things'

Parser directives

解析器指令是可選的,而且影響處理Dockerfile中後續行的方式。解析器指令不會向構建中添加圖層,而且不會顯示在構建步驟。解析器指令是以# directive = value形式寫成一種特殊類型的註釋。單個指令只能使用一次。

一旦註釋,空行或構建器指令已經被處理,Docker再也不尋找解析器指令。相反,它將任何格式化爲解析器指令做爲註釋,而且不嘗試驗證它是否多是解析器指令。所以,全部解析器指令必須位於Dockerfile的最頂端。

解析器指令不區分大小寫。然而,約定是他們是小寫的。公約還要包括一個空白行,遵循任何解析器指令。解析器指令不支持行連續字符。

因爲這些規則,如下示例都無效:

因行延續,無效:

# direc \
tive=value

因出現兩次,無效:

# directive=value1
# directive=value2

FROM ImageName

因寫在構建指令後,無效:

FROM ImageName
# directive=value

因寫在不是解析器指令以後,無效:

# About my dockerfile
FROM ImageName
# directive=value

未知指令視爲註釋,以後的解析器指令也隨之,無效:

# unknowndirective=value
# knowndirective=value

解析器指令中容許使用非換行符空格,下面幾行被視爲相同:

#directive=value
# directive =value
#   directive= value
# directive = value
#     dIrEcTiVe=value

支持如下解析器指令: * escape

escape

# escape=\ (backslash)
或者
# escape=` (backtick)

escape指令設置用於在Dockerfile中轉義字符的字符。若是未指定,則缺省轉義字符爲\

轉義字符既用於轉義行中的字符,也用於轉義換行符。這容許Dockerfile指令跨越多行。注意,無論escape解析器指令是否包括在Dockerfile中,在RUN命令中不執行轉義,除非在行的末尾。

將轉義字符設置爲 Windows上特別有用,其中``是目錄路徑分隔符。Windows PowerShell一致。

請考慮如下示例,這將在Windows上以非顯而易見的方式失敗。第二行末尾的第二個\將被解釋爲換行符,而不是從第一個\轉義的目標。相似地,假設第三行結尾處的\實際上做爲一條指令處理,它將被視爲行繼續。這個dockerfile的結果是第二行和第三行被認爲是單個指令:

FROM windowsservercore
COPY testfile.txt c:\\
RUN dir c:\

結果是:

PS C:\John> docker build -t cmd .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM windowsservercore
 ---> dbfee88ee9fd
Step 2 : COPY testfile.txt c:RUN dir c:
GetFileAttributesEx c:RUN: The system cannot find the file specified.
PS C:\John>

上述的一個解決方案是使用/做爲COPY指令和dir的目標。然而,這種語法,最好的狀況是混亂,由於它在Windows上是不日常的路徑,最壞的狀況下,錯誤傾向,由於並非Windows上的全部命令支持/做爲路徑分隔符。

經過添加轉義解析器指令,下面的Dockerfile在Windows上使用文件路徑的天然平臺語義成功:

# escape=`

FROM windowsservercore
COPY testfile.txt c:\
RUN dir c:\

結果是:

PS C:\John> docker build -t succeeds --no-cache=true .
Sending build context to Docker daemon 3.072 kB
Step 1 : FROM windowsservercore
 ---> dbfee88ee9fd
Step 2 : COPY testfile.txt c:\
 ---> 99ceb62e90df
Removing intermediate container 62afbe726221
Step 3 : RUN dir c:\
 ---> Running in a5ff53ad6323
 Volume in drive C has no label.
 Volume Serial Number is 1440-27FA

 Directory of c:\

03/25/2016  05:28 AM    <DIR>          inetpub
03/25/2016  04:22 AM    <DIR>          PerfLogs
04/22/2016  10:59 PM    <DIR>          Program Files
03/25/2016  04:22 AM    <DIR>          Program Files (x86)
04/18/2016  09:26 AM                 4 testfile.txt
04/22/2016  10:59 PM    <DIR>          Users
04/22/2016  10:59 PM    <DIR>          Windows
               1 File(s)              4 bytes
               6 Dir(s)  21,252,689,920 bytes free
 ---> 2569aa19abef
Removing intermediate container a5ff53ad6323
Successfully built 2569aa19abef
PS C:\John>

Environment replacement

環境變量(使用ENV語句聲明)也能夠在某些指令中用做要由Dockerfile解釋的變量。還能夠處理轉義,以將相似變量的語法包含在語句中。

環境變量在Dockerfile中用$variable_name${variable_name}表示。它們被等同對待,而且括號語法一般用於解決不帶空格的變量名的問題,例如${foo}_bar

${variable_name}語法還支持如下指定的一些標準bash修飾符:

  • ${variable:-word}表示若是設置了variable,則結果將是該值。若是variable未設置,那麼word將是結果。
  • ${variable:+word}表示若是設置了variable,那麼word將是結果,不然結果是空字符串。

在全部狀況下,word能夠是任何字符串,包括額外的環境變量。

能夠經過在變量以前添加\來轉義:\$foo\${foo},分別轉換爲$foo${foo}

示例(解析的表示顯示在#後面):

FROM busybox
ENV foo /bar
WORKDIR ${foo}   # WORKDIR /bar
ADD . $foo       # ADD . /bar
COPY \$foo /quux # COPY $foo /quux

Dockerfile中的如下指令列表支持環境變量:

  • ADD
  • COPY
  • ENV
  • EXPOSE
  • LABEL
  • USER
  • WORKDIR
  • VOLUME
  • STOPSIGNAL

以及:

  • ONBUILD(當與上面支持的指令之一組合時)

注意:在1.4以前,ONBUILD指令不支持環境變量,即便與上面列出的任何指令相結合。

環境變量替換將在整個命令中對每一個變量使用相同的值。換句話說,在這個例子中:

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc

將致使def值爲hello,再也不bye。然而,ghi的值爲bye,由於它不是設置abcbye的相同命令的一部分。

.dockerignore file

在docker CLI將上下文發送到docker守護程序以前,它會在上下文的根目錄中查找名爲.dockerignore的文件。若是此文件存在,CLI將修改上下文以排除匹配其中模式的文件和目錄。這有助於避免沒必要要地向守護程序發送大型或敏感文件和目錄,並可能使用ADDCOPY將其添加到映像。

CLI將.dockerignore文件解釋爲換行符分隔的模式列表,相似於Unix shell的file globs。爲了匹配的目的,上下文的根被認爲是工做目錄和根目錄。例如,模式/foo/barfoo/bar都排除了PATHfoo子目錄中的名爲bar的文件或目錄,或者位於URL處的git repository的根目錄中。也不排除任何其餘。

若是.dockerignore文件中的一行以第1列中以#開頭,則此行被視爲註釋,並在CLI解釋以前被忽略。

這裏是一個例子.dockerignore文件:

# comment
*/temp*
*/*/temp*
temp?

此文件致使如下構建行爲:

規則 行爲
# comment 忽略
*/temp* 在根的任何直接子目錄中排除其名稱以temp開頭的文件和目錄。 例如,普通文件/somedir/temporary.txt被排除,目錄/somedir/temp也被排除。
*/*/temp* 從根目錄下兩級的任何子目錄中排除以temp開頭的文件和目錄。 例如,排除了/somedir/subdir/temporary.txt。
temp? 排除根目錄中名稱爲temp的單字符擴展名的文件和目錄。 例如,/tempa和/tempb被排除。

匹配是使用Go的filepath.Match規則完成的。 預處理步驟刪除前導和尾隨空格並消除...元素使用Go的filepath.Clean。預處理後爲空的行將被忽略。

除了Go的filepath.Match規則,Docker還支持一個特殊的通配符字符串**,它匹配任何數量的目錄(包括零)。 例如,**/*.go將排除全部目錄中找到的以.go結尾的全部文件,包括構建上下文的根。

行開頭!(感嘆號)可用於排除例外。 如下是使用此機制的.dockerignore文件示例:

*.md
!README.md

除了README.md以外的全部markdown文件都從上下文中排除。

放置!異常規則影響行爲:匹配特定文件的.dockerignore的最後一行肯定它是包括仍是排除。思考下面的例子:

*.md
!README*.md
README-secret.md

除了README-secret.md以外的README文件,上下文中排除全部markdown文件。

如今思考這個例子:

*.md
README-secret.md
!README*.md

包括全部README文件。 中間行沒有效果,由於最後的!README*.mdREADME-secret.md匹配。

您甚至可使用.dockerignore文件來排除Dockerfile.dockerignore文件。這些文件仍然發送到守護程序,由於它須要它們來完成它的工做。可是ADDCOPY命令不會將它們複製到映像。

最後,您可能須要指定要包括在上下文中的文件,而不是要排除的文件。 要實現這一點,指定*做爲第一個模式,後面跟一個或多個!異常模式。

注意:因爲歷史緣由.模式。被忽略。

FROM

FROM <image>
# 或則
FROM <image>:<tag>
# 或則
FROM <image>@<digest>

FROM指令爲後續指令設置Base Image。所以,有效的Dockerfile必須具備FROM做爲其第一條指令。image能夠是任何有效的image - 能夠從Public Repositories pulling an image

  • FROM必須是Dockerfile中的第一個非註釋指令。
  • FROM能夠在單個Dockerfile中屢次出現,以建立多個圖像。只需記下在每一個新的FROM命令以前由提交輸出的最後一個image ID。
  • tagdigest是可選的。若是省略其中任何一個,構建器將默認使用latest。若是構建器與tag值不匹配,則構建器將返回錯誤。

MAINTAINER

MAINTAINER <name>

MAINTAINER指令容許您設置生成的images的做者字段。

RUN

RUN有2種形式:

  • RUN <command>(*shell*形式,命令在shell中運行,Linux上爲/bin/sh -c,Windows上爲cmd /S/C
  • RUN ["executable","param1","param2"]exec 形式)

RUN指令將在當前image之上的新層中執行任何命令,並提交結果。生成的已提交image將用於Dockerfile中的下一步。

分層RUN指令和生成提交符合Docker的核心概念,其中提交很輕量,能夠從image歷史中的任何點建立容器,就像源代碼控制同樣。

exec形式使得能夠避免shell字符串變化,以及使用不包含指定的shell可執行文件的基本image來運行RUN命令。

可使用SHELL命令更改shell表單的默認shell。

在shell形式中,可使用\(反斜槓)將單個RUN指令繼續到下一行。例如,考慮這兩行:RUN /bin/bash -c 'source $HOME/.bashrc ; \ echo $HOME'它們等同於這一行:RUN /bin/bash -c 'source $HOME/.bashrc ; echo $HOME'

注意:要使用不一樣的shell,而不是’/bin/sh’,請使用在所需shell中傳遞的exec形式。例如,RUN [「/bin/bash」,「-c」,「echo hello」]

注意:exec形式做爲JSON數組解析,這意味着您必須在單詞以外使用雙引號(」)而不是單引號(’)。

注意:與shell表單不一樣,exec表單不調用命令shell。這意味着正常的shell處理不會發生。例如,RUN ["echo","$HOME"]不會在$HOME上進行可變替換。若是你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:RUN ["sh","-c","echo $HOME"]。當使用exec形式並直接執行shell時,正如shell形式的狀況,它是作環境變量擴展的shell,而不是docker。

注意:在JSON形式中,有必要轉義反斜槓。這在Windows上特別相關,其中反斜槓是路徑分隔符。由於不是有效的JSON,而且以意外的方式失敗,如下行將被視爲shell形式:RUN ["c:\windows\system32\tasklist.exe"]此示例的正確語法爲:RUN ["c:\\windows\\system32\\tasklist.exe"]

用於RUN指令的高速緩存在下一次構建期間不會自動失效。用於諸如RUN apt-get dist-upgrade之類的指令的高速緩存將在下一次構建期間被重用。能夠經過使用--no-cache標誌來使用於RUN指令的高速緩存無效,例如docker build --no-cache

有關詳細信息,請參閱Dockerfile最佳實踐指南

用於RUN指令的高速緩存能夠經過ADD指令無效。有關詳細信息,請參見下文

Known issues(RUN)

  • Issue 783是關於在使用AUFS文件系統時可能發生的文件權限問題。例如,您可能會在嘗試rm文件時注意到它。對於具備最近aufs版本的系統(即,能夠設置dirperm1安裝選項),docker將嘗試經過使用dirperm1選項安裝image來自動解決問題。有關dirperm1選項的更多詳細信息,請參見aufs手冊頁 若是您的系統不支持dirperm1,則該問題描述了一種解決方法。

CMD

CMD指令三種形式:

  • CMD ["executable","param1","param2"] (exec form, 首選形式)
  • CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
  • CMD command param1 param2 (shell form)

Dockerfile中只能有一個CMD指令。若是您列出多個CMD,則只有最後一個CMD將生效。

CMD的主要目的是爲執行容器提供默認值。這些默認值能夠包括可執行文件,或者它們能夠省略可執行文件,在這種狀況下,您還必須指定ENTRYPOINT指令。

注意:若是使用CMDENTRYPOINT指令提供默認參數,CMDENTRYPOINT指令都應以JSON數組格式指定。

注意:exec形式做爲JSON數組解析,這意味着您必須在單詞以外使用雙引號(」)而不是單引號(’)。

注意:與shell表單不一樣,exec表單不調用命令shell。這意味着正常的shell處理不會發生。例如,CMD ["echo","$HOME"]不會在$HOME上進行可變替換。若是你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:CMD ["sh","-c","echo $HOME"]。當使用exec形式並直接執行shell時,正如shell形式的狀況,它是作環境變量擴展的shell,而不是docker。

當以shell或exec格式使用時,CMD指令設置運行image時要執行的命令。

若是使用CMD的shell形式,那麼<command>將在/bin/sh -c中執行:

FROM ubuntu
CMD echo "This is a test." | wc -

若是你想運行你的<command>沒有shell,那麼你必須將該命令表示爲一個JSON數組,並給出可執行文件的完整路徑。此數組形式是CMD的首選格式。任何其餘參數必須單獨表示爲數組中的字符串:

FROM ubuntu
CMD ["/usr/bin/wc","--help"]

若是你但願你的容器每次運行相同的可執行文件,那麼你應該考慮使用ENTRYPOINT結合CMD。 請參閱ENTRYPOINT

若是用戶指定docker run參數,那麼它們將覆蓋CMD中指定的默認值。

注意:不要將RUNCMD混淆。RUN實際上運行一個命令並提交結果;CMD在構建時不執行任何操做,但指定了image的預期命令。

LABEL

LABEL <key>=<value> <key>=<value> <key>=<value> ...

LABEL指令向image添加元數據。LABEL是鍵值對。要在LABEL值中包含空格,請使用引號和反斜槓,就像在命令行解析中同樣。幾個使用示例:

LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."

image能夠有多個label。要指定多個label,Docker建議在可能的狀況下將標籤合併到單個LABEL指令中。每一個LABEL指令產生一個新層,若是使用許多標籤,可能會致使效率低下的圖像。該示例產生單個圖像層。

LABEL multi.label1="value1" multi.label2="value2" other="value3"

上面的也可寫爲:

LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"

標籤是添加的,包括LABELFROM images中。若是Docker遇到已經存在的label/key,則新值將覆蓋具備相同鍵的任何先前標籤。

要查看image的labels,請使用docker inspect命令。

"Labels": {
    "com.example.vendor": "ACME Incorporated"
    "com.example.label-with-value": "foo",
    "version": "1.0",
    "description": "This text illustrates that label-values can span multiple lines.",
    "multi.label1": "value1",
    "multi.label2": "value2",
    "other": "value3"
},

EXPOSE

EXPOSE <port> [<port>...]

EXPOSE指令通知Docker容器在運行時偵聽指定的網絡端口。EXPOSE不使主機的容器的端口可訪問。爲此,必須使用-p標誌發佈一系列端口,或者使用-P標誌發佈全部暴露的端口。您能夠公開一個端口號,並用另外一個端口號在外部發布。

要在主機系統上設置端口重定向,請參閱使用-P標誌。Docker網絡功能支持建立網絡,無需在網絡中公開端口,有關詳細信息,請參閱此功能的概述)。

ENV

ENV <key> <value>
ENV <key>=<value> ...

ENV指令將環境變量<key>設置爲值<value>。該值將在全部」descendant」 Dockerfile命令的環境中,而且能夠在許多中被替換爲inline

ENV指令有兩種形式。第一種形式,ENV <key> <value>,將單個變量設置爲一個值。第一個空格後面的整個字符串將被視爲<value> - 包括空格和引號等字符。

第二種形式,ENV <key> = <value> ...,容許一次設置多個變量。注意,第二種形式在語法中使用等號(=),而第一種形式不使用。與命令行解析相似,引號和反斜槓可用於在值內包含空格。

例如:

ENV myName="John Doe" myDog=Rex\ The\ Dog \
    myCat=fluffy
# 和
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy

將在最終容器中產生相同的淨結果,但第一種形式是優選的,由於它產生單個高速緩存層。

使用ENV設置的環境變量將在從生成的image運行容器時保留。您可使用docker inspect查看值,並使用docker run --env <key> = <value>更改它們。

注意:環境持久性可能會致使意外的反作用。例如,將ENV DEBIAN_FRONTEND設置爲非交互式可能會使apt-get用戶混淆基於Debian的映像。要爲單個命令設置值,請使用RUN <key> = <value> <command>

ADD

兩種形式:

  • ADD <src>... <dest>
  • ADD ["<src>",... "<dest>"] (對於包含空格的路徑,此形式是必需的)

ADD指令從<src>複製新文件,目錄或遠程文件URL,並將它們添加到容器的文件系統,路徑<dest>

能夠指定多個<src>資源,但若是它們是文件或目錄,那麼它們必須是相對於正在構建的源目錄(構建的context)。

每一個<src>可能包含通配符,匹配將使用Go的filepath.Match規則完成。 例如:

ADD hom* /mydir/        # adds all files starting with "hom"
ADD hom?.txt /mydir/    # ? is replaced with any single character, e.g., "home.txt"

<dest>是絕對路徑或相對於WORKDIR的路徑,源將在目標容器中複製到其中。

ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/

全部新文件和目錄都使用UID和GID爲0建立。

<src>是遠程文件URL的狀況下,目標將具備600的權限。若是正在檢索的遠程文件具備HTTP Last-Modified標頭,則來自該標頭的時間戳將用於設置目的地上的mtime文件。然而,像在ADD期間處理的任何其它文件同樣,mtime將不包括在肯定文件是否已經改變而且高速緩存應該被更新。

注意:若是經過傳遞一個Dockerfile經過STDIN(docker build - <somefile)構建,沒有構建上下文,因此Dockerfile只能包含一個基於URL的ADD指令。您還能夠經過STDIN傳遞壓縮歸檔文件:(docker build - <archive.tar.gz),歸檔根目錄下的Dockerfile和歸檔的其他部分將在構建的上下文中使用。

注意:若是您的URL文件使用身份驗證保護,則您須要使用RUN wgetRUN curl或從容器內使用其餘工具,由於ADD指令不支持身份驗證。

注意:若是<src>的內容已更改,第一個遇到的ADD指令將使來自Dockerfile的全部後續指令的高速緩存無效。這包括使用於RUN指令的高速緩存無效。有關詳細信息,請參閱Dockerfile最佳實踐指南

ADD遵照如下規則:

  • <src>路徑必須在構建的上下文中;你不能ADD ../something /something,由於docker構建的第一步是發送上下文目錄(和子目錄)到docker守護進程。若是<src>是URL而且<dest>不以尾部斜槓結尾,則從URL下載文件並將其複製到<dest>
  • 若是<src>是URL而且<dest>以尾部斜槓結尾,則從URL中推斷文件名,並將文件下載到<dest>/<filename>。例如,ADD http://example.com/foobar /會建立文件/ foobar。網址必須有一個非平凡的路徑,以便在這種狀況下能夠發現一個適當的文件名(http://example.com不會工做)。
  • 若是<src>是目錄,則複製目錄的整個內容,包括文件系統元數據。

注意:目錄自己不被複制,只是其內容。

  • 若是<src>是識別的壓縮格式(identity,gzip,bzip2或xz)的本地tar存檔,則將其解包爲目錄。來自遠程URL的資源不會解壓縮。當目錄被複制或解壓縮時,它具備與tar -x相同的行爲:結果是如下的聯合:
    1. 不管在目的地路徑和
    2. 源樹的內容,衝突以逐個文件爲基礎解析爲「2.」。

注意:文件是否被識別爲識別的壓縮格式,僅基於文件的內容,而不是文件的名稱。例如,若是一個空文件以.tar.gz結尾,則不會被識別爲壓縮文件,而且不會生成任何解壓縮錯誤消息,而是將該文件簡單地複製到目的地。

  • 若是<src>是任何其餘類型的文件,它會與其元數據一塊兒單獨複製。在這種狀況下,若是<dest>以尾部斜槓/結尾,它將被認爲是一個目錄,而且<src>的內容將被寫在<dest>/base(<src>)
  • 若是直接或因爲使用通配符指定了多個<src>資源,則<dest>必須是目錄,而且必須以斜槓/結尾。
  • 若是<dest>不以尾部斜槓結尾,它將被視爲常規文件,<src>的內容將寫在<dest>
  • 若是<dest>不存在,則會與其路徑中的全部缺乏的目錄一塊兒建立。

COPY

兩種形式:

  • COPY <src>... <dest>
  • COPY ["<src>",... "<dest>"] (this form is required for paths containing whitespace)

基本和ADD相似,不過COPY<src>不能爲URL。

ENTRYPOINT

兩種形式:

  • ENTRYPOINT [「executable」, 「param1」, 「param2」] (exec 形式, 首選)
  • ENTRYPOINT command param1 param2 (shell 形式)

ENTRYPOINT容許您配置容器,運行執行的可執行文件。

例如,如下將使用其默認內容啓動nginx,偵聽端口80:

docker run -i -t --rm -p 80:80 nginx

docker run <image>的命令行參數將附跟在 exec 形式的ENTRYPOINT中的全部元素以後,並將覆蓋使用CMD指定的全部元素。這容許將參數傳遞到入口點,即docker run <image> -d將把-d參數傳遞給入口點。您可使用docker run --entrypoint標誌覆蓋ENTRYPOINT指令。

shell 形式防止使用任何CMD或運行命令行參數,可是缺點是您的ENTRYPOINT將做/bin/sh -c的子命令啓動,它不傳遞信號。這意味着可執行文件將不是容器的PID 1,而且不會接收Unix信號,所以您的可執行文件將不會從docker stop <container>接收到SIGTERM

只有Dockerfile中最後一個ENTRYPOINT指令會有效果。

Exec form ENTRYPOINT example

您可使用ENTRYPOINT的*exec*形式設置至關穩定的默認命令和參數,而後使用任一形式的CMD設置更可能更改的其餘默認值。

FROM ubuntu
ENTRYPOINT ["top", "-b"]
CMD ["-c"]

運行容器時,您能夠看到top是惟一的進程:

$ docker run -it --rm --name test  top -H
top - 08:25:00 up  7:27,  0 users,  load average: 0.00, 0.01, 0.05
Threads:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.1 us,  0.1 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem:   2056668 total,  1616832 used,   439836 free,    99352 buffers
KiB Swap:  1441840 total,        0 used,  1441840 free.  1324440 cached Mem

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND
    1 root      20   0   19744   2336   2080 R  0.0  0.1   0:00.04 top

要進一步檢查結果,可使用docker exec

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  2.6  0.1  19752  2352 ?        Ss+  08:24   0:00 top -b -H
root         7  0.0  0.1  15572  2164 ?        R+   08:25   0:00 ps aux

而且你能夠優雅地請求top使用docker stop test關閉。

如下Dockerfile顯示使用ENTRYPOINT在前臺運行Apache(即,做爲PID 1):

FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]

若是須要爲單個可執行文件編寫啓動腳本,可使用execgosu命令確保最終可執行文件接收到Unix信號:

#!/bin/bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

最後,若是須要在關閉時進行一些額外的清理(或與其餘容器通訊),或者協調多個可執行文件,您可能須要確保ENTRYPOINT腳本接收到Unix信號,傳遞它們,而後作一些更多的工做:

#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too

# USE the trap if you need to also do manual cleanup after the service is stopped,
#     or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM

# start service in background here
/usr/sbin/apachectl start

echo "[hit enter key to exit] or run 'docker stop <container>'"
read

# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop

echo "exited $0"

若是你用docker run -it --rm -p 80:80 --name test apache運行image,則可使用·docker exec·或·docker top·檢查容器的進程,而後請求腳本中止Apache:

$ docker exec -it test ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.1  0.0   4448   692 ?        Ss+  00:42   0:00 /bin/sh /run.sh 123 cmd cmd2
root        19  0.0  0.2  71304  4440 ?        Ss   00:42   0:00 /usr/sbin/apache2 -k start
www-data    20  0.2  0.2 360468  6004 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
www-data    21  0.2  0.2 360468  6000 ?        Sl   00:42   0:00 /usr/sbin/apache2 -k start
root        81  0.0  0.1  15572  2140 ?        R+   00:44   0:00 ps aux
$ docker top test
PID                 USER                COMMAND
10035               root                {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054               root                /usr/sbin/apache2 -k start
10055               33                  /usr/sbin/apache2 -k start
10056               33                  /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real    0m 0.27s
user    0m 0.03s
sys 0m 0.03s

注意:您可使用--entrypoint覆蓋ENTRYPOINT設置,但這隻能將二進制設置爲*exec*(不使用sh -c)。

注意:*exec*形式做爲JSON數組解析,這意味着您必須在單詞以外使用雙引號(」)而不是單引號(’)。

注意:與shell形式不一樣,*exec*形式不調用命令shell。這意味着正常的shell處理不會發生。例如,ENTRYPOINT ["echo","$ HOME"]不會在$HOME上進行可變替換。若是你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:ENTRYPOINT ["sh","-c","echo $HOME"]。當使用exec形式並直接執行shell時,正如shell形式的狀況,它是作環境變量擴展的shell,而不是docker。

Shell form ENTRYPOINT example

您能夠爲ENTRYPOINT指定一個純字符串,它將在/bin/sh -c中執行。這中形式將使用shell處理來替換shell環境變量,而且將忽略任何CMDdocker run命令行參數。要確保docker stop將正確地發出任何長時間運行的ENTRYPOINT可執行文件,您須要記住用exec啓動它:

FROM ubuntu
ENTRYPOINT exec top -b

運行此image時,您將看到單個PID 1進程:

$ docker run -it --rm --name test top
Mem: 1704520K used, 352148K free, 0K shrd, 0K buff, 140368121167873K cached
CPU:   5% usr   0% sys   0% nic  94% idle   0% io   0% irq   0% sirq
Load average: 0.08 0.03 0.05 2/98 6
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     R     3164   0%   0% top -b

它獎在docker stop乾淨的退出:

$ /usr/bin/time docker stop test
test
real    0m 0.20s
user    0m 0.02s
sys 0m 0.04s

若是忘記將exec添加到您的ENTRYPOINT的開頭:

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1

而後,您能夠運行它(給它一個名稱爲下一步):

$ docker run -it --name test top --ignored-param2
Mem: 1704184K used, 352484K free, 0K shrd, 0K buff, 140621524238337K cached
CPU:   9% usr   2% sys   0% nic  88% idle   0% io   0% irq   0% sirq
Load average: 0.01 0.02 0.05 2/101 7
  PID  PPID USER     STAT   VSZ %VSZ %CPU COMMAND
    1     0 root     S     3168   0%   0% /bin/sh -c top -b cmd cmd2
    7     1 root     R     3164   0%   0% top -b

您能夠從top的輸出中看到指定的ENTRYPOINT不是PID 1。

若是你而後運行docker中止測試,容器將不會徹底退出 - 中止命令將強制發送SIGKILL超時後:

$ docker exec -it test ps aux
PID   USER     COMMAND
    1 root     /bin/sh -c top -b cmd cmd2
    7 root     top -b
    8 root     ps aux
$ /usr/bin/time docker stop test
test
real    0m 10.19s
user    0m 0.04s
sys 0m 0.03s

Understand how CMD and ENTRYPOINT interact

CMDENTRYPOINT指令定義在運行容器時執行什麼命令。這裏有較少的規則描述他們的合做。

  • Dockerfile應該至少指定一個CMDENTRYPOINT命令。
  • 當使用容器做爲可執行文件時,應該定義ENTRYPOINT
  • CMD應該用做定義ENTRYPOINT命令的默認參數或在容器中執行ad-hoc命令的一種方法。
  • 當運行帶有替代參數的容器時,CMD將被覆蓋。

下表顯示了對不一樣ENTRYPOINT/CMD組合執行的命令:

  no ENTRYPOINT ENTRYPOINT exec_enty p1_entry ENTRYPOINT [「exec_entry」,「p1_entry」]
No CMD error, not allowed /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [「exec_cmd」,「p1_cmd」] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_cmd p1_cmd exec_entry p1_entry exec_cmd p1_cmd
CMD [「p1_cmd」, 「p2_cmd」] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

VOLUME

VOLUME ["/data"]

VOLUME指令建立具備指定名稱的掛載點,並將其標記爲從本機主機或其餘容器保留外部掛載的卷。該值能夠是JSON數組VOLUME ["/var/log/"]或具備多個參數的純字符串,例如VOLUME /var/logVOLUME /var/log /var/db。有關經過Docker客戶端的更多信息/示例和安裝說明,請參閱經過卷文檔共享目錄

docker run命令用存在於基本image中指定位置的任何數據初始化新建立的卷。例如,思考如下Dockerfile片斷:

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol

此Dockerfile docker run的映像,在/myvol上建立一個新的掛載點,並將greeting文件複製到新建立的卷中。

注意:若是任何構建步驟在聲明後更改卷中的數據,那麼這些更改將被丟棄。

注意:該列表解析爲JSON數組,這意味着您必須在單詞以外使用雙引號(」)而不是單引號(’)。

USER

USER daemon

USER指令設置運行image時使用的用戶名或UID,以及Dockerfile中的任何RUN,CMDENTRYPOINT指令。

WORKDIR

WORKDIR /path/to/workdir

WORKDIR指令爲Dockerfile中的任何RUNCMDENTRYPOINTCOPYADD指令設置工做目錄。若是WORKDIR不存在,它將被建立,即便它沒有在任何後續的Dockerfile指令中使用。

它能夠在一個Dockerfile中屢次使用。若是提供了相對路徑,它將相對於先前WORKDIR指令的路徑。 例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

在這個Dockerfile中的最終pwd命令的輸出是/a/b/c

WORKDIR指令能夠解析先前使用ENV設置的環境變量。您只能使用在Dockerfile中顯式設置的環境變量。 例如:

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd

pwd命令在該Dockerfile中輸出的最後結果是/path/$DIRNAME

ARG

ARG <name>[=<default value>]

ARG指令定義一個變量,用戶可使用docker build命令使用--build-arg <varname> = <value>標誌,在構建時將其傳遞給構建器。若是用戶指定了一個未在Dockerfile中定義的構建參數,構建將輸出錯誤。

One or more build-args were not consumed, failing build.

Dockerfile做者能夠經過指定ARG一個或多個變量,經過屢次指定ARG來定義單個變量。例如,一個有效的Dockerfile

FROM busybox
ARG user1
ARG buildno
...

Dockerfile做者能夠可選地指定ARG指令的默認值:

FROM busybox
ARG user1=someuser
ARG buildno=1
...

若是ARG值具備缺省值,而且若是在構建時沒有傳遞值,則構建器使用缺省值。

ARG變量定義從在Dockerfile中定義的行開始生效,而不是從命令行或其餘地方的參數使用。例如,考慮這個Dockerfile:

1 FROM busybox
2 USER ${user:-some_user}
3 ARG user
4 USER $user
...

用戶構建此文件以下:

$ docker build --build-arg user=what_user Dockerfile

第2行的USER將評估爲some_user,由於用戶變量在後續行3上定義。第4行的USER在定義用戶時估計爲what_user,在命令行中傳遞what_user值。在經過ARG指令定義以前,變量的任何使用都將致使空字符串。

警告:不建議使用build-time變量來傳遞諸如github密鑰,用戶憑證等密碼。構建時變量值使用docker history命令對圖像的任何用戶可見。

可使用ARGENV指令來指定RUN指令可用的變量。使用ENV指令定義的環境變量老是覆蓋同名的ARG指令。思考這個Dockerfile帶有ENVARG指令。

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER v1.0.0
4 RUN echo $CONT_IMG_VER

而後,假設此image是使用此命令構建的:

$ docker build --build-arg CONT_IMG_VER=v2.0.1 Dockerfile

在這種狀況下,RUN指令使用v1.0.0而不是用戶傳遞的ARG設置:v2.0.1此行爲相似於shell腳本,其中本地做用域變量覆蓋做爲參數傳遞或從環境繼承的變量,從其定義點。

使用上述示例,但使用不一樣的ENV規範,您能夠在ARGENV指令之間建立更有用的交互:

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
4 RUN echo $CONT_IMG_VER

ARG指令不一樣,ENV值始終保留在image中。考慮一個沒有-build-arg標誌的docker構建:

$ docker build Dockerfile

使用這個Dockerfile示例,CONT_IMG_VER仍然保留在映像中,但它的值將是v1.0.0,由於它是ENV指令在第3行中的默認設置。

此示例中的變量擴展技術容許您從命令行傳遞參數,並經過利用ENV指令將它們持久保存在最終image中。僅對一組有限的Dockerfile指令支持變量擴展

Docker有一組預約義的ARG變量,您能夠在Dockerfile中使用相應的ARG指令。

  • HTTP_PROXY
  • http_proxy
  • HTTPS_PROXY
  • https_proxy
  • FTP_PROXY
  • ftp_proxy
  • NO_PROXY
  • no_proxy

要使用這些,只需在命令行使用標誌傳遞它們:

--build-arg <varname>=<value>

Impact on build caching

ARG變量不會持久化到構建的image中,由於ENV變量是。可是,ARG變量會以相似的方式影響構建緩存。若是一個Dockerfile定義一個ARG變量,它的值不一樣於之前的版本,那麼在它的第一次使用時會出現一個「cache miss」,而不是它的定義。特別地,在ARG指令以後的全部RUN指令都隱式地使用ARG變量(做爲環境變量),所以可能致使高速緩存未命中。

例如,考慮這兩個Dockerfile:

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 RUN echo $CONT_IMG_VER
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 RUN echo hello

若是在命令行上指定--build-arg CONT_IMG_VER = <value>,則在這兩種狀況下,第2行的規範不會致使高速緩存未命中;行3確實致使高速緩存未命中。ARG CONT_IMG_VER致使RUN行被標識爲與運行CONT_IMG_VER = <value> echo hello相同,所以若是<value>更改,咱們將獲得高速緩存未命中。

考慮在同一命令行下的另外一個示例:

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER $CONT_IMG_VER
4 RUN echo $CONT_IMG_VER

在此示例中,高速緩存未命中發生在第3行。因爲變量在ENV中的值引用ARG變量而且該變量經過命令行更改,所以發生了未命中。在此示例中,ENV命令使image包括該值。

若是ENV指令覆蓋同名的ARG指令,就像這個Dockerfile:

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER hello
4 RUN echo $CONT_IMG_VER

第3行不會致使高速緩存未命中,由於CONT_IMG_VER的值是一個常量(hello)。所以,RUN(第4行)上使用的環境變量和值在構建之間不會更改。

ONBUILD

ONBUILD [INSTRUCTION]

ONBUILD指令在image被用做另外一個構建的基礎時,向image添加要在之後執行的*trigger*指令。trigger將在下游構建的上下文中執行,就好像它已經在下游Dockerfile中的1FROM1指令以後當即插入。

任何構建指令均可以註冊爲trigger。

若是您正在構建將用做構建其餘image的基礎的圖像,例如應用程序構建環境或可使用用戶特定配置自定義的後臺駐留程序,這將很是有用。

例如,若是您的image是可重用的Python應用程序構建器,則須要將應用程序源代碼添加到特定目錄中,而且可能須要在此以後調用構建腳本。你不能只是調用ADDRUN如今,由於你尚未訪問應用程序源代碼,它將是不一樣的每一個應用程序構建。您能夠簡單地爲應用程序開發人員提供一個樣板Dockerfile以將其複製粘貼到其應用程序中,但這是低效,容易出錯,而且很難更新,由於它與應用程序特定的代碼混合。

解決方案是使用ONBUILD來註冊提早指令,以便稍後在下一個構建階段運行。

如下是它的工做原理:

  1. 當遇到ONBUILD指令時,構建器會向正在構建的image的元數據添加trigger。該指令不會另外影響當前構建。
  2. 在構建結束時,全部trigger的列表存儲在image清單中的OnBuild鍵下。可使用docker inspect命令檢查它們。
  3. 稍後,可使用FROM指令將image用做新構建的基礎。做爲處理FROM指令的一部分,下游構建器會查找ONBUILD triggers,並按照它們註冊的順序執行它們。若是任何觸發器失敗,則FROM指令停止,這又致使構建失敗。若是全部觸發器都成功,則FROM指令完成而且構建如常繼續。觸發器在執行後從最終image中清除。換句話說,它們不會被「grand-children」構建繼承。 例如,您能夠添加以下:[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]警告:不容許使用ONBUILD ONBUILD連接ONBUILD指令。 > 警告ONBUILD指令可能不會觸發FROMMAINTAINER指令。

STOPSIGNAL

STOPSIGNAL signal

STOPSIGNAL指令設置將發送到容器以退出的系統調用信號。該信號能夠是與內核系統調用表中的位置匹配的有效無符號數,例如9,或者是SIGNAME格式的信號名稱,例如SIGKILL。

HEALTHCHECK

兩種形式:

  • HEALTHCHECK [OPTIONS] CMD command (經過在容器中運行命令來檢查容器運行情況)
  • HEALTHCHECK NONE (禁用從基本映像繼承的任何運行情況檢查)

HEALTHCHECK指令告訴Docker如何測試容器以檢查它是否仍在工做。這能夠檢測到諸如Web服務器被卡在無限循環中而且沒法處理新鏈接的狀況,即便服務器進程仍在運行。

當容器指定了healthcheck時,除了其正常狀態外,它還具備健康狀態。此狀態最初開始。 每當健康檢查經過,它變得健康(不管以前的狀態)。在必定數量的連續故障後,它變得不健康。

在CMD以前能夠出現的選項有:

  • --interval=DURATION (default: 30s)
  • --timeout=DURATION (default: 30s)
  • --retries=N (default: 3)

運行情況檢查將首先在容器啓動後運行interval秒,而後在每次上次檢查完成後再次運行interval秒。

若是檢查的單次運行所花費的時間超過timeout秒數,則該檢查被認爲已失敗。

它須要retries連續的健康檢查的故障,容器被認爲是不健康的。

在Dockerfile中只能有一個HEALTHCHECK指令。若是您列出多個,則只有最後一個HEALTHCHECK將生效。

CMD關鍵字以後的命令能夠是shell命令(例如HEALTHCHECK CMD /bin/check-running)或exec數組(如同其餘Dockerfile命令同樣;詳情參見ENTRYPOINT)。

命令的退出狀態表示容器的運行情況。 可能的值爲:

  • 0: success - the container is healthy and ready for use
  • 1: unhealthy - the container is not working correctly
  • 2: reserved - do not use this exit code

例如,要每五分鐘檢查一次Web服務器可以在三秒鐘內爲網站的主頁提供服務:

HEALTHCHECK --interval=5m --timeout=3s \
  CMD curl -f http://localhost/ || exit 1

爲了幫助調試失敗的探測器,命令在stdout或stderr上寫入的任何輸出文本(UTF-8編碼)將存儲在運行情況狀態,並可使用docker inspect查詢。這樣的輸出應該保持短路(只存儲當前的4096個字節)。

當容器的運行情況發生更改時,將生成具備新狀態的health_status事件。

HEALTHCHECK功能在Docker 1.12中添加。

SHELL

SHELL ["executable", "parameters"]

SHELL指令容許用於命令的shell形式的默認shell被覆蓋。 Linux上的默認shell是["/bin/sh","-c"],在Windows上是["cmd","/S","/C"]SHELL指令必須以JSON格式寫在Dockerfile中。

SHELL指令在Windows上特別有用,其中有兩個經常使用的和徹底不一樣的本機shell:cmdpowershell,以及包括sh的備用Shell。

SHELL指令能夠屢次出現。每一個SHELL指令覆蓋全部先前的SHELL指令,並影響全部後續指令。 例如:

FROM windowsservercore

# Executed as cmd /S /C echo default
RUN echo default

# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default

# Executed as powershell -command Write-Host hello
SHELL ["powershell", "-command"]
RUN Write-Host hello

# Executed as cmd /S /C echo hello
SHELL ["cmd", "/S"", "/C"]
RUN echo hello

如下指令可能受SHELL指令的影響,當它們的shell形式用於Dockerfile:RUNCMDENTRYPOINT

如下示例是Windows上的常見模式,可使用SHELL指令進行簡化:

...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...

docker調用的命令將是:

cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"

這是低效的,有兩個緣由。首先,有一個沒必要要的cmd.exe命令處理器(也稱爲shell)被調用。其次,shell中的每一個RUN指令都須要一個額外的powershell -command

爲了更有效率,能夠採用兩種機制之一。 一種是使用JSON形式的RUN命令,如:

...
RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]
...

雖然JSON形式是明確的,而且不使用沒必要要的cmd.exe,但它須要經過雙引號和轉義更詳細。 備用機制是使用SHELL指令和shell形式,爲Windows用戶提供更天然的語法,特別是與escape 解析指令結合使用時:

# escape=`

FROM windowsservercore
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'

結果是:

PS E:\docker\build\shell> docker build -t shell .
Sending build context to Docker daemon 3.584 kB
Step 1 : FROM windowsservercore
 ---> 5bc36a335344
Step 2 : SHELL powershell -command
 ---> Running in 87d7a64c9751
 ---> 4327358436c1
Removing intermediate container 87d7a64c9751
Step 3 : RUN New-Item -ItemType Directory C:\Example
 ---> Running in 3e6ba16b8df9


    Directory: C:\


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----         6/2/2016   2:59 PM                Example


 ---> 1f1dfdcec085
Removing intermediate container 3e6ba16b8df9
Step 4 : ADD Execute-MyCmdlet.ps1 c:\example\
 ---> 6770b4c17f29
Removing intermediate container b139e34291dc
Step 5 : RUN c:\example\Execute-MyCmdlet -sample 'hello world'
 ---> Running in abdcf50dfd1f
Hello from Execute-MyCmdlet.ps1 - passed hello world
 ---> ba0e25255fda
Removing intermediate container abdcf50dfd1f
Successfully built ba0e25255fda
PS E:\docker\build\shell>

SHELL指令還能夠用於修改外殼操做的方式。例如,在Windows上使用SHELL cmd /S /C /V:ON|OFF,能夠修改延遲的環境變量擴展語義。

SHELL指令也能夠在Linux上使用,若是須要一個替代shell,如zshcshtcsh和其餘。

SHELL功能在Docker 1.12中添加。

Dockerfile examples

下面你能夠看到一些Dockerfile語法的例子。 若是你對更現實的東西感興趣,能夠看看Dockerization的例子。

# Nginx
#
# VERSION               0.0.1

FROM      ubuntu
MAINTAINER Victor Vieux <victor@docker.com>

LABEL Description="This image is used to start the foobar executable" Vendor="ACME Products" Version="1.0"
RUN apt-get update && apt-get install -y inotify-tools nginx apache2 openssh-server
# Firefox over VNC
#
# VERSION               0.3

FROM ubuntu

# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get update && apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'

EXPOSE 5900
CMD    ["x11vnc", "-forever", "-usepw", "-create"]
# Multiple images example
#
# VERSION               0.1

FROM ubuntu
RUN echo foo > bar
# Will output something like ===> 907ad6c2736f

FROM ubuntu
RUN echo moo > oink
# Will output something like ===> 695d7793cbe4

# You᾿ll now have two images, 907ad6c2736f with /bar, and 695d7793cbe4 with
# /oink.
相關文章
相關標籤/搜索