Dockerfile參考

Dockerfile參考

用法

docker build命令Dockerfile根據上下文構建image。構建的上下文是指定位置PATH或的文件URL。這PATH是本地文件系統上的目錄。URL是一個Git存儲庫位置。python

遞歸處理上下文。所以,a PATH包括全部子目錄,URL包括存儲庫及其子模塊。此示例顯示了使用當前目錄做爲上下文的構建命令:nginx

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

構建由Docker守護程序運行,而不是由CLI運行。構建過程的第一件事是將整個上下文(遞歸地)發送到守護進程。在大多數狀況下,最好從空目錄開始做爲上下文,並將Dockerfile保存在該目錄中。僅添加構建Dockerfile所需的文件。git

警告:不要用你的根目錄下,/做爲PATH由於它會致使生成到您的硬盤驅動器的所有內容傳輸到docker守護進程。github

要在構建上下文中使用文件,請Dockerfile引用指令中指定的文件,例如COPY指令。要提升構建的性能,請經過向.dockerignore上下文目錄添加文件來排除文件和目錄。golang

Dockerfile被調用Dockerfile並位於上下文的根中。您可使用-f標誌docker build指向文件系統中任何位置的Dockerfile。docker

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

若是構建成功,您能夠指定存儲庫和標記以保存新image:shell

$ docker build -t shykes/myapp .

要在構建後將映像標記爲多個存儲庫,請在-t運行build命令時添加多個參數:apache

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

在Docker守護程序運行其中的指令以前Dockerfile,它會執行初步驗證Dockerfile並在語法不正確時返回錯誤:ubuntu

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

Docker守護程序Dockerfile逐個運行指令,在必要時將每條指令的結果提交給新image,最後輸出新image的ID。Docker守護程序將自動清理您發送的上下文。windows

請注意,每條指令都是獨立運行的,會致使建立新image - 所以RUN cd /tmp不會對下一條指令產生任何影響。

只要有可能,Docker將從新使用中間image(緩存),以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 xxx@xxx.xx
 ---> 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

構建緩存僅用於具備本地父鏈的。這意味着這些image是由之前的版本建立的,或者加載了整個image鏈docker load。若是您但願使用特定image的構建緩存,可使用--cache-from選項指定它。指定的image --cache-from不須要具備父鏈,能夠從其餘註冊表中提取。

格式

這是如下格式Dockerfile

# Comment
INSTRUCTION arguments

該指令不區分大小寫。可是,慣例是讓它們成爲大寫的,以便更容易地將它們與參數區分開來。

Docker Dockerfile按順序運行指令。一個Dockerfile 必須用FROM指令啓動。該FROM指令指定您正在構建的BaseimageFROM能夠僅由一個或多個前面ARG的指令,其聲明瞭在使用的參數FROM中的行Dockerfile

Docker 將以條目開頭的#視爲註釋,除非該行是有效的parser-directives#行中任何其餘位置的標記都被視爲參數。這容許這樣的陳述:

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

註釋中不支持行繼續符。

directive

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

一旦處理了註釋,空行或構建器指令,Docker就再也不查找解析器指令。相反,它將格式化爲解析器指令的任何內容視爲註釋,而且不會嘗試驗證它是否多是解析器指令。所以,全部解析器指令必須位於a的頂部Dockerfile

解析器器指令不區分大小寫。可是,慣例是它們是小寫的。約定還包括任何解析器指令後面的空行。解析器指令不支持行繼續符。

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

因爲行繼續而無效:

# direc \
tive=value

因爲出現兩次無效:

# directive=value1
# directive=value2

FROM ImageName

因爲在構建器指令後出現而被視爲註釋:

FROM ImageName
# directive=value

因爲在不是解析器指令的註釋以後出現而被視爲註釋:

# About my dockerfile
# directive=value
FROM ImageName

因爲未被識別,未知指令被視爲註釋。此外,因爲出如今不是解析器指令的註釋以後,已知指令被視爲註釋。

# unknowndirective=value
# knowndirective=value

解析器指令中容許使用非換行空格。所以,如下幾行都是相同的:

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

支持如下解析器指令:

  • escape

escape

# escape=\ (backslash)

要麼

# escape=` (backtick)

escape指令設置用於轉義字符的字符 Dockerfile。若是未指定,則默認轉義字符爲\

FROM microsoft/nanoserver
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/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>

上面的一個解決方案是/用做COPY 指令的目標,和dir。可是,這種語法充其量是使人困惑的,由於對於路徑來講並不天然Windows,而且最壞的狀況是容易出錯,由於並不是全部命令都 做爲路徑分隔符Windows支持/

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

# escape=`

FROM microsoft/nanoserver
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/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.txt
10/05/2016  02:22 PM    <DIR>          Program Files
10/05/2016  02:14 PM    <DIR>          Program Files (x86)
10/28/2016  11:18 AM                62 testfile.txt
10/28/2016  11:20 AM    <DIR>          Users
10/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>

Environment replacement

環境變量(聲明的ENV),也能夠在特定指令做爲變量用來被解釋 Dockerfile。還會處理轉義,以便將相似變量的語法包含在字面上。

環境變量Dockerfile$variable_nameor表示${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
  • FROM
  • LABEL
  • STOPSIGNAL
  • USER
  • VOLUME
  • WORKDIR

以及:

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

注意:在1.4以前,ONBUILD指令支持環境變量,即便與上面列出的任何指令結合使用也是如此。

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

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

將致使def具備值hello,而不是bye。可是, ghi將具備值,bye由於它不是設置abc爲的相同指令的一部分bye

.dockerignore

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

CLI將.dockerignore文件解釋爲新行分隔的模式列表,相似於Unix shell的文件globs。出於匹配的目的,上下文的根被認爲是工做目錄和根目錄。例如,模式 /foo/barfoo/bar二者都排除bar 在位於的git存儲庫的foo子目錄PATH或根目錄中命名的文件或目錄URL。二者都不包括任何其餘內容。

若是.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上下文,全部降價文件除外

!異常規則的放置會影響行爲:.dockerignore匹配特定文件的最後一行肯定是包含仍是排除。請考慮如下示例:

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

除了之外的README文件,上下文中不包含markdown文件 README-secret.md

如今考慮這個例子:

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

包含全部README文件。中間線沒有效果,由於 !README*.md匹配README-secret.md而且最後。

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

最後,您可能但願指定要包含在上下文中的文件,而不是要排除的文件。要實現此目的,請指定*第一個模式,而後指定一個或多個!異常模式。

注意:因爲歷史緣由,將.忽略該模式。

FROM

FROM <image> [AS <name>]

要麼

FROM <image>[:<tag>] [AS <name>]

要麼

FROM <image>[@<digest>] [AS <name>]

FROM指令初始化新的構建階段併爲後續指令設置Baseimage。所以,有效Dockerfile必須以FROM指令開始。image能夠是任何有效image - 經過從dockerrepos提取image來啓動它尤爲容易。

  • ARG是先於僅指示FROMDockerfile
  • FROM能夠在單個內容中屢次出現Dockerfile以建立多個image,或者使用一個構建階段做爲另外一個構建階段的依賴項。只需在每條新FROM指令以前記下提交輸出的最後一個imageID 。每條FROM指令都清除先前指令建立的任何狀態。
  • 可選地,能夠經過添加AS nameFROM指令來將 名稱賦予新的構建階段。該名稱可用於後續FROMCOPY --from=<name|index>指令,以引用此階段構建的image。
  • tagdigest值是可選的。若是省略其中任何一個,則構建器默認採用latest標記。若是找不到tag值,構建器將返回錯誤。

瞭解ARG和FROM如何交互

FROM說明支持由ARG 第一個以前發生的任何指令聲明的變量FROM

ARG  CODE_VERSION=latest
FROM base:${CODE_VERSION}
CMD  /code/run-app

FROM extras:${CODE_VERSION}
CMD  /code/run-extras

ARG生命以前,FROM是一個構建階段以外,所以它不能在以後的任何指令使用FROM。要ARG在第一次FROM使用以前使用聲明的默認值,請在ARG構建階段內使用沒有值的指令:

ARG VERSION=latest
FROM busybox:$VERSION
ARG VERSION
RUN echo $VERSION > image_version

RUN

RUN有兩種形式:

  • RUN <command>shell表單,該命令在shell中運行,默認狀況下/bin/sh -c在Linux或cmd /S /CWindows 上運行)
  • RUN ["executable", "param1", "param2"]執行形式)

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

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

EXEC形式使得可以避免殼串改寫(munging),RUN 使用不包含指定殼可執行基本image命令。

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

shell形式中,您可使用\(反斜槓)將單個RUN指令繼續到下一行。例如,考慮如下兩行:

RUN /bin/bash -c 'source $HOME/.bashrc; \
echo $HOME'

它們一塊兒至關於這一行:

RUN /bin/bash -c 'source $HOME/.bashrc; echo $HOME'

注意:要使用除「/ bin / sh」以外的其餘shell,請使用傳入所需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 -y將在下一次構建期間重用。例如,RUN能夠經過使用--no-cache 標誌使指令的高速緩存無效docker build --no-cache

RUN指令的高速緩存能夠經過ADD

CMD

CMD指令有三種形式:

  • CMD ["executable","param1","param2"]執行形式,這是首選形式)
  • CMD ["param1","param2"](做爲ENTRYPOINT的默認參數
  • CMD command param1 param2貝殼形式)

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

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

注意:若是CMD用於爲ENTRYPOINT 指令提供默認參數,則應使用JSON數組格式指定CMDENTRYPOINT指令。

注意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指令設置在運行映像時要執行的命令。

若是你使用的是shell的形式CMD,那麼<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

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

注意:不要混淆RUN使用CMDRUN實際上運行一個命令並提交結果; 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能夠有多個標籤。您能夠在一行中指定多個標籤。在Docker 1.10以前,這減少了最終image的大小,但如今再也不是這種狀況了。您仍然能夠選擇在單個指令中指定多個標籤,方法有如下兩種:

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

基本或父image中包含的標籤(FROM線中的image)由image繼承。若是標籤已存在但具備不一樣的值,則最近應用的值將覆蓋任何先前設置的值。

要查看image的標籤,請使用該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>/<protocol>...]

EXPOSE指令通知Docker容器在運行時偵聽指定的網絡端口。您能夠指定端口是偵聽TCP仍是UDP,若是未指定協議,則默認爲TCP。

EXPOSE指令實際上沒有發佈端口。它做爲構建映像的人和運行容器的人之間的一種文檔,用於發佈要發佈的端口。要在運行容器時實際發佈端口,請使用-p標誌on docker run 來發布和映射一個或多個端口,或使用-P標誌發佈全部公開的端口並將它們映射到高階端口。

默認狀況下,EXPOSE假定爲TCP。您還能夠指定UDP:

EXPOSE 80/udp

要在TCP和UDP上公開,請包含兩行:

EXPOSE 80/tcp
EXPOSE 80/udp

在這種狀況下,若是使用docker run -P ,端口將爲TCP暴露一次,對UDP則暴露一次。請記住,-P在主機上使用短暫的高階主機端口,所以TCP和UDP的端口不一樣。

不管EXPOSE設置如何,您均可以使用-p標誌在運行時覆蓋它們。例如

docker run -p 80:80/tcp -p 80:80/udp ...

ENV

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

ENV指令將環境變量<key>設置爲該值 <value>。此值將在構建階段中全部後續指令的環境中。

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

將在最終image中產生相同的結果。

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

注意:環境持久性可能會致使意外的反作用。例如,設置ENV DEBIAN_FRONTEND noninteractive可能會使基於Debian的image上的apt-get用戶感到困惑。要爲單個命令設置值,請使用 RUN <key>=<value> <command>

ADD

ADD有兩種形式:

  • ADD [--chown=<user>:<group>] <src>... <dest>
  • ADD [--chown=<user>:<group>] ["<src>",... "<dest>"] (包含空格的路徑須要此表單)

注意:該--chown功能僅在用於構建Linux容器的Dockerfiles上受支持,而且不適用於Windows容器。因爲用戶和組全部權概念不能在Linux和Windows之間進行轉換,所以使用/etc/passwd/etc/group將用戶名和組名轉換爲ID會限制此功能僅適用於基於Linux OS的容器。

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

<src>能夠指定多個資源,但若是它們是文件或目錄,則它們的路徑將被解釋爲相對於構建上下文的源。

每一個都<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/

添加包含特殊字符(例如[])的文件或目錄時,須要按照Golang規則轉義這些路徑,以防止它們被視爲匹配模式。例如,要添加名爲的文件arr[0].txt,請使用如下命令;

ADD arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

除非可選--chown標誌指定給定用戶名,組名或UID / GID組合以請求所添加內容的特定全部權,不然將使用UID和GID爲0建立全部新文件和目錄。--chown標誌的格式容許用戶名和組名字符串或任意組合的直接整數UID和GID。提供沒有組名的用戶名或沒有GID的UID將使用與GID相同的數字UID。若是提供了用戶名或組名,則容器的根文件系統 /etc/passwd/etc/group文件將分別用於執行從名稱到整數UID或GID的轉換。如下示例顯示了該--chown標誌的有效定義:

ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/

若是容器根文件系統不包含任何文件/etc/passwd/etc/group文件,而且--chown 標誌中使用了用戶名或組名,則構建將在ADD操做上失敗。使用數字ID不須要查找,也不依賴於容器根文件系統內容。

<src>遠程文件URL 的狀況下,目標將具備600的權限。若是正在檢索的遠程文件具備HTTPLast-Modified標頭,則來自該標頭的時間戳將用於設置mtime目標文件。可是,與在處理期間處理的任何其餘文件同樣ADDmtime將不包括在肯定文件是否已更改且應更新緩存中。

注意:若是經過傳遞DockerfileSTDIN(docker build - < somefile)進行構建,則沒有構建上下文,所以Dockerfile 只能包含基於URL的ADD指令。您還能夠經過STDIN :( docker build - < archive.tar.gz)傳遞壓縮存檔Dockerfile,該存檔位於存檔的根目錄,其他存檔將用做構建的上下文。

注意:若是您的網址文件都使用認證保護,您將須要使用RUN wgetRUN curl或使用其它工具從容器內的ADD指令不支持驗證。

注意ADD若是內容<src>已更改,則第一個遇到的指令將使來自Dockerfile的全部後續指令的高速緩存無效。這包括使緩存無效以獲取RUN指令。

ADD 遵照如下規則:

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

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

  • 若是<src>是以可識別的壓縮格式(identity,gzip,bzip2或xz)的本地 tar存檔,則將其解壓縮爲目錄。從資源遠程網址解壓。複製或解壓縮目錄時,它具備與之相同的行爲tar -x,結果是:

    1. 不管在目的地路徑上存在什麼,
    2. 源樹的內容,在逐個文件的基礎上解決了有利於「2.」的衝突。

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

  • 若是<src>是任何其餘類型的文件,則將其與元數據一塊兒單獨複製。在這種狀況下,若是<dest>以尾部斜槓結尾/,則將其視爲目錄,<src>並將寫入內容<dest>/base(<src>)

  • 若是<src>直接或因爲使用通配符指定了多個資源,則<dest>必須是目錄,而且必須以斜槓結尾/

  • 若是<dest>不以尾部斜槓結束,則將其視爲常規文件,<src>並將寫入其中的內容<dest>

  • 若是<dest>不存在,則會在其路徑中建立全部缺乏的目錄。

COPY

COPY有兩種形式:

  • COPY [--chown=<user>:<group>] <src>... <dest>
  • COPY [--chown=<user>:<group>] ["<src>",... "<dest>"] (包含空格的路徑須要此表單)

注意:該--chown功能僅在用於構建Linux容器的Dockerfiles上受支持,而且不適用於Windows容器。因爲用戶和組全部權概念不能在Linux和Windows之間進行轉換,所以使用/etc/passwd/etc/group將用戶名和組名轉換爲ID會限制此功能僅適用於基於Linux OS的容器。

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

<src>能夠指定多個資源,但文件和目錄的路徑將被解釋爲相對於構建上下文的源。

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

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

<dest>是一個絕對路徑,或相對於一個路徑WORKDIR,到其中的源將在目標容器內進行復制。

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

複製包含特殊字符(例如[])的文件或目錄時,須要按照Golang規則轉義這些路徑,以防止它們被視爲匹配模式。例如,要複製名爲的文件arr[0].txt,請使用如下命令;

COPY arr[[]0].txt /mydir/    # copy a file named "arr[0].txt" to /mydir/

除非可選--chown標誌指定給定用戶名,組名或UID / GID組合以請求複製內容的特定全部權,不然將使用UID和GID爲0建立全部新文件和目錄。--chown標誌的格式容許用戶名和組名字符串或任意組合的直接整數UID和GID。提供沒有組名的用戶名或沒有GID的UID將使用與GID相同的數字UID。若是提供了用戶名或組名,則容器的根文件系統 /etc/passwd/etc/group文件將分別用於執行從名稱到整數UID或GID的轉換。如下示例顯示了該--chown標誌的有效定義:

COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/

若是容器根文件系統不包含任何文件/etc/passwd/etc/group文件,而且--chown 標誌中使用了用戶名或組名,則構建將在COPY操做上失敗。使用數字ID不須要查找,也不依賴於容器根文件系統內容。

注意:若是使用STDIN(docker build - < somefile)構建,則沒有構建上下文,所以COPY沒法使用。

(可選)COPY接受一個標誌--from=<name|index>,該標誌可用於將源位置設置爲FROM .. AS <name>將用於替代用戶發送的構建上下文的先前構建階段(使用其建立)。該標誌還接受爲FROM指令啓動的全部先前構建階段分配的數字索引 。若是找不到具備指定名稱的構建階段,則嘗試使用具備相同名稱的image。

COPY 遵照如下規則:

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

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

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

ENTRYPOINT

ENTRYPOINT有兩種形式:

  • ENTRYPOINT ["executable", "param1", "param2"]exec形式,首選)
  • ENTRYPOINT command param1 param2shell形式)

ENTRYPOINT容許您配置將做爲可執行文件運行的容器。

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

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

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

所述shell形式防止任何CMDrun被使用命令行參數,可是具備你的缺點ENTRYPOINT將被開始做爲一個子命令/bin/sh -c,其不經過信號。這意味着可執行文件將不是容器PID 1- 而且不會收到Unix信號 - 所以您的可執行文件將不會收到 SIGTERM來自docker stop <container>

只有意志中的最後一條ENTRYPOINT指令Dockerfile纔有效。

exec ENTRYPOINT示例

您可使用exec形式ENTRYPOINT設置至關穩定的默認命令和參數,而後使用任一形式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

而且您能夠優雅地請求docker stop test來關閉top

如下Dockerfile顯示使用ENTRYPOINT在前臺運行Apache(即as 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信號:

#!/usr/bin/env 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,則可使用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 ENTRYPOINT示例

您能夠爲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 stop test,容器將不會乾淨地退出 - stop命令將被強制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如何相互做用

CMDENTRYPOINT指定運行容器時執行的命令。不多有規則描述他們的合做。

  1. Dockerfile應至少指定一個CMDENTRYPOINT命令。
  2. ENTRYPOINT 應該在將容器用做可執行文件時定義。
  3. CMD應該用做定義ENTRYPOINT命令的默認參數或在容器中執行ad-hoc命令的方法。
  4. CMD 在使用替代參數運行容器時將被覆蓋。

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

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

VOLUME ["/data"]

VOLUME指令建立具備指定名稱的安裝點,並將其標記爲從本機主機或其餘容器保存外部安裝的卷。該值能夠是JSON數組,VOLUME ["/var/log/"]或具備多個參數的普通字符串,例如VOLUME /var/logVOLUME /var/log /var/db

docker run命令使用基礎映像中指定位置存在的任何數據初始化新建立的卷。例如,請考慮如下Dockerfile片斷:

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

此Dockerfile會docker run生成一個image,該image將致使建立新的掛載點/myvol並將greeting文件複製到新建立的卷中。

有關指定卷的說明

關於卷中的卷,請記住如下事項Dockerfile

  • 基於Windows的容器上的卷:使用基於Windows的容器時,容器中卷的目標必須是如下之一:
    • 不存在或空目錄
    • 除了以外的驅動器 C:
  • 從Dockerfile中更改卷:若是任何構建步驟在聲明後更改卷內的數據,那麼這些更改將被丟棄。
  • JSON格式:列表被解析爲JSON數組。您必須用雙引號(")而不是單引號(')括起單詞。
  • 主機目錄在容器運行時聲明:主機目錄(mountpoint)本質上是依賴於主機的。這是爲了保持image的可移植性,由於不能保證給定的主機目錄在全部主機上均可用。所以,您沒法從Dockerfile中安裝主機目錄。該VOLUME指令不支持指定host-dir 參數。您必須在建立或運行容器時指定安裝點。

USER

USER <user>[:<group>] or
USER <UID>[:<GID>]

USER運行的image和用於當任何指令設置的用戶名(或UID)和任選的所述用戶組(或GID)使用RUNCMDENTRYPOINT它後面的指令Dockerfile

警告:當用戶沒有主要組時,image(或下一個說明)將與該root組一塊兒運行。

在Windows上,若是用戶不是內置賬戶,則必須先建立用戶。這能夠經過net user做爲Dockerfile的一部分調用的命令來完成。

FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrick

WORKDIR

WORKDIR /path/to/workdir

WORKDIR指令集的工做目錄對任何RUNCMDENTRYPOINTCOPYADD它後面的說明Dockerfile。若是WORKDIR不存在,即便它未在任何後續Dockerfile指令中使用,也將建立它。

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

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd

最終pwd命令的輸出Dockerfile將是 /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中定義的構建參數,則構建會輸出警告。

[Warning] One or more build-args [foo] were not consumed.

Dockerfile能夠包括一個或多個ARG指令。例如,如下是有效的Dockerfile:

FROM busybox
ARG user1
ARG buildno
...

警告:建議不要使用構建時變量來傳遞密碼,例如github密鑰,用戶憑據等docker history。使用該命令,構建時變量值對於映像的任何用戶都是可見的。

默認值

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 .

第2行計算USER``some_useruser變量在後續第3行定義。第4行USER計算結果what_useruser定義,並what_user在命令行上傳遞值。在經過ARG指令定義以前 ,對變量的任何使用都會致使空字符串。

一個ARG指令超出範圍在它被定義的構建階段結束。要在多個階段中使用arg,每一個階段都必須包含該ARG指令。

FROM busybox
ARG SETTINGS
RUN ./run/setup $SETTINGS

FROM busybox
ARG SETTINGS
RUN ./run/other $SETTINGS

使用ARG變量

您可使用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

而後,假設使用此命令構建此映像:

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

在這種狀況下,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示例CONT_IMG_VER仍然保留在image中,但其值將是指令v1.0.0中第3行的默認值ENV

預約義的ARG

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

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

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

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

默認狀況下,這些預約義變量將從輸出中排除 docker history。排除它們能夠下降在HTTP_PROXY變量中意外泄露敏感驗證信息的風險。

例如,考慮使用構建如下Dockerfile--build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com

FROM ubuntu
RUN echo "Hello World"

在這種狀況下,HTTP_PROXY變量的值在docker history和中不可用, 而且不會被緩存。若是您要更改位置,而且您的代理服務器已更改成http://user:pass@proxy.sfo.example.com,則後續構建不會致使緩存未命中。

若是須要覆蓋此行爲,則能夠經過ARG 在Dockerfile中添加語句來執行此操做,以下所示:

FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"

構建此Dockerfile時,HTTP_PROXY會保留在其中 docker history,而且更改其值會使構建緩存無效。

對構建緩存的影響

ARG變量不會像ENV變量那樣持久保存在構建的image中。可是,ARG變量確實以相似的方式影響構建緩存。若是Dockerfile定義了一個ARG值與前一個版本不一樣的變量,則在第一次使用時會發生「緩存未命中」,而不是其定義。特別是,RUN指令後面的全部指令都 隱式ARG使用ARG變量(做爲環境變量),所以可能致使高速緩存未命中。ARG除非在中包含匹配的ARG語句,不然全部預約義變量都將免於緩存Dockerfile

例如,考慮這兩個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]

當image用做另外一個構建的基礎時,該ONBUILD指令向image添加將在稍後執行的觸發指令。觸發器將在下游構建的上下文中執行,就好像它已經FROM在下游指令以後當即插入同樣Dockerfile

任何構建指令均可以註冊爲觸發器。

若是要構建將用做構建其餘映像的基礎的映像(例如,可使用特定於用戶的配置自定義的應用程序構建環境或守護程序),這將很是有用。

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

解決方案是用於ONBUILD在下一個構建階段註冊預先指令以便稍後運行。

如下是它的工做原理:

  1. 當遇到ONBUILD指令時,構建器會向正在構建的image的元數據添加觸發器。該指令不會影響當前構建。
  2. 在構建結束時,全部觸發器的列表存儲在鍵下的image清單中OnBuild。可使用該docker inspect命令檢查它們。
  3. 稍後,可使用該FROM指令將image用做新構建的基礎 。做爲處理FROM指令的一部分,下游構建器查找ONBUILD觸發器,並按照它們註冊的順序執行它們。若是任何觸發器失敗,FROM則停止指令,這反過來致使構建失敗。若是全部觸發器都成功,則FROM指令完成而且構建繼續照常進行。
  4. 執行後,觸發器將從最終image中清除。換句話說,它們不是由「大孩子」構建繼承的。

例如,您能夠添加如下內容:

[...]
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指令有兩種形式:

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

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

當容器指定了運行情況檢查時,除了正常狀態外,它還具備運行情況。這個狀態最初是starting。每當健康檢查經過時,它就會變成healthy(之前的狀態)。通過必定數量的連續失敗後,它就變成了unhealthy

以前能夠出現的選項CMD是:

  • --interval=DURATION(默認值:30s
  • --timeout=DURATION(默認值:30s
  • --start-period=DURATION(默認值:0s
  • --retries=N(默認值:3

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

若是單次運行的檢查花費的時間超過超時秒數,那麼檢查將被視爲失敗。

它須要重試連續的健康檢查失敗才能考慮容器unhealthy

start period爲須要時間引導的容器提供初始化時間。在此期間探測失敗將不計入最大重試次數。可是,若是在啓動期間運行情況檢查成功,則會將容器視爲已啓動,而且全部連續失敗將計入最大重試次數。

HEALTHCHECKDockerfile中只能有一條指令。若是列出多個,則只有最後一個HEALTHCHECK生效。

CMD關鍵字後面的命令能夠是shell命令(例如HEALTHCHECK CMD /bin/check-running)或exec數組(與其餘Dockerfile命令同樣; ENTRYPOINT有關詳細信息,請參閱參考資料)。

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

  • 0:成功 - 容器健康且隨時可用
  • 1:不健康 - 容器沒法正常工做
  • 2:保留 - 不要使用此退出代碼

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

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上特別有用cmdpowershell,以及提供包括候補炮彈sh

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

FROM microsoft/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指令時, 他們的形式在一個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

爲了提升效率,能夠採用兩種機制中的一種。一種是使用RUN命令的JSON形式,例如:

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

雖然JSON表單是明確的,而且不使用沒必要要的cmd.exe,但它確實須要經過雙引號和轉義更加詳細。替代機制是使用SHELL指令和shell表單,爲Windows用戶建立更天然的語法,尤爲是與escape解析器指令結合使用時:

# 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'

致使:

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的運行方式。例如,SHELL cmd /S /C /V:ON|OFF在Windows上使用,能夠修改延遲的環境變量擴展語義。

SHELL,也能夠在Linux上使用的指令應當替代殼須要如zshcshtcsh和其餘。

SHELL功能已添加到Docker 1.12中。

Dockerfile示例

# Nginx
#
# VERSION               0.0.1

FROM      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.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.
相關文章
相關標籤/搜索