?
This document uses PHP Chinese website manual Release
Docker可以通過閱讀a的指示自動(dòng)構(gòu)建圖像Dockerfile
。Dockerfile
是一個(gè)文本文檔,其中包含用戶可以在命令行上調(diào)用以組裝圖像的所有命令。使用docker build
用戶可以創(chuàng)建一個(gè)自動(dòng)構(gòu)建,連續(xù)執(zhí)行幾條命令行指令。
該頁面描述了您可以在Dockerfile中使用的命令。閱讀本頁后,請(qǐng)參閱Dockerfile
面向提示的指南的最佳做法。
docker build命令從Dockerfile和上下文構(gòu)建一個(gè)映像。 構(gòu)建的上下文是指定位置PATH或URL中的文件集。 PATH是本地文件系統(tǒng)上的一個(gè)目錄。 該URL是一個(gè)Git存儲(chǔ)庫(kù)位置。
上下文是遞歸處理的。因此, PATH
包含任何子目錄,且URL
包含存儲(chǔ)庫(kù)及其子模塊。此示例顯示了一個(gè)使用當(dāng)前目錄作為上下文的構(gòu)建命令:
$ docker build .Sending build context to Docker daemon 6.51 MB...
構(gòu)建由Docker守護(hù)進(jìn)程運(yùn)行,而不是通過CLI運(yùn)行。構(gòu)建過程所做的第一件事是將整個(gè)上下文(遞歸地)發(fā)送到守護(hù)進(jìn)程。在大多數(shù)情況下,最好以空目錄作為上下文開始,并將Dockerfile保存在該目錄中。僅添加構(gòu)建Dockerfile所需的文件。
警告:不要用你的根目錄下,
/
作為PATH
因?yàn)樗鼤?huì)導(dǎo)致生成到您的硬盤驅(qū)動(dòng)器的全部?jī)?nèi)容傳輸?shù)酱a頭工人守護(hù)進(jìn)程。
要在構(gòu)建上下文中使用文件,Dockerfile引用指令中指定的文件,例如COPY指令。 要增加構(gòu)建的性能,請(qǐng)通過將.dockerignore文件添加到上下文目錄來排除文件和目錄。 有關(guān)如何創(chuàng)建.dockerignore文件的信息,請(qǐng)參閱此頁面上的文檔。
傳統(tǒng)上,Dockerfile
被稱為Dockerfile
并位于上下文的根部。您可以使用該-f
標(biāo)志docker build
指向文件系統(tǒng)中任何位置的Dockerfile。
$ docker build -f /path/to/a/Dockerfile .
如果構(gòu)建成功,您可以指定一個(gè)存儲(chǔ)庫(kù)和標(biāo)記來保存新映像:
$ docker build -t shykes/myapp .
要在構(gòu)建之后將圖像標(biāo)記到多個(gè)存儲(chǔ)庫(kù)中,請(qǐng)?jiān)?code>-t運(yùn)行此build
命令時(shí)添加多個(gè)參數(shù):
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
在Docker守護(hù)進(jìn)程運(yùn)行Dockerfile中的指令之前,它會(huì)執(zhí)行Dockerfile的初步驗(yàn)證,并在語法不正確時(shí)返回錯(cuò)誤:
$ docker build -t test/myapp .Sending build context to Docker daemon 2.048 kB Error response from daemon: Unknown instruction: RUNCMD
Docker守護(hù)進(jìn)程會(huì)Dockerfile
逐個(gè)運(yùn)行指令,在必要時(shí)將每條指令的結(jié)果提交給新映像,最終輸出新映像的標(biāo)識(shí)。Docker守護(hù)進(jìn)程將自動(dòng)清理您發(fā)送的上下文。
請(qǐng)注意,每條指令都是獨(dú)立運(yùn)行的,并會(huì)創(chuàng)建一個(gè)新圖像 - 所以RUN cd /tmp
不會(huì)對(duì)下一條指令產(chǎn)生任何影響。
只要有可能,Docker將重新使用中間映像(緩存),以docker build
顯著加速該過程。這由Using cache
控制臺(tái)輸出中的消息指示。(有關(guān)更多信息,請(qǐng)參閱Dockerfile
最佳做法指南中的“構(gòu)建緩存”部分):
$ 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
構(gòu)建緩存僅用于具有本地父鏈的圖像。這意味著這些圖像是由以前的版本創(chuàng)建的,或者是整個(gè)圖像鏈加載的docker load
。如果您希望使用特定映像的構(gòu)建緩存,則可以使用--cache-from
選項(xiàng)指定它。指定的圖像--cache-from
不需要有父鏈,可以從其他注冊(cè)表中提取。
當(dāng)你完成你的構(gòu)建時(shí),你已經(jīng)準(zhǔn)備好考慮將存儲(chǔ)庫(kù)推送到它的注冊(cè)表。
以下是Dockerfile
格式:
# Comment INSTRUCTION arguments
該指令不區(qū)分大小寫。然而,約定是為了更容易將它們與爭(zhēng)論區(qū)分開來。
Docker按順序在Dockerfile中運(yùn)行指令。 Dockerfile必須以FROM指令開始。 FROM指令指定您正在構(gòu)建的基本映像。 FROM只能在一個(gè)或多個(gè)ARG指令之后,這些指令聲明在Dockerfile的FROM行中使用的參數(shù)。
Docker treats 把該行開始與#
一個(gè)評(píng)論,除非該行是一個(gè)合法的解析器指令。#
一行中其他任何地方的標(biāo)記都被視為參數(shù)。這允許像這樣的語句:
# Comment RUN echo 'we are running some # of cool things'
注釋中不支持換行符。
解析器指令是可選的,并影響處理Dockerfile中后續(xù)行的方式。 解析器指令不會(huì)將圖層添加到構(gòu)建中,并且不會(huì)顯示為構(gòu)建步驟。 解析器指令以#directive = value的形式寫入特殊類型的注釋。 單個(gè)指令只能使用一次。
一旦注釋,空行或構(gòu)建器指令已被處理,Docker不再查找解析器指令。相反,它將格式化為分析器指令的任何內(nèi)容視為注釋,并且不會(huì)嘗試驗(yàn)證它是否可能是解析器指令。因此,所有解析器指令都必須位于Dockerfile
最頂端。
解析器指令不區(qū)分大小寫。但是,約定是小寫。約定還包括在任何解析器指令之后的空白行。解析器指令不支持行連續(xù)字符。
由于這些規(guī)則,以下示例都是無效的:
由于行延續(xù)而無效:
# direc \ tive=value
由于出現(xiàn)兩次而無效:
# directive=value1 # directive=value2 FROM ImageName
由于出現(xiàn)在建造者指令之后,作為評(píng)論對(duì)待:
FROM ImageName # directive=value
由于在不是解析器指令的注釋之后出現(xiàn),所以作為注釋處理:
# About my dockerfile # directive=value FROM ImageName
未知指令由于未被識(shí)別而被視為評(píng)論。另外,由于在不是解析器指令的注釋之后出現(xiàn),已知指令被視為注釋。
# unknowndirective=value # knowndirective=value
解析器指令中允許使用非分行空白。因此,以下幾行都是一致對(duì)待的:
#directive=value # directive =value # directive= value # directive = value # dIrEcTiVe=value
以下解析器指令受支持:
escape
# escape=\ (backslash)
或是
# escape=` (backtick)
該escape
指令設(shè)置用于轉(zhuǎn)義字符的字符Dockerfile
。如果未指定,則默認(rèn)轉(zhuǎn)義字符為\
。
轉(zhuǎn)義字符既用于轉(zhuǎn)義一行中的字符,又用于轉(zhuǎn)義換行符。這允許Dockerfile
指令跨越多行。請(qǐng)注意,無論escape
解析器指令是否包含在a中Dockerfile
,轉(zhuǎn)義都不在 RUN
命令中執(zhí)行,除了在行的末尾。
將轉(zhuǎn)義字符設(shè)置`
為特別有用Windows
,其中\
是目錄路徑分隔符。`
與Windows PowerShell一致。
考慮下面的例子,它會(huì)以非顯而易見的方式失敗Windows
。第二\
,在第二行的端部將被解釋為用于換行的逃逸,而不是從第一逸出的目標(biāo)\
。同樣,\
假設(shè)它實(shí)際上是作為一條指令處理的,那么在第三行的末尾會(huì)導(dǎo)致它被視為連續(xù)行。這個(gè)dockerfile的結(jié)果是第二行和第三行被認(rèn)為是一條單獨(dú)的指令:
FROM microsoft/nanoserver COPY testfile.txt c:\\ RUN dir c:\
結(jié)果是:
PS C:\John> docker build -t cmd .Sending build context to Docker daemon 3.072 kB Step 1/2 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/2 : COPY testfile.txt c:\RUN dir c:GetFileAttributesEx c:RUN: The system cannot find the file specified.PS C:\John>
上述的一個(gè)解決方案將是/
用作COPY
指令和目標(biāo)dir
。然而,這種語法充其量是令人困惑的,因?yàn)槁窂讲⒉皇亲匀坏?code>Windows,并且最壞的情況是容易出錯(cuò),因?yàn)椴⒎撬?code>Windows支持的命令都/
作為路徑分隔符。
通過添加轉(zhuǎn)義解析器指令,在Windows上使用自然平臺(tái)語義對(duì)文件路徑使用以下Dockerfile可以成功:
# escape=` FROM microsoft/nanoserver COPY testfile.txt c:\ RUN dir c:\
結(jié)果是:
PS C:\John> docker build -t succeeds --no-cache=true .Sending build context to Docker daemon 3.072 kB Step 1/3 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/3 : COPY testfile.txt c:\ ---> 96655de338de Removing intermediate container 4db9acbb1682 Step 3/3 : RUN dir c:\ ---> Running in a2c157f842f5 Volume in drive C has no label. Volume Serial Number is 7E6D-E0F7 Directory of c:\10/05/2016 05:04 PM 1,894 License.txt10/05/2016 02:22 PM <DIR> Program Files10/05/2016 02:14 PM <DIR> Program Files (x86)10/28/2016 11:18 AM 62 testfile.txt10/28/2016 11:20 AM <DIR> Users10/28/2016 11:20 AM <DIR> Windows 2 File(s) 1,956 bytes 4 Dir(s) 21,259,096,064 bytes free ---> 01c7f3bef04f Removing intermediate container a2c157f842f5 Successfully built 01c7f3bef04f PS C:\John>
環(huán)境變量(用ENV語句聲明)也可以在某些指令中用作由Dockerfile解釋的變量。 轉(zhuǎn)義也被處理,從字面上將類似于變量的語法包含到語句中。
使用$ variable_name或$ {variable_name}在Dockerfile中記錄環(huán)境變量。 它們被等價(jià)處理,括號(hào)語法通常用于解決變量名稱中沒有空格的問題,如$ {foo} _bar。
該${variable_name}
語法還支持一些標(biāo)準(zhǔn)bash
修飾符,如下所示:
$ {variable:-word}表示如果設(shè)置了變量,那么結(jié)果就是該值。 如果變量沒有設(shè)置,則字將是結(jié)果。
$ {variable:+ word}表示如果設(shè)置了變量,那么word將是結(jié)果,否則結(jié)果是空字符串。
在任何情況下,word
都可以是任何字符串,包括其他環(huán)境變量。
通過\
在變量之前添加一個(gè)變量可以進(jìn)行轉(zhuǎn)義:\$foo
或者\${foo}
,例如分別轉(zhuǎn)換為文字$foo
和${foo}
文字。
示例(在之后顯示解析的表示#
):
FROM busybox ENV foo /bar WORKDIR ${foo} # WORKDIR /bar ADD . $foo # ADD . /bar COPY \$foo /quux # COPY $foo /quux
Dockerfile中的以下指令列表支持環(huán)境變量:
ADD
COPY
ENV
EXPOSE
FROM
LABEL
STOPSIGNAL
USER
VOLUME
WORKDIR
以及:
ONBUILD
(當(dāng)與上述支持的指令之一結(jié)合使用時(shí))
注意:在1.4之前,
ONBUILD
說明不支持環(huán)境變量,即使與上面列出的任何指令結(jié)合使用。
整個(gè)指令中的環(huán)境變量替換將對(duì)每個(gè)變量使用相同的值。換句話說,在這個(gè)例子中:
ENV abc=hello ENV abc=bye def=$abc ENV ghi=$abc
將導(dǎo)致def的值為hello,而不是再見。 然而,ghi將具有再見值,因?yàn)樗皇菍bc設(shè)置為再見的同一指令的一部分。
在docker CLI將上下文發(fā)送到docker守護(hù)程序之前,它會(huì)在上下文的根目錄中查找名為.dockerignore的文件。 如果此文件存在,CLI會(huì)修改上下文以排除與其中的模式匹配的文件和目錄。 這有助于避免不必要地將大型或敏感文件和目錄發(fā)送到守護(hù)程序,并可能使用ADD或COPY將它們添加到圖像。
CLI將.dockerignore
文件解釋為與Unix shell文件大小相似的以換行符分隔的模式列表。為了匹配的目的,上下文的根被認(rèn)為是工作目錄和根目錄。例如,這些模式/foo/bar
和foo/bar
兩者都不包含位于位于的git存儲(chǔ)庫(kù)bar
的foo
子目錄PATH
或根目錄中指定的文件或目錄URL
。兩者都沒有排除其他任何東西。
如果.dockerignore
文件中的一行以第一#
列開頭,則此行被視為注釋,并在被CLI解釋之前被忽略。
這是一個(gè)示例.dockerignore
文件:
# comment*/temp**/*/temp* temp?
該文件導(dǎo)致以下構(gòu)建行為:
規(guī)則 | 行為 |
---|---|
# comment | 忽略。 |
*/temp* | 排除在根目錄的任何直接子目錄中名稱以temp開頭的文件和目錄。例如,排除純文件/somedir/temporary.txt,就像目錄/ somedir / temp一樣。 |
*/*/temp* | 從根目錄下兩個(gè)級(jí)別的任何子目錄中排除以temp開頭的文件和目錄。例如,排除/somedir/subdir/temporary.txt。 |
temp? | 排除名稱為temp的一個(gè)字符擴(kuò)展名的根目錄中的文件和目錄。例如,/ tempa和/ tempb被排除在外。 |
匹配是使用Go的filepath.Match規(guī)則完成的。 預(yù)處理步驟刪除前導(dǎo)和尾隨空白并消除。 和..使用Go的filepath.Clean。 預(yù)處理后空白的行將被忽略。
除了Go的filepath.Match規(guī)則,Docker還支持**
匹配任意數(shù)量目錄(包括零)的特殊通配符字符串。例如,**/*.go
將排除.go
以所有目錄中包含的文件結(jié)尾的所有文件,包括構(gòu)建上下文的根目錄。
以!
(感嘆號(hào))開頭的行可用于排除例外情況。以下是.dockerignore
使用此機(jī)制的示例文件:
*.md !README.md
除 README.md
上下文外,所有減價(jià)文件均被排除在外。
!
例外規(guī)則的放置會(huì)影響行為:.dockerignore
匹配特定文件的最后一行確定是否包含或排除??紤]下面的例子:
*.md !README*.md README-secret.md
除README-secret.md以外的README文件除上下文外不包含任何降價(jià)文件。
現(xiàn)在考慮這個(gè)例子:
*.md README-secret.md !README*.md
所有的README文件都包含在內(nèi)。 中間行不起作用,因?yàn)?!README * .md與README-secret.md匹配并且最后一個(gè)。
您甚至可以使用.dockerignore文件來排除Dockerfile和.dockerignore文件。 這些文件仍然被發(fā)送到守護(hù)進(jìn)程,因?yàn)樗枰鼈儊硗瓿伤墓ぷ鳌?但ADD和COPY指令不會(huì)將它們復(fù)制到圖像上。
最后,您可能需要指定要在上下文中包含哪些文件,而不是要排除的文件。要實(shí)現(xiàn)這一點(diǎn),請(qǐng)指定*
第一個(gè)模式,然后指定一個(gè)或多個(gè)!
異常模式。
注意:由于歷史原因,該模式.
被忽略。
FROM <image> [AS <name>]
或者
FROM <image>[:<tag>] [AS <name>]
或者
FROM <image>[@<digest>] [AS <name>]
該FROM
指令初始化一個(gè)新的編譯階段并為后續(xù)指令設(shè)置基本映像。因此,有效的Dockerfile
必須以FROM
指令開始。圖像可以是任何有效的圖像 - 通過從公共存儲(chǔ)庫(kù)中拉出圖像開始特別容易。
ARG是Dockerfile中可能位于FROM之前的唯一指令。 請(qǐng)參閱了解ARG和FROM的交互方式。
FROM可以在單個(gè)Dockerfile中多次出現(xiàn)以創(chuàng)建多個(gè)圖像或?qū)⒁粋€(gè)構(gòu)建階段用作另一個(gè)構(gòu)建階段的依賴關(guān)系。 只需在每個(gè)新的FROM指令之前記錄提交輸出的最后一個(gè)映像ID即可。 每條FROM指令清除以前指令創(chuàng)建的任何狀態(tài)。
通過將AS名稱添加到FROM指令,可以給新的生成階段賦予一個(gè)名稱。 該名稱可用于后續(xù)的FROM和COPY --from = <name | index>指令以引用此階段中構(gòu)建的映像。
標(biāo)簽或摘要值是可選的。 如果您忽略其中之一,則默認(rèn)情況下,構(gòu)建器會(huì)采用最新的標(biāo)記。 如果無法找到標(biāo)記值,構(gòu)建器將返回錯(cuò)誤。
FROM
說明支持由ARG
第一個(gè)之前發(fā)生的任何指令聲明的變量FROM
。
ARG CODE_VERSION=latest FROM base:${CODE_VERSION}CMD /code/run-app FROM extras:${CODE_VERSION}CMD /code/run-extras
在FROM之前聲明的ARG在構(gòu)建階段之外,所以它不能在FROM之后的任何指令中使用。 要使用在第一個(gè)FROM之前聲明的ARG的默認(rèn)值,請(qǐng)?jiān)跇?gòu)建階段內(nèi)使用沒有值的ARG指令:
ARG VERSION=latest FROM busybox:$VERSION ARG VERSION RUN echo $VERSION > image_version
RUN有兩種形式:
RUN <command>(shell形式,該命令在shell中運(yùn)行,默認(rèn)情況下是Linux上的/ bin / sh -c或Windows上的cmd / S / C)
RUN [“executable”,“param1”,“param2”](exec形式)
該RUN
指令將在當(dāng)前圖像頂部的新圖層中執(zhí)行任何命令并提交結(jié)果。由此產(chǎn)生的提交圖像將用于下一步Dockerfile
。
分層RUN
指令和生成提交符合Docker的核心概念,其中提交很便宜,容器可以從圖像歷史中的任意點(diǎn)創(chuàng)建,就像源代碼控制一樣。
在EXEC形式使得能夠避免殼串改寫(munging),且RUN
使用不包含指定殼可執(zhí)行基本圖像命令。
shell表單的默認(rèn)shell 可以使用該SHELL
命令進(jìn)行更改。
在shell 形式中,您可以使用\
(反斜杠)將單個(gè)RUN指令繼續(xù)到下一行。例如,考慮這兩行:
RUN /bin/bash -c 'source $HOME/.bashrc; \ echo $HOME'
它們一起等同于這一行:
RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'
注:要使用不同于'/ bin / sh' 的shell ,請(qǐng)使用傳遞給所需shell 的exec表單。例如,
RUN ["/bin/bash", "-c", "echo hello"]
注意:exec表單被解析為JSON數(shù)組,這意味著您必須在單詞(而非單引號(hào)('))周圍使用雙引號(hào)(“)。注意:與shell形式不同,exec形式不會(huì)調(diào)用命令shell。這意味著正常的shell處理不會(huì)發(fā)生。例如,RUN [ "echo", "$HOME" ]
不會(huì)對(duì)變量進(jìn)行替換$HOME
。如果您想要進(jìn)行shell處理,請(qǐng)使用shell窗體或直接執(zhí)行shell,例如:RUN [ "sh", "-c", "echo $HOME" ]
。當(dāng)使用exec表單并直接執(zhí)行一個(gè)shell時(shí)(如shell格式的情況),它是在執(zhí)行環(huán)境變量擴(kuò)展的shell,而不是docker。 注意:在JSON形式中,必須避免反斜杠。這在反斜杠是路徑分隔符的Windows上尤其重要。由于不是有效的JSON,以下行將被視為shell形式,并以意外的方式失?。?code>RUN ["c:\windows\system32\tasklist.exe"]此示例的正確語法為:RUN ["c:\\windows\\system32\\tasklist.exe"]
RUN指令緩存在下一次構(gòu)建期間不會(huì)自動(dòng)失效。 像RUN運(yùn)行apt-get dist-upgrade -y這樣的指令的緩存將在下一次構(gòu)建時(shí)重用。 RUN指令緩存可以通過使用--no-cache標(biāo)志失效,例如docker build --no-cache。
有關(guān)Dockerfile
更多信息,請(qǐng)參閱最佳實(shí)踐指南。
說明的高速緩存RUN
可能會(huì)因ADD
指令而失效。詳情請(qǐng)參閱下文。
問題783是關(guān)于使用AUFS文件系統(tǒng)時(shí)可能發(fā)生的文件權(quán)限問題。 例如,您可能會(huì)在嘗試制作文件時(shí)注意到它。對(duì)于具有最新aufs版本的系統(tǒng)(即可以設(shè)置dirperm1安裝選項(xiàng)),docker將嘗試通過使用dirperm1選項(xiàng)安裝圖層來自動(dòng)修復(fù)問題。 有關(guān)dirperm1選項(xiàng)的更多詳細(xì)信息,請(qǐng)參閱aufs手冊(cè)頁。如果您的系統(tǒng)不支持dirperm1,則說明問題是解決方法。
該CMD
指令有三種形式:
CMD ["executable","param1","param2"]
(執(zhí)行形式,這是首選形式)
CMD ["param1","param2"]
(作為進(jìn)入點(diǎn)的默認(rèn)參數(shù))
CMD command param1 param2
(殼形式)
只能有一條CMD
指令Dockerfile
。如果列出多個(gè),CMD
則只有最后一個(gè)CMD
會(huì)生效。
CMD的主要目的是為執(zhí)行容器提供默認(rèn)值。 這些默認(rèn)值可以包含可執(zhí)行文件,或者可以省略可執(zhí)行文件,在這種情況下,您還必須指定ENTRYPOINT指令。
注:如果
CMD
用于為ENTRYPOINT
指令提供缺省參數(shù),則應(yīng)該使用JSON數(shù)組格式指定CMD
和ENTRYPOINT
指令。注意:exec表單被解析為JSON數(shù)組,這意味著您必須在單詞(而非單引號(hào)('))周圍使用雙引號(hào)(“)。注意:與shell形式不同,exec形式不會(huì)調(diào)用命令shell。這意味著正常的shell處理不會(huì)發(fā)生。例如,CMD [ "echo", "$HOME" ]
不會(huì)對(duì)變量進(jìn)行替換$HOME
。如果您想要進(jìn)行shell處理,請(qǐng)使用shell窗體或直接執(zhí)行shell,例如:CMD [ "sh", "-c", "echo $HOME" ]
。當(dāng)使用exec表單并直接執(zhí)行一個(gè)shell時(shí)(如shell格式的情況),它是在執(zhí)行環(huán)境變量擴(kuò)展的shell,而不是docker。
當(dāng)以shell或exec格式使用時(shí),CMD
指令設(shè)置運(yùn)行映像時(shí)要執(zhí)行的命令。
如果你使用的是shell的形式CMD
,那么<command>
將執(zhí)行在/bin/sh -c
:
FROM ubuntu CMD echo "This is a test." | wc -
如果您想在沒有shell的情況下運(yùn)行<command>,那么您必須將該命令表示為JSON數(shù)組并給出可執(zhí)行文件的完整路徑。 這種數(shù)組形式是CMD **的首選格式。**任何附加參數(shù)都必須在數(shù)組中單獨(dú)表示為字符串:
FROM ubuntu CMD ["/usr/bin/wc","--help"]
如果您希望您的容器每次都運(yùn)行相同的可執(zhí)行文件,那么您應(yīng)該考慮ENTRYPOINT
與其結(jié)合使用CMD
。見入口點(diǎn)。
如果用戶指定碼頭運(yùn)行的參數(shù),那么它們將覆蓋CMD中指定的默認(rèn)值。
注意:不要將RUN與CMD混淆。 RUN實(shí)際上運(yùn)行一個(gè)命令并提交結(jié)果; CMD在構(gòu)建時(shí)不執(zhí)行任何操作,但是指定了圖像的預(yù)期命令。
LABEL <key>=<value> <key>=<value> <key>=<value> ...
LABEL指令為圖像添加元數(shù)據(jù)。 LABEL是一個(gè)鍵值對(duì)。 要在LABEL值中包含空格,請(qǐng)像在命令行解析中一樣使用引號(hào)和反斜杠。 幾個(gè)用法示例:
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."
一張圖片可以有多個(gè)標(biāo)簽。 要指定多個(gè)標(biāo)簽,Docker建議盡可能將標(biāo)簽結(jié)合到單個(gè)LABEL指令中。 每個(gè)LABEL指令都會(huì)產(chǎn)生一個(gè)新圖層,如果您使用多個(gè)標(biāo)簽,則會(huì)導(dǎo)致圖像效率低下。 這個(gè)例子導(dǎo)致一個(gè)圖像層。
LABEL multi.label1="value1" multi.label2="value2" other="value3"
以上內(nèi)容也可以寫成:
LABEL multi.label1="value1" \ multi.label2="value2" \ other="value3"
標(biāo)簽是添加的,包括圖像中的LABEL
s FROM
。如果Docker遇到已存在的標(biāo)簽/鍵,則新值將覆蓋任何以前具有相同鍵的標(biāo)簽。
要查看圖像的標(biāo)簽,請(qǐng)使用該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"},
MAINTAINER <name>
MAINTAINER指令設(shè)置生成圖像的Author字段。 LABEL指令是一個(gè)非常靈活的版本,您應(yīng)該使用它,因?yàn)樗梢栽O(shè)置您需要的任何元數(shù)據(jù),并且可以很容易地查看,例如使用docker檢查。 要設(shè)置與MAINTAINER字段對(duì)應(yīng)的標(biāo)簽,您可以使用:
LABEL maintainer="SvenDowideit@home.org.au"
這將從docker inspect
其他標(biāo)簽中可見。
EXPOSE <port> [<port>...]
EXPOSE指令通知Docker,該容器在運(yùn)行時(shí)偵聽指定的網(wǎng)絡(luò)端口。 EXPOSE不會(huì)使主機(jī)可以訪問容器的端口。 要做到這一點(diǎn),您必須使用-p標(biāo)志來發(fā)布一系列端口或使用-P標(biāo)志來發(fā)布所有暴露的端口。 您可以公開一個(gè)端口號(hào)并在另一個(gè)號(hào)碼外部發(fā)布它。
要在主機(jī)系統(tǒng)上設(shè)置端口重定向,請(qǐng)參閱使用-P標(biāo)志。Docker網(wǎng)絡(luò)功能支持創(chuàng)建網(wǎng)絡(luò),而無需公開網(wǎng)絡(luò)中的端口,有關(guān)詳細(xì)信息,請(qǐng)參閱此功能的概述)。
ENV <key> <value>ENV <key>=<value> ...
ENV指令將環(huán)境變量<key>設(shè)置為值<value>。 該值將處于所有“后代”Dockerfile命令的環(huán)境中,并且可以在許多內(nèi)聯(lián)中被替換。
ENV指令有兩種形式。 第一種形式ENV <key> <value>將把單個(gè)變量設(shè)置為一個(gè)值。 第一個(gè)空格之后的整個(gè)字符串將被視為<value> - 包括諸如空格和引號(hào)之類的字符。
第二種形式ENV <key> = <value> ...允許一次設(shè)置多個(gè)變量。 請(qǐng)注意,第二種形式在語法中使用等號(hào)(=),而第一種形式不使用。 與命令行解析一樣,引號(hào)和反斜杠可用于包含值中的空格。
例如:
ENV myName="John Doe" myDog=Rex\ The\ Dog \ myCat=fluffy
且如下:
ENV myName John Doe ENV myDog Rex The Dog ENV myCat fluffy
將在最終圖像中產(chǎn)生相同的凈結(jié)果,但首選形式是首選,因?yàn)樗鼤?huì)生成單個(gè)緩存層。
使用ENV設(shè)置的環(huán)境變量將在從結(jié)果圖像運(yùn)行容器時(shí)保留。 您可以使用docker inspect查看這些值,并使用docker run --env <key> = <value>更改它們。
注意:環(huán)境持久性可能會(huì)導(dǎo)致意想不到的副作用。例如,設(shè)置
ENV DEBIAN_FRONTEND noninteractive
可能會(huì)將apt-get用戶混淆在基于Debian的映像上。要為單個(gè)命令設(shè)置值,請(qǐng)使用RUN <key>=<value> <command>
。
ADD有兩種形式:
ADD <src>... <dest>
ADD ["<src>",... "<dest>"]
(此表單對(duì)于包含空格的路徑是必需的)
ADD指令從<src>中復(fù)制新文件,目錄或遠(yuǎn)程文件URL,并將它們添加到路徑<dest>中圖像的文件系統(tǒng)中。
<src>
可以指定多個(gè)資源,但如果它們是文件或目錄,則它們必須與正在構(gòu)建的源目錄(構(gòu)建的上下文)相關(guān)。
每個(gè)<src>
可能包含通配符,匹配將使用Go的filepath.Match規(guī)則完成。例如:
ADD hom* /mydir/ # adds all files starting with "hom"ADD hom?.txt /mydir/ # ? is replaced with any single character, e.g., "home.txt"
這<dest>
是一個(gè)絕對(duì)路徑或相對(duì)路徑,WORKDIR
源將在目標(biāo)容器中復(fù)制到該路徑中。
ADD test relativeDir/ # adds "test" to `WORKDIR`/relativeDir/ADD test /absoluteDir/ # adds "test" to /absoluteDir/
添加包含特殊字符(例如[
和]
)的文件或目錄時(shí),您需要按照Golang規(guī)則轉(zhuǎn)義這些路徑,以防止它們被視為匹配模式。例如,要添加一個(gè)名為的文件arr[0].txt
,請(qǐng)使用以下內(nèi)容;
ADD arr[[]0].txt /mydir/ # copy a file named "arr[0].txt" to /mydir/
所有新文件和目錄都是使用UID和GID創(chuàng)建的。
在<src>是遠(yuǎn)程文件URL的情況下,目標(biāo)將具有600的權(quán)限。如果正在檢索的遠(yuǎn)程文件具有HTTP Last-Modified標(biāo)頭,則將使用來自該標(biāo)頭的時(shí)間戳來設(shè)置目的地上的mtime 文件。 但是,與在ADD期間處理的任何其他文件一樣,mtime不會(huì)包含在文件是否已更改以及緩存應(yīng)該更新的確定中。
注意:如果通過STDIN(docker build - <somefile)傳遞Dockerfile來構(gòu)建,則不存在構(gòu)建上下文,因此Dockerfile只能包含基于URL的ADD指令。 您還可以通過STDIN傳遞一個(gè)壓縮歸檔文件:(docker build - <archive.tar.gz),歸檔文件根目錄下的Dockerfile以及歸檔文件的其余部分將用作構(gòu)建的上下文。 注意:如果您的URL文件使用身份驗(yàn)證進(jìn)行保護(hù),則需要使用RUN wget,RUN curl或使用容器內(nèi)的其他工具,因?yàn)锳DD指令不支持身份驗(yàn)證。 注意:如果<src>的內(nèi)容已更改,則第一次遇到的ADD指令將使Dockerfile中所有后續(xù)指令的緩存無效。 這包括使RUN指令的緩存無效。 有關(guān)更多信息,請(qǐng)參閱Dockerfile最佳實(shí)踐指南。
ADD
遵守以下規(guī)則:
<src>路徑必須位于構(gòu)建的上下文中; 你不能添加../something / something,因?yàn)閐ocker build的第一步是將上下文目錄(和子目錄)發(fā)送到docker守護(hù)進(jìn)程。
如果<src>是一個(gè)URL并且<dest>不以結(jié)尾的斜杠結(jié)尾,那么文件將從URL下載并復(fù)制到<dest>。
如果<src>是一個(gè)URL,并且<dest>以尾部的斜線結(jié)尾,則從URL中推斷出該文件名,并將該文件下載到<dest> / <filename>。 例如,添加http://example.com/foobar /會(huì)創(chuàng)建文件/ foobar。 該URL必須有一個(gè)不平凡的路徑,以便在這種情況下可以找到適當(dāng)?shù)奈募╤ttp://example.com將不起作用)。
如果<src>是一個(gè)目錄,則復(fù)制該目錄的全部?jī)?nèi)容,包括文件系統(tǒng)元數(shù)據(jù)。
注意:目錄本身不被復(fù)制,只是它的內(nèi)容。
如果<src>
是以可識(shí)別的壓縮格式(身份,gzip,bzip2或xz)的本地 tar歸檔文件,則將其解壓縮為目錄。來自遠(yuǎn)程 URL的資源不被解壓縮。當(dāng)一個(gè)目錄被復(fù)制或解壓縮時(shí),它的行為tar -x
與結(jié)果相同,結(jié)果是:
1. Whatever existed at the destination path and2. The contents of the source tree, with conflicts resolved in favor of “2.” on a file-by-file basis.
注意:文件是否被識(shí)別為可識(shí)別的壓縮格式完全是基于文件的內(nèi)容而不是文件的名稱。例如,如果一個(gè)空文件恰好結(jié)束,.tar.gz
這將不會(huì)被識(shí)別為一個(gè)壓縮文件,并且不會(huì)生成任何類型的解壓縮錯(cuò)誤消息,而是將該文件簡(jiǎn)單地復(fù)制到目標(biāo)。
如果<src>是任何其他類型的文件,則將其與其元數(shù)據(jù)一起單獨(dú)復(fù)制。 在這種情況下,如果<dest>以結(jié)尾斜杠/結(jié)尾,則它將被視為一個(gè)目錄,<src>的內(nèi)容將寫入<dest> / base(<src>)。
如果指定了多個(gè)<src>資源(直接或由于使用通配符),則<dest>必須是目錄,并且必須以斜杠/結(jié)尾。
如果<dest>不以結(jié)尾的斜杠結(jié)尾,則它將被視為常規(guī)文件,<src>的內(nèi)容將寫入<dest>。
如果<dest>不存在,則會(huì)在其路徑中創(chuàng)建所有缺少的目錄。
COPY有兩種形式:
COPY <src>... <dest>
COPY ["<src>",... "<dest>"]
(此表單對(duì)于包含空格的路徑是必需的)
該COPY
指令復(fù)制新文件或目錄<src>
并將其添加到路徑中容器的文件系統(tǒng)<dest>
。
<src>
可以指定多個(gè)資源,但它們必須相對(duì)于正在構(gòu)建的源目錄(構(gòu)建的上下文)。
每個(gè)<src>
可能包含通配符,匹配將使用Go的filepath.Match規(guī)則完成。例如:
COPY hom* /mydir/ # adds all files starting with "hom"COPY hom?.txt /mydir/ # ? is replaced with any single character, e.g., "home.txt"
這<dest>
是一個(gè)絕對(duì)路徑或相對(duì)路徑,WORKDIR
源將在目標(biāo)容器中復(fù)制到該路徑中。
COPY test relativeDir/ # adds "test" to `WORKDIR`/relativeDir/COPY test /absoluteDir/ # adds "test" to /absoluteDir/
在復(fù)制包含特殊字符(如[
和]
)的文件或目錄時(shí),您需要按照Golang規(guī)則轉(zhuǎn)義這些路徑,以防止它們被視為匹配模式。例如,要復(fù)制一個(gè)名為arr[0].txt
的文件,請(qǐng)使用以下內(nèi)容;
COPY arr[[]0].txt /mydir/ # copy a file named "arr[0].txt" to /mydir/
所有新文件和目錄都是使用UID和GID創(chuàng)建的。
注意:如果使用STDIN(
docker build - < somefile
)構(gòu)建,則沒有構(gòu)建上下文,因此COPY
無法使用。
可選地,COPY接受一個(gè)flag --from = <name | index>,它可以用來將源位置設(shè)置為以前的構(gòu)建階段(使用FROM .. AS <name>創(chuàng)建),而不是由 用戶。 該標(biāo)志還接受為以FROM指令開始的所有以前的構(gòu)建階段分配的數(shù)字索引。 如果無法找到具有指定名稱的構(gòu)建階段,則嘗試使用具有相同名稱的圖像。
COPY
遵守以下規(guī)則:
<src>路徑必須位于構(gòu)建的上下文中; 你不能COPY ../something / something,因?yàn)閐ocker build的第一步是將上下文目錄(和子目錄)發(fā)送到docker守護(hù)進(jìn)程。
如果<src>是一個(gè)目錄,則復(fù)制該目錄的全部?jī)?nèi)容,包括文件系統(tǒng)元數(shù)據(jù)。
注意:目錄本身不被復(fù)制,只是它的內(nèi)容。
如果<src>是任何其他類型的文件,則將其與其元數(shù)據(jù)一起單獨(dú)復(fù)制。 在這種情況下,如果<dest>以結(jié)尾斜杠/結(jié)尾,則它將被視為一個(gè)目錄,<src>的內(nèi)容將寫入<dest> / base(<src>)。
如果指定了多個(gè)<src>資源(直接或由于使用通配符),則<dest>必須是目錄,并且必須以斜杠/結(jié)尾。
如果<dest>不以結(jié)尾的斜杠結(jié)尾,則它將被視為常規(guī)文件,<src>的內(nèi)容將寫入<dest>。
如果<dest>不存在,則會(huì)在其路徑中創(chuàng)建所有缺少的目錄。
ENTRYPOINT有兩種形式:
ENTRYPOINT ["executable", "param1", "param2"]
(exec form, preferred)
ENTRYPOINT command param1 param2
(shell form)
一個(gè)ENTRYPOINT
允許您配置將要運(yùn)行一個(gè)可執(zhí)行的容器。
例如,以下內(nèi)容將啟動(dòng)nginx及其默認(rèn)內(nèi)容,并在端口80上偵聽:
docker run -i -t --rm -p 80:80 nginx
docker run <image>的命令行參數(shù)將被添加到exec表單ENTRYPOINT中的所有元素之后,并且將覆蓋使用CMD指定的所有元素。 這允許將參數(shù)傳遞給入口點(diǎn),即docker run <image> -d將-d參數(shù)傳遞給入口點(diǎn)。 您可以使用docker run --entrypoint標(biāo)志覆蓋ENTRYPOINT指令。
shell形式阻止使用任何CMD或運(yùn)行命令行參數(shù),但具有缺點(diǎn),即您的ENTRYPOINT將作為/ bin / sh -c的子命令啟動(dòng),該命令不傳遞信號(hào)。 這意味著可執(zhí)行文件不會(huì)是容器的PID 1 - 并且不會(huì)接收Unix信號(hào) - 所以您的可執(zhí)行文件將不會(huì)從docker stop <container>收到SIGTERM。
只有最后一條ENTRYPOINT
指令Dockerfile
才會(huì)起作用。
您可以使用ENTRYPOINT的exec形式來設(shè)置相當(dāng)穩(wěn)定的默認(rèn)命令和參數(shù),然后使用CMD的任何一種形式來設(shè)置更可能更改的其他默認(rèn)值。
FROM ubuntu ENTRYPOINT ["top", "-b"]CMD ["-c"]
當(dāng)你運(yùn)行容器時(shí),你可以看到這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.05Threads: 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
要進(jìn)一步檢查結(jié)果,您可以使用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
你可以優(yōu)雅地請(qǐng)求top
關(guān)閉使用docker stop test
。
以下Dockerfile
顯示使用ENTRYPOINT
前臺(tái)運(yùn)行Apache(即as PID 1
):
FROM debian:stable RUN apt-get update && apt-get install -y --force-yes apache2 EXPOSE 80 443VOLUME ["/var/www", "/var/log/apache2", "/etc/apache2"]ENTRYPOINT ["/usr/sbin/apache2ctl", "-D", "FOREGROUND"]
如果您需要為單個(gè)可執(zhí)行文件編寫啟動(dòng)腳本,則可以通過使用exec
和gosu
命令確保最終的可執(zhí)行文件接收到Unix信號(hào):
#!/usr/bin/env bashset -eif [ "$1" = 'postgres' ]; then chown -R postgres "$PGDATA" if [ -z "$(ls -A "$PGDATA")" ]; then gosu postgres initdb fi exec gosu postgres "$@"fi exec "$@"
最后,如果您需要在關(guān)閉時(shí)進(jìn)行一些額外的清理(或與其他容器進(jìn)行通信),或者協(xié)調(diào)多個(gè)可執(zhí)行文件,則可能需要確保ENTRYPOINT
腳本接收到Unix信號(hào),并將其傳遞,然后執(zhí)行一些更多的工作:
#!/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運(yùn)行此鏡像--name test apache,則可以使用docker exec或docker top檢查容器的進(jìn)程,然后讓腳本停止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 COMMAND10035 root {run.sh} /bin/sh /run.sh 123 cmd cmd210054 root /usr/sbin/apache2 -k start10055 33 /usr/sbin/apache2 -k start10056 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設(shè)置,但是這只能將二進(jìn)制設(shè)置為exec(不會(huì)使用sh -c)。 注意:exec表單被解析為JSON數(shù)組,這意味著您必須在單詞(而非單引號(hào)('))周圍使用雙引號(hào)(“)。 注意:與shell形式不同,exec形式不會(huì)調(diào)用命令shell。 這意味著正常的shell處理不會(huì)發(fā)生。 例如,ENTRYPOINT [“echo”,“$ HOME”]不會(huì)在$ HOME上進(jìn)行變量替換。 如果您想要進(jìn)行shell處理,那么可以使用shell窗體或直接執(zhí)行shell,例如:ENTRYPOINT [“sh”,“-c”,“echo $ HOME”]。 當(dāng)使用exec表單并直接執(zhí)行一個(gè)shell時(shí)(如shell格式的情況),它是在執(zhí)行環(huán)境變量擴(kuò)展的shell,而不是docker。
您可以為ENTRYPOINT指定一個(gè)純字符串,它將在/ bin / sh -c中執(zhí)行。 該表單將使用shell處理來替換shell環(huán)境變量,并且將忽略任何CMD或docker run命令行參數(shù)。 為了確保docker stop會(huì)正確地告訴任何長(zhǎng)時(shí)間運(yùn)行的ENTRYPOINT可執(zhí)行文件,你需要記住用exec來啟動(dòng)它:
FROM ubuntu ENTRYPOINT exec top -b
當(dāng)你運(yùn)行這個(gè)圖像時(shí),你會(huì)看到單個(gè)PID 1
進(jìn)程:
$ 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添加到入口點(diǎn)的開頭:
FROM ubuntu ENTRYPOINT top -b CMD --ignored-param1
然后你可以運(yùn)行它(給它下一步的名字):
$ 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
。
如果你然后運(yùn)行docker stop test,那么容器不會(huì)干凈地退出 - 在超時(shí)之后,stop命令將被迫發(fā)送一個(gè)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
兩者CMD
和ENTRYPOINT
指令都定義了運(yùn)行容器時(shí)執(zhí)行的命令。有幾條規(guī)則描述了他們的合作。
Dockerfile應(yīng)至少指定一個(gè)CMD
或ENTRYPOINT
命令。
ENTRYPOINT
應(yīng)該在使用容器作為可執(zhí)行文件時(shí)定義。
CMD
應(yīng)該用作為ENTRYPOINT
命令定義默認(rèn)參數(shù)或在容器中執(zhí)行ad-hoc命令的一種方式。
CMD
在使用替代參數(shù)運(yùn)行容器時(shí)將被覆蓋。
下表顯示了針對(duì)不同ENTRYPOINT
/ CMD
組合執(zhí)行的命令:
No ENTRYPOINT | ENTRYPOINT exec_entry 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_entry p1_entry exec_cmd p1_cmd |
CMD “p1_cmd”, “p2_cmd” | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry | 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 | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
VOLUME ["/data"]
VOLUME指令創(chuàng)建一個(gè)具有指定名稱的掛載點(diǎn),并將其標(biāo)記為從本機(jī)主機(jī)或其他容器中存儲(chǔ)外部安裝的卷。 該值可以是JSON數(shù)組,VOLUME [“/ var / log /”]或具有多個(gè)參數(shù)的純字符串,例如VOLUME / var / log或VOLUME / var / log / var / db。 有關(guān)通過Docker客戶端的更多信息/示例和安裝說明,請(qǐng)參閱通過卷文檔共享目錄。
該docker run
命令使用基礎(chǔ)映像中指定位置存在的任何數(shù)據(jù)初始化新創(chuàng)建的卷。例如,請(qǐng)考慮以下Dockerfile代碼片段:
FROM ubuntu RUN mkdir /myvol RUN echo "hello world" > /myvol/greeting VOLUME /myvol
此Dockerfile導(dǎo)致導(dǎo)致docker運(yùn)行的映像,在/ myvol處創(chuàng)建新的掛載點(diǎn),并將問候語文件復(fù)制到新創(chuàng)建的卷中。
記住Dockerfile中的卷的以下幾點(diǎn)。
基于Windows的容器上的卷:使用基于Windows的容器時(shí),容器內(nèi)的卷的目標(biāo)必須是以下之一:
- a non-existing or empty directory- a drive other than `C:`
在Dockerfile中更改卷:如果任何構(gòu)建步驟在聲明后更改了卷內(nèi)的數(shù)據(jù),則這些更改將被丟棄。
JSON格式:列表被解析為JSON數(shù)組。您必須用雙引號(hào)("
)括住單詞而不是單引號(hào)('
)。
主機(jī)目錄在容器運(yùn)行時(shí)聲明:主機(jī)目錄(掛載點(diǎn))本質(zhì)上是與主機(jī)相關(guān)的。這是為了保持圖像的可移植性。因?yàn)闊o法保證給定的主機(jī)目錄在所有主機(jī)上都可用。因此,您無法從Dockerfile中掛載主機(jī)目錄。該VOLUME
指令不支持指定host-dir
參數(shù)。您必須在創(chuàng)建或運(yùn)行容器時(shí)指定安裝點(diǎn)。
USER <user>[:<group>] or USER <UID>[:<GID>]
USER指令設(shè)置用戶名(或UID)和可選的用戶組(或GID),以在運(yùn)行映像時(shí)以及在Dockerfile中執(zhí)行后續(xù)的任何RUN,CMD和ENTRYPOINT指令。
警告:當(dāng)用戶確實(shí)沒有主組時(shí),圖像(或下一個(gè)指令)將與
root
組一起運(yùn)行。
WORKDIR /path/to/workdir
WORKDIR指令為Dockerfile中后面的任何RUN,CMD,ENTRYPOINT,COPY和ADD指令設(shè)置工作目錄。 如果WORKDIR不存在,即使未在任何后續(xù)的Dockerfile指令中使用它,它也將被創(chuàng)建。
WORKDIR指令可以在Dockerfile中多次使用。 如果提供了相對(duì)路徑,它將相對(duì)于以前的WORKDIR指令的路徑。 例如:
WORKDIR /a WORKDIR b WORKDIR c RUN pwd
最終的輸出pwd
命令Dockerfile
將是/a/b/c
。
WORKDIR指令可以解析先前使用ENV設(shè)置的環(huán)境變量。 您只能使用在Dockerfile中顯式設(shè)置的環(huán)境變量。 例如:
ENV DIRPATH /path WORKDIR $DIRPATH/$DIRNAME RUN pwd
此Dockerfile中最終pwd命令的輸出將是/ path / $ DIRNAME
ARG <name>[=<default value>]
ARG指令定義了一個(gè)變量,用戶可以使用--build-arg <varname> = <value>標(biāo)志在構(gòu)建器中通過docker build命令將其傳遞給構(gòu)建器。 如果用戶指定了Dockerfile中未定義的構(gòu)建參數(shù),則構(gòu)建會(huì)輸出警告。
[Warning] One or more build-args [foo] were not consumed.
Dockerfile可能包含一條或多ARG
條指令。例如,以下是有效的Dockerfile:
FROM busybox ARG user1 ARG buildno...
警告:建議不要使用構(gòu)建時(shí)變量來傳遞github密鑰,用戶憑據(jù)等秘密。構(gòu)建時(shí)變量值對(duì)于具有docker history命令的圖像的任何用戶都是可見的。
ARG
指令可以可選地包括一個(gè)默認(rèn)值:
FROM busybox ARG user1=someuser ARG buildno=1...
如果ARG
指令具有默認(rèn)值,并且在構(gòu)建時(shí)沒有值傳遞,那么構(gòu)建器將使用默認(rèn)值。
一個(gè)ARG
變量定義從它在其中定義的行開始生效,而Dockerfile
不是來自參數(shù)在命令行或其他地方使用的行。例如,考慮這個(gè)Dockerfile:
1 FROM busybox2 USER ${user:-some_user}3 ARG user4 USER $user...
用戶通過調(diào)用以下命令構(gòu)建該文件:
$ docker build --build-arg user=what_user .
第2行的用戶評(píng)估為some_user,因?yàn)橛脩糇兞渴窃诤罄m(xù)行3上定義的。第4行的用戶評(píng)估為用戶定義的what_user,并在命令行上傳遞了what_user值。 在通過ARG指令定義之前,任何使用變量都會(huì)導(dǎo)致一個(gè)空字符串。
ARG指令在構(gòu)建階段結(jié)束時(shí)超出了范圍。 要在多個(gè)階段使用arg,每個(gè)階段都必須包含ARG指令。
FROM busybox ARG SETTINGS RUN ./run/setup $SETTINGS FROM busybox ARG SETTINGS RUN ./run/other $SETTINGS
您可以使用ARG或ENV指令來指定RUN指令可用的變量。 使用ENV指令定義的環(huán)境變量總是覆蓋相同名稱的ARG指令。 用ENV和ARG指令考慮這個(gè)Dockerfile。
1 FROM ubuntu2 ARG CONT_IMG_VER3 ENV CONT_IMG_VER v1.0.04 RUN echo $CONT_IMG_VER
然后,假設(shè)這個(gè)圖像是用這個(gè)命令建立的:
$ docker build --build-arg CONT_IMG_VER=v2.0.1 .
在這種情況下,RUN指令使用v1.0.0而不是用戶傳遞的ARG設(shè)置:v2.0.1這種行為類似于shell腳本,其中本地作用域變量覆蓋作為參數(shù)傳遞的變量或從環(huán)境繼承的變量, 定義點(diǎn)。
使用上面的示例但不同的ENV規(guī)范,您可以在ARG和ENV指令之間創(chuàng)建更多有用的交互:
1 FROM ubuntu2 ARG CONT_IMG_VER3 ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}4 RUN echo $CONT_IMG_VER
與ARG指令不同,ENV值始終保留在構(gòu)建的映像中。 考慮一個(gè)沒有--build-arg標(biāo)志的docker build:
$ docker build .
使用這個(gè)Dockerfile示例,CONT_IMG_VER仍然保留在圖像中,但其值為v1.0.0,因?yàn)樗荅NV指令在第3行默認(rèn)設(shè)置的值。
本例中的變量擴(kuò)展技術(shù)允許您通過命令行傳遞參數(shù),并通過利用ENV指令將它們保存在最終圖像中。 變量擴(kuò)展僅支持有限的Dockerfile指令集。
Docker有一組預(yù)定義的ARG變量,您可以在Dockerfile中使用沒有相應(yīng)的ARG指令的變量。
HTTP_PROXY
http_proxy
HTTPS_PROXY
https_proxy
FTP_PROXY
ftp_proxy
NO_PROXY
no_proxy
要使用這些,只需使用標(biāo)志在命令行上傳遞它們即可:
--build-arg <varname>=<value>
默認(rèn)情況下,這些預(yù)定義的變量將從Docker歷史記錄的輸出中排除。 將它們排除在外可以減少在HTTP_PROXY變量中意外泄漏敏感身份驗(yàn)證信息的風(fēng)險(xiǎn)。
For example, consider building the following Dockerfile using --build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com
FROM ubuntu RUN echo "Hello World"
在這種情況下,HTTP_PROXY變量的值在Docker歷史記錄中不可用,并且不會(huì)被緩存。 如果您要更改位置,并且您的代理服務(wù)器更改為http:// user:pass@proxy.sfo.example.com,則后續(xù)構(gòu)建不會(huì)導(dǎo)致緩存未命中。
如果您需要重寫此行為,則可以通過在Dockerfile中添加ARG語句來執(zhí)行此操作,如下所示:
FROM ubuntu ARG HTTP_PROXY RUN echo "Hello World"
構(gòu)建此Dockerfile時(shí),HTTP_PROXY將保留在Docker歷史記錄中,并且更改其值可使構(gòu)建緩存失效。
作為ENV變量,ARG變量不會(huì)保留在構(gòu)建的映像中。 但是,ARG變量確實(shí)會(huì)以類似的方式影響構(gòu)建緩存。 如果一個(gè)Dockerfile定義了一個(gè)ARG變量,它的值與以前的版本不同,那么第一次使用時(shí)會(huì)發(fā)生“緩存未命中”,而不是其定義。 尤其是,遵循ARG指令的所有RUN指令都隱式使用ARG變量(作為環(huán)境變量),因此可能導(dǎo)致緩存未命中。 除非在Dockerfile中存在匹配的ARG語句,否則所有預(yù)定義的ARG變量都可以免于緩存。
例如,考慮這兩個(gè)Dockerfile:
1 FROM ubuntu2 ARG CONT_IMG_VER3 RUN echo $CONT_IMG_VER
1 FROM ubuntu2 ARG CONT_IMG_VER3 RUN echo hello
如果在命令行中指定--build-arg CONT_IMG_VER = <value>,則在這兩種情況下,第2行上的規(guī)范不會(huì)導(dǎo)致緩存未命中; 第3行確實(shí)導(dǎo)致緩存未命中.ARG CONT_IMG_VER導(dǎo)致RUN行被識(shí)別為與運(yùn)行CONT_IMG_VER = <value> echo hello相同,因此如果<value>發(fā)生更改,則會(huì)導(dǎo)致緩存未命中。
考慮同一命令行下的另一個(gè)示例:
1 FROM ubuntu2 ARG CONT_IMG_VER3 ENV CONT_IMG_VER $CONT_IMG_VER4 RUN echo $CONT_IMG_VER
在此示例中,第3行發(fā)生高速緩存未命中。發(fā)生未命中是因?yàn)镋NV中的變量值引用了ARG變量,并且該變量通過命令行進(jìn)行了更改。 在此示例中,ENV命令會(huì)使圖像包含該值。
如果ENV
指令覆蓋ARG
同名的指令,就像這個(gè)Dockerfile一樣:
1 FROM ubuntu2 ARG CONT_IMG_VER3 ENV CONT_IMG_VER hello4 RUN echo $CONT_IMG_VER
第3行不會(huì)導(dǎo)致緩存缺失,因?yàn)镃ONT_IMG_VER的值是常量(hello)。 因此,RUN(第4行)上使用的環(huán)境變量和值在構(gòu)建之間不會(huì)更改。
ONBUILD [INSTRUCTION]
當(dāng)圖像被用作另一個(gè)構(gòu)建的基礎(chǔ)時(shí),ONBUILD指令為圖像添加一個(gè)稍后執(zhí)行的觸發(fā)指令。 觸發(fā)器將在下游構(gòu)建的上下文中執(zhí)行,就好像它已經(jīng)在下游Dockerfile中的FROM指令之后立即插入一樣。
任何構(gòu)建指令都可以注冊(cè)為觸發(fā)器。
如果您正在構(gòu)建將用作構(gòu)建其他圖像的基礎(chǔ)的圖像(例如應(yīng)用程序構(gòu)建環(huán)境或可使用用戶特定配置進(jìn)行自定義的守護(hù)程序),這非常有用。
例如,如果您的映像是可重用的Python應(yīng)用程序構(gòu)建器,則需要將應(yīng)用程序源代碼添加到特定目錄中,并且可能需要在此之后調(diào)用構(gòu)建腳本。 您現(xiàn)在不能僅僅調(diào)用ADD和RUN,因?yàn)槟€沒有訪問應(yīng)用程序源代碼,并且每個(gè)應(yīng)用程序構(gòu)建都會(huì)有所不同。 您可以簡(jiǎn)單地向應(yīng)用程序開發(fā)人員提供樣板Dockerfile以復(fù)制粘貼到他們的應(yīng)用程序中,但效率低下,容易出錯(cuò)并且難以更新,因?yàn)樗c特定于應(yīng)用程序的代碼混合在一起。
解決方案是使用ONBUILD
注冊(cè)先行指令在稍后的構(gòu)建階段運(yùn)行。
以下是它的工作原理:
當(dāng)它遇到ONBUILD指令時(shí),構(gòu)建器會(huì)為正在構(gòu)建的映像的元數(shù)據(jù)添加一個(gè)觸發(fā)器。 該指令不會(huì)影響當(dāng)前的構(gòu)建。
在構(gòu)建結(jié)束時(shí),所有觸發(fā)器的列表都存儲(chǔ)在圖像清單中的OnBuild鍵下。 可以使用docker inspect命令檢查它們。
稍后,可以使用FROM指令將圖像用作新構(gòu)建的基礎(chǔ)。 作為處理FROM指令的一部分,下游構(gòu)建器會(huì)查找ONBUILD觸發(fā)器,并按照它們的注冊(cè)順序執(zhí)行它們。 如果任何觸發(fā)器失敗,那么FROM指令將中止,從而導(dǎo)致構(gòu)建失敗。 如果所有觸發(fā)器都成功,則FROM指令完成并且構(gòu)建繼續(xù)照常。
觸發(fā)器在執(zhí)行后從最終圖像中清除。 換句話說,它們不會(huì)被“grand-children”構(gòu)建遺傳。
例如,你可能會(huì)添加如下內(nèi)容:
[...]ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src[...]
警告:不允許使用ONBUILD ONBUILD鏈接ONBUILD指令。 警告:ONBUILD指令可能不會(huì)觸發(fā)FROM或MAINTAINER指令。
STOPSIGNAL signal
該STOPSIGNAL
指令設(shè)置將被發(fā)送到容器的系統(tǒng)呼叫信號(hào)以退出。這個(gè)信號(hào)可以是一個(gè)有效的無符號(hào)數(shù)字,與內(nèi)核syscall表中的位置相匹配,例如9,或者SIGNAME格式的信號(hào)名稱,例如SIGKILL。
該HEALTHCHECK
指令有兩種形式:
HEALTHCHECK [OPTIONS] CMD command
(通過在容器中運(yùn)行一個(gè)命令來檢查容器的健康狀況)
HEALTHCHECK NONE
(禁用從基礎(chǔ)映像繼承的任何健康檢查)
該HEALTHCHECK
指令告訴Docker如何測(cè)試容器以檢查它是否仍在工作。這可以檢測(cè)到一些情況,例如即使服務(wù)器進(jìn)程仍在運(yùn)行,仍停留在無限循環(huán)中但無法處理新連接的Web服務(wù)器。
當(dāng)容器指定了健康狀況檢查時(shí),除了正常狀態(tài)之外,它還具有健康狀態(tài)。這是最初的狀態(tài)starting
。每當(dāng)健康檢查通過時(shí),就會(huì)變成healthy
(無論以前處于何種狀態(tài))。經(jīng)過一定次數(shù)的連續(xù)失敗后,它變成了unhealthy
。
之前可以顯示的選項(xiàng)CMD
是:
--interval=DURATION
(默認(rèn)值:30s
)
--timeout=DURATION
(默認(rèn)值:30s
)
--start-period=DURATION
(默認(rèn)值:0s
)
--retries=N
(默認(rèn)值:3
)
運(yùn)行狀況檢查將首先在容器啟動(dòng)后的間隔秒內(nèi)運(yùn)行,然后在每次前一次檢查完成后再次間隔幾秒。
如果單次運(yùn)行檢查花費(fèi)的時(shí)間超過了超時(shí)秒數(shù),那么檢查將被視為失敗。
需要重試連續(xù)的容器運(yùn)行狀況檢查失敗才會(huì)被視為不健康。
啟動(dòng)期為需要時(shí)間啟動(dòng)的容器提供初始化時(shí)間。在此期間探測(cè)失敗不會(huì)計(jì)入最大重試次數(shù)。但是,如果在啟動(dòng)期間運(yùn)行狀況檢查成功,則認(rèn)為容器已啟動(dòng),并且所有連續(xù)的故障都將計(jì)入最大重試次數(shù)。
Dockerfile中只能有一個(gè)HEALTHCHECK指令。 如果您列出多個(gè),則只有最后一個(gè)HEALTHCHECK將生效。
CMD
關(guān)鍵字后面的命令可以是shell命令(例如HEALTHCHECK CMD /bin/check-running
)或exec陣列(與其他Dockerfile命令一樣;請(qǐng)參閱ENTRYPOINT
詳細(xì)信息)。
該命令的退出狀態(tài)指示容器的健康狀態(tài)??赡艿闹凳牵?/p>
0:success - 容器健康并且可以使用
1:unhealthy - 容器工作不正常
2:reserved - 不要使用此退出代碼
例如,要每五分鐘檢查一次,網(wǎng)絡(luò)服務(wù)器能夠在三秒鐘內(nèi)為網(wǎng)站的主頁面提供服務(wù):
HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1
為了幫助調(diào)試失敗的探測(cè)器,命令在stdout或stderr上寫入的任何輸出文本(UTF-8編碼)都將存儲(chǔ)在健康狀態(tài)中,并且可以使用它進(jìn)行查詢docker inspect
。這樣的輸出應(yīng)該保持很短(目前僅存儲(chǔ)前4096個(gè)字節(jié))。
當(dāng)容器的健康狀況發(fā)生變化時(shí),health_status
會(huì)生成一個(gè)新狀態(tài)的事件。
該HEALTHCHECK
功能添加到Docker 1.12中。
SHELL ["executable", "parameters"]
SHELL指令允許覆蓋用于shell命令形式的默認(rèn)shell。 Linux上的默認(rèn)shell為[“/ bin / sh”,“-c”],在Windows上為[“cmd”,“/ S”,“/ C”]。 SHELL指令必須以JSON格式寫入Dockerfile中。
SHELL指令在Windows中有兩個(gè)常用且完全不同的本機(jī)shell特別有用:cmd和powershell,以及可用的備用shell,包括sh。
SHELL指令可以出現(xiàn)多次。 每個(gè)SHELL指令都會(huì)覆蓋所有先前的SHELL指令,并影響后面的所有指令。 例如:
FROM microsoft/windowsservercore # Executed as cmd /S /C echo defaultRUN echo default# Executed as cmd /S /C powershell -command Write-Host defaultRUN 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
當(dāng)它們的shell形式在Dockerfile中使用時(shí),以下指令可能受到SHELL指令的影響:RUN,CMD和ENTRYPOINT。
以下示例是Windows上可以通過使用該SHELL
指令簡(jiǎn)化的常見模式:
...RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"...
docker調(diào)用的命令是:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
這是無效的,原因有兩個(gè)。 首先,調(diào)用一個(gè)不必要的cmd.exe命令處理器(aka shell)。 其次,shell格式中的每條RUN指令都需要在命令前加上一個(gè)額外的powershell命令。
為了提高效率,可以采用兩種機(jī)制之一。一種是使用RUN命令的JSON格式,例如:
...RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""]...
盡管JSON格式是明確的,并且不使用不必要的cmd.exe,但它通過雙引號(hào)和轉(zhuǎn)義確實(shí)需要更多的冗長(zhǎng)。另一種機(jī)制是使用SHELL
指令和shell形式,為Windows用戶提供更自然的語法,尤其是與escape
解析器指令結(jié)合使用時(shí):
# escape=` FROM microsoft/nanoserver SHELL ["powershell","-command"]RUN New-Item -ItemType Directory C:\Example ADD Execute-MyCmdlet.ps1 c:\example\ RUN c:\example\Execute-MyCmdlet -sample 'hello world'
導(dǎo)致:
PS E:\docker\build\shell> docker build -t shell .Sending build context to Docker daemon 4.096 kB Step 1/5 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/5 : SHELL powershell -command ---> Running in 6fcdb6855ae2 ---> 6331462d4300 Removing intermediate container 6fcdb6855ae2 Step 3/5 : RUN New-Item -ItemType Directory C:\Example ---> Running in d0eef8386e97 Directory: C:\ Mode LastWriteTime Length Name---- ------------- ------ ----d----- 10/28/2016 11:26 AM Example ---> 3f2fbf1395d9 Removing intermediate container d0eef8386e97 Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\ ---> a955b2621c31 Removing intermediate container b825593d39fc Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world' ---> Running in be6d8e63fe75 hello world ---> 8e559e9bf424 Removing intermediate container be6d8e63fe75 Successfully built 8e559e9bf424 PS E:\docker\build\shell>
SHELL指令也可以用來修改shell的運(yùn)行方式。 例如,在Windows上使用SHELL cmd / S / C / V:ON | OFF,可以修改延遲的環(huán)境變量擴(kuò)展語義。
SHELL指令也可用于Linux,如果需要備用shell,如zsh,csh,tcsh等。
該SHELL
功能添加到Docker 1.12中。
下面你可以看到一些Dockerfile語法的例子。如果您對(duì)更真實(shí)的東西感興趣,請(qǐng)查看Dockerization示例列表。
# Nginx # # VERSION 0.0.1FROM ubuntu 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.3FROM 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 5900CMD ["x11vnc", "-forever", "-usepw", "-create"]
# Multiple images example # # VERSION 0.1FROM 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.