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>拷貝到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遵照如下規則:
當使用本地目錄爲源目錄時,推薦使用 COPY 。
九、ENTRYPOINT
兩種格式:
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指令。
下表列出了在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
裏面包含了構建整個image
的完整命令。Docker經過docker build
執行Dockerfile
中的一系列命令自動構建image
。
Dockerfile
其語法很是簡單,此頁面描述了您能夠在Dockerfile中使用的命令。 閱讀此頁面後,你能夠參閱Dockerfile最佳實踐。
docker build
命令從Dockerfile
和context
構建image。context
是PATH
或URL
處的文件。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。
Dockerfile
的格式以下:
# Comment INSTRUCTION arguments
INSTRUCTION
是不區分大小寫的,不過建議大寫。
Dockerfile中的指令第一個指令必需是
FROM`,指定構建鏡像的Base Image。
Dockerfile中以#
開頭的行都將視爲註釋,除非是[Parser directives]()解析器指令。不支持連續註釋符。
# Comment RUN echo 'we are running some # of cool things'
解析器指令是可選的,而且影響處理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=\ (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>
環境變量(使用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
中的如下指令列表支持環境變量:
以及:
注意
:在1.4以前,ONBUILD
指令不支持環境變量,即便與上面列出的任何指令相結合。
環境變量替換將在整個命令中對每一個變量使用相同的值。換句話說,在這個例子中:
ENV abc=hello ENV abc=bye def=$abc ENV ghi=$abc
將致使def
值爲hello
,再也不bye
。然而,ghi
的值爲bye
,由於它不是設置abc
爲bye
的相同命令的一部分。
在docker CLI將上下文發送到docker守護程序以前,它會在上下文的根目錄中查找名爲.dockerignore
的文件。若是此文件存在,CLI將修改上下文以排除匹配其中模式的文件和目錄。這有助於避免沒必要要地向守護程序發送大型或敏感文件和目錄,並可能使用ADD
或COPY
將其添加到映像。
CLI將.dockerignore
文件解釋爲換行符分隔的模式列表,相似於Unix shell
的file globs。爲了匹配的目的,上下文的根被認爲是工做目錄和根目錄。例如,模式/foo/bar
和foo/bar
都排除了PATH
的foo
子目錄中的名爲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*.md
與README-secret.md
匹配。
您甚至可使用.dockerignore
文件來排除Dockerfile
和.dockerignore
文件。這些文件仍然發送到守護程序,由於它須要它們來完成它的工做。可是ADD
和COPY
命令不會將它們複製到映像。
最後,您可能須要指定要包括在上下文中的文件,而不是要排除的文件。 要實現這一點,指定*
做爲第一個模式,後面跟一個或多個!
異常模式。
注意
:因爲歷史緣由.
模式。被忽略。
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。tag
或digest
是可選的。若是省略其中任何一個,構建器將默認使用latest
。若是構建器與tag
值不匹配,則構建器將返回錯誤。MAINTAINER <name>
MAINTAINER
指令容許您設置生成的images的做者字段。
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)
rm
文件時注意到它。對於具備最近aufs版本的系統(即,能夠設置dirperm1
安裝選項),docker將嘗試經過使用dirperm1
選項安裝image來自動解決問題。有關dirperm1
選項的更多詳細信息,請參見aufs手冊頁 若是您的系統不支持dirperm1
,則該問題描述了一種解決方法。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
指令。
注意
:若是使用CMD
爲ENTRYPOINT
指令提供默認參數,CMD
和ENTRYPOINT
指令都應以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
中指定的默認值。
注意
:不要將RUN
和CMD
混淆。RUN
實際上運行一個命令並提交結果;CMD
在構建時不執行任何操做,但指定了image的預期命令。
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"
標籤是添加的,包括LABEL
在FROM
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 <port> [<port>...]
EXPOSE
指令通知Docker容器在運行時偵聽指定的網絡端口。EXPOSE
不使主機的容器的端口可訪問。爲此,必須使用-p
標誌發佈一系列端口,或者使用-P
標誌發佈全部暴露的端口。您能夠公開一個端口號,並用另外一個端口號在外部發布。
要在主機系統上設置端口重定向,請參閱使用-P標誌。Docker網絡功能支持建立網絡,無需在網絡中公開端口,有關詳細信息,請參閱此功能的概述)。
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 <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 wget
,RUN 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
相同的行爲:結果是如下的聯合:
注意
:文件是否被識別爲識別的壓縮格式,僅基於文件的內容,而不是文件的名稱。例如,若是一個空文件以.tar.gz結尾,則不會被識別爲壓縮文件,而且不會生成任何解壓縮錯誤消息,而是將該文件簡單地複製到目的地。
<src>
是任何其餘類型的文件,它會與其元數據一塊兒單獨複製。在這種狀況下,若是<dest>
以尾部斜槓/
結尾,它將被認爲是一個目錄,而且<src>
的內容將被寫在<dest>/base(<src>)
。<src>
資源,則<dest>
必須是目錄,而且必須以斜槓/
結尾。<dest>
不以尾部斜槓結尾,它將被視爲常規文件,<src>
的內容將寫在<dest>
。<dest>
不存在,則會與其路徑中的全部缺乏的目錄一塊兒建立。兩種形式:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
(this form is required for paths containing whitespace)基本和ADD相似,不過COPY
的<src>
不能爲URL。
兩種形式:
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"]
若是須要爲單個可執行文件編寫啓動腳本,可使用exec
和gosu
命令確保最終可執行文件接收到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環境變量,而且將忽略任何CMD
或docker 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
CMD
和ENTRYPOINT
指令定義在運行容器時執行什麼命令。這裏有較少的規則描述他們的合做。
Dockerfile
應該至少指定一個CMD
或ENTRYPOINT
命令。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 ["/data"]
VOLUME
指令建立具備指定名稱的掛載點,並將其標記爲從本機主機或其餘容器保留外部掛載的卷。該值能夠是JSON數組VOLUME ["/var/log/"]
或具備多個參數的純字符串,例如VOLUME /var/log
或VOLUME /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 daemon
USER
指令設置運行image時使用的用戶名或UID,以及Dockerfile
中的任何RUN,CMD
和ENTRYPOINT
指令。
WORKDIR /path/to/workdir
WORKDIR
指令爲Dockerfile
中的任何RUN
,CMD
,ENTRYPOINT
,COPY
和ADD
指令設置工做目錄。若是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 <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
命令對圖像的任何用戶可見。
可使用ARG
或ENV
指令來指定RUN
指令可用的變量。使用ENV
指令定義的環境變量老是覆蓋同名的ARG
指令。思考這個Dockerfile
帶有ENV
和ARG
指令。
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
規範,您能夠在ARG
和ENV
指令之間建立更有用的交互:
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指令。
要使用這些,只需在命令行使用標誌傳遞它們:
--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 [INSTRUCTION]
ONBUILD
指令在image被用做另外一個構建的基礎時,向image添加要在之後執行的*trigger*指令。trigger將在下游構建的上下文中執行,就好像它已經在下游Dockerfile中的1FROM1指令以後當即插入。
任何構建指令均可以註冊爲trigger。
若是您正在構建將用做構建其餘image的基礎的圖像,例如應用程序構建環境或可使用用戶特定配置自定義的後臺駐留程序,這將很是有用。
例如,若是您的image是可重用的Python應用程序構建器,則須要將應用程序源代碼添加到特定目錄中,而且可能須要在此以後調用構建腳本。你不能只是調用ADD
和RUN
如今,由於你尚未訪問應用程序源代碼,它將是不一樣的每一個應用程序構建。您能夠簡單地爲應用程序開發人員提供一個樣板Dockerfile以將其複製粘貼到其應用程序中,但這是低效,容易出錯,而且很難更新,由於它與應用程序特定的代碼混合。
解決方案是使用ONBUILD
來註冊提早指令,以便稍後在下一個構建階段運行。
如下是它的工做原理:
ONBUILD
指令時,構建器會向正在構建的image的元數據添加trigger。該指令不會另外影響當前構建。docker inspect
命令檢查它們。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
指令可能不會觸發FROM
或MAINTAINER
指令。STOPSIGNAL signal
STOPSIGNAL
指令設置將發送到容器以退出的系統調用信號。該信號能夠是與內核系統調用表中的位置匹配的有效無符號數,例如9,或者是SIGNAME格式的信號名稱,例如SIGKILL。
兩種形式:
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
)。
命令的退出狀態表示容器的運行情況。 可能的值爲:
例如,要每五分鐘檢查一次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 ["executable", "parameters"]
SHELL
指令容許用於命令的shell形式的默認shell被覆蓋。 Linux上的默認shell是["/bin/sh","-c"]
,在Windows上是["cmd","/S","/C"]
。SHELL
指令必須以JSON格式寫在Dockerfile中。
SHELL
指令在Windows上特別有用,其中有兩個經常使用的和徹底不一樣的本機shell:cmd
和powershell
,以及包括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:RUN
,CMD
和ENTRYPOINT
。
如下示例是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,如zsh
,csh
,tcsh
和其餘。
SHELL
功能在Docker 1.12中添加。
下面你能夠看到一些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.