1. 程式人生 > 程式設計 >Dockerfile、Docker Compose file 參考檔案

Dockerfile、Docker Compose file 參考檔案

Dockerfile

Dockerfile是由一系列命令和引數構成的指令碼,一個Dockerfile裡麵包含了構建整個image的完整命令。Docker通過docker build執行Dockerfile中的一系列命令自動構建image

Dockerfile其語法非常簡單,此頁面描述了您可以在Dockerfile中使用的命令。 閱讀此頁面後,你可以參閱Dockerfile最佳實踐

Usage

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

context

以遞迴方式處理。因此,PATH包括任何子目錄,URL包括repository及submodules。一個使用當前目錄作為context的簡單構建命令:

$ docker build .
Sending build context to Docker daemon  6.51 MB
...
複製程式碼

構建由Docker守護程式執行,而不是由CLI執行。構建過程所做的第一件事是將整個context(遞迴地)傳送給守護程式。大多數情況下,最好是將Dockerfile和所需檔案複製到一個空的目錄,再到這個目錄進行構建。

警告:不要使用根目錄/作為PATH,因為它會導致構建將硬碟驅動器的所有內容傳輸到Docker守護程式。

build時新增檔案,通過Dockerfile引用指令中指定的檔案,例如COPY指令。要增加構建的效能,請通過將.dockerignore檔案新增到context目錄中來排除檔案和目錄。有關如何建立.dockerignore檔案的資訊,請參閱此頁上的檔案。

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

$ docker build -f /path/to/a/Dockerfile .
複製程式碼

如果build成功,您可以指定要儲存新image的repository和tag:

$ docker build -t shykes/myapp .
複製程式碼

要在構建後將image標記為多個repositories,請在執行構建命令時新增多個-t引數:

$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
複製程式碼

Docker守護程式一個接一個地執行Dockerfile中的指令,如果需要,將每個指令的結果提交到一個新image,最後輸出新映像的ID。Docker守護程式將自動清理您傳送的context。

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

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

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

構建成功後,就可以準備Pushing a repository to its registry

Format

Dockerfile的格式如下:

# Comment
INSTRUCTION arguments
複製程式碼

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

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

# Comment
RUN echo 'we are running some # of cool things'
複製程式碼

Parser directives

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

一旦註釋,空行或構建器指令已經被處理,Docker不再尋找解析器指令。相反,它將任何格式化為解析器指令作為註釋,並且不嘗試驗證它是否可能是解析器指令。因此,所有解析器指令必須位於Dockerfile的最頂端。

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

由於這些規則,以下示例都無效:

因行延續,無效:

# direc \
tive=value
複製程式碼

因出現兩次,無效:

# directive=value1
# directive=value2

FROM ImageName
複製程式碼

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

FROM ImageName
# directive=value
複製程式碼

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

# About my dockerfile
FROM ImageName
# directive=value
複製程式碼

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

# unknowndirective=value
# knowndirective=value
複製程式碼

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

#directive=value
# directive =value
#   directive= value
# directive = value
#     dIrEcTiVe=value
複製程式碼

支援以下解析器指令: * escape

escape

# escape=\ (backslash)
或者
# escape=` (backtick)
複製程式碼

escape指令設定用於在Dockerfile中轉義字元的字元。如果未指定,則預設轉義字元為\

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

將轉義字元設定為 ` 在Windows上特別有用,其中\是目錄路徑分隔符。 ` 與Windows PowerShell一致。

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

FROM windowsservercore
COPY testfile.txt c:\\
RUN dir c:\
複製程式碼

結果是:

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

上述的一個解決方案是使用/作為COPY指令和dir的目標。然而,這種語法,最好的情況是混亂,因為它在Windows上是不平常的路徑,最壞的情況下,錯誤傾向,因為並不是Windows上的所有命令支援/作為路徑分隔符。

通過新增轉義解析器指令,下面的Dockerfile在Windows上使用檔案路徑的自然平臺語義成功:

# escape=`

FROM windowsservercore
COPY testfile.txt c:\
RUN dir c:\
複製程式碼

結果是:

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

 Directory of c:\

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

Environment replacement

環境變數(使用ENV語句宣告)也可以在某些指令中用作要由Dockerfile解釋的變數。還可以處理轉義,以將類似變數的語法包含在語句中。

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

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

  • ${variable:-word}表示如果設定了variable,則結果將是該值。如果variable未設定,那麼word將是結果。
  • ${variable:+word}表示如果設定了variable,那麼word將是結果,否則結果是空字串。

在所有情況下,word可以是任何字串,包括額外的環境變數。

可以通過在變數之前新增\來轉義:\$foo\${foo},分別轉換為$foo${foo}

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

FROM busybox
ENV foo /bar
WORKDIR ${foo}   # WORKDIR /bar
ADD . $foo       # ADD . /bar
COPY \$foo /quux # COPY $foo /quux
複製程式碼

Dockerfile中的以下指令列表支援環境變數:

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

以及:

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

注意:在1.4之前,ONBUILD指令不支援環境變數,即使與上面列出的任何指令相結合。

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

ENV abc=hello
ENV abc=bye def=$abc
ENV ghi=$abc
複製程式碼

將導致def值為hello,不再bye。然而,ghi的值為bye,因為它不是設定abcbye的相同命令的一部分。

.dockerignore file

在docker CLI將上下文傳送到docker守護程式之前,它會在上下文的根目錄中查詢名為.dockerignore的檔案。如果此檔案存在,CLI將修改上下文以排除匹配其中模式的檔案和目錄。這有助於避免不必要地向守護程式傳送大型或敏感檔案和目錄,並可能使用ADDCOPY將其新增到映像。

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

如果.dockerignore檔案中的一行以第1列中以#開頭,則此行被視為註釋,並在CLI解釋之前被忽略。

這裡是一個例子.dockerignore檔案:

# comment
*/temp*
*/*/temp*
temp?
複製程式碼

此檔案導致以下構建行為:

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

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

除了Go的filepath.Match規則,Docker還支援一個特殊的萬用字元字串**,它匹配任何數量的目錄(包括零)。 例如,**/*.go將排除所有目錄中找到的以.go結尾的所有檔案,包括構建上下文的根。

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

*.md
!README.md
複製程式碼

除了README.md之外的所有markdown檔案都從上下文中排除。

放置!異常規則影響行為:匹配特定檔案的.dockerignore的最後一行確定它是包括還是排除。思考下面的例子:

*.md
!README*.md
README-secret.md
複製程式碼

除了README-secret.md之外的README檔案,上下文中排除所有markdown檔案。

現在思考這個例子:

*.md
README-secret.md
!README*.md
複製程式碼

包括所有README檔案。 中間行沒有效果,因為最後的!README*.mdREADME-secret.md匹配。

您甚至可以使用.dockerignore檔案來排除Dockerfile.dockerignore檔案。這些檔案仍然傳送到守護程式,因為它需要它們來完成它的工作。但是ADDCOPY命令不會將它們複製到映像。

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

注意:由於歷史原因.模式。被忽略。

FROM

FROM <image>
# 或則
FROM <image>:<tag>
# 或則
FROM <image>@<digest>
複製程式碼

FROM指令為後續指令設定Base Image。因此,有效的Dockerfile必須具有FROM作為其第一條指令。image可以是任何有效的image - 可以從Public Repositoriespulling an image

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

MAINTAINER

MAINTAINER <name>
複製程式碼

MAINTAINER指令允許您設定生成的images的作者欄位。

RUN

RUN有2種形式:

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

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

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

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

可以使用SHELL命令更改shell表單的預設shell。

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

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

注意:exec形式作為JSON陣列解析,這意味著您必須在單詞之外使用雙引號(”)而不是單引號(’)。

注意:與shell表單不同,exec表單不呼叫命令shell。這意味著正常的shell處理不會發生。例如,RUN ["echo","$HOME"]不會在$HOME上進行可變替換。如果你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:RUN ["sh","-c","echo $HOME"]。當使用exec形式並直接執行shell時,正如shell形式的情況,它是做環境變數擴充套件的shell,而不是docker。

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

用於RUN指令的快取記憶體在下一次構建期間不會自動失效。用於諸如RUN apt-get dist-upgrade之類的指令的快取記憶體將在下一次構建期間被重用。可以通過使用--no-cache標誌來使用於RUN指令的快取記憶體無效,例如docker build --no-cache

有關詳細資訊,請參閱Dockerfile最佳實踐指南

用於RUN指令的快取記憶體可以通過ADD指令無效。有關詳細資訊,請參見下文

Known issues(RUN)

  • Issue 783是關於在使用AUFS檔案系統時可能發生的檔案許可權問題。例如,您可能會在嘗試rm檔案時注意到它。對於具有最近aufs版本的系統(即,可以設定dirperm1安裝選項),docker將嘗試通過使用dirperm1選項安裝image來自動解決問題。有關dirperm1選項的更多詳細資訊,請參見aufs手冊頁 如果您的系統不支援dirperm1,則該問題描述了一種解決方法。

CMD

CMD指令三種形式:

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

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

CMD的主要目的是為執行容器提供預設值。這些預設值可以包括可執行檔案,或者它們可以省略可執行檔案,在這種情況下,您還必須指定ENTRYPOINT指令。

注意:如果使用CMDENTRYPOINT指令提供預設引數,CMDENTRYPOINT指令都應以JSON陣列格式指定。

注意:exec形式作為JSON陣列解析,這意味著您必須在單詞之外使用雙引號(”)而不是單引號(’)。

注意:與shell表單不同,exec表單不呼叫命令shell。這意味著正常的shell處理不會發生。例如,CMD ["echo","$HOME"]不會在$HOME上進行可變替換。如果你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:CMD ["sh","echo $HOME"]。當使用exec形式並直接執行shell時,正如shell形式的情況,它是做環境變數擴充套件的shell,而不是docker。

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

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

FROM ubuntu
CMD echo "This is a test." | wc -
複製程式碼

如果你想執行你的<command>沒有shell,那麼你必須將該命令表示為一個JSON陣列,並給出可執行檔案的完整路徑。此陣列形式是CMD的首選格式。任何其他引數必須單獨表示為陣列中的字串:

FROM ubuntu
CMD ["/usr/bin/wc","--help"]
複製程式碼

如果你希望你的容器每次執行相同的可執行檔案,那麼你應該考慮使用ENTRYPOINT結合CMD。 請參閱ENTRYPOINT

如果使用者指定docker run引數,那麼它們將覆蓋CMD中指定的預設值。

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

LABEL

LABEL <key>=<value> <key>=<value> <key>=<value> ...
複製程式碼

LABEL指令向image新增元資料。LABEL是鍵值對。要在LABEL值中包含空格,請使用引號和反斜槓,就像在命令列解析中一樣。幾個使用示例:

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

image可以有多個label。要指定多個label,Docker建議在可能的情況下將標籤合併到單個LABEL指令中。每個LABEL指令產生一個新層,如果使用許多標籤,可能會導致效率低下的影象。該示例產生單個影象層。

LABEL multi.label1="value1" multi.label2="value2" other="value3"
複製程式碼

上面的也可寫為:

LABEL multi.label1="value1" \
      multi.label2="value2" \
      other="value3"
複製程式碼

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

要檢視image的labels,請使用docker inspect命令。

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

EXPOSE

EXPOSE <port> [<port>...]
複製程式碼

EXPOSE指令通知Docker容器在執行時偵聽指定的網路埠。EXPOSE不使主機的容器的埠可訪問。為此,必須使用-p標誌釋出一系列埠,或者使用-P標誌釋出所有暴露的埠。您可以公開一個埠號,並用另一個埠號在外部發布。

要在主機系統上設定埠重定向,請參閱使用-P標誌。Docker網路功能支援建立網路,無需在網路中公開埠,有關詳細資訊,請參閱此功能的概述)。

ENV

ENV <key> <value>
ENV <key>=<value> ...
複製程式碼

ENV指令將環境變數<key>設定為值<value>。該值將在所有”descendant” Dockerfile命令的環境中,並且可以在許多中被替換為inline

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

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

例如:

ENV myName="John Doe" myDog=Rex\ The\ Dog \
    myCat=fluffy
# 和
ENV myName John Doe
ENV myDog Rex The Dog
ENV myCat fluffy
複製程式碼

將在最終容器中產生相同的淨結果,但第一種形式是優選的,因為它產生單個快取記憶體層。

使用ENV設定的環境變數將在從生成的image執行容器時保留。您可以使用docker inspect檢視值,並使用docker run --env <key> = <value>更改它們。

注意:環境永續性可能會導致意外的副作用。例如,將ENV DEBIAN_FRONTEND設定為非互動式可能會使apt-get使用者混淆基於Debian的映像。要為單個命令設定值,請使用RUN <key> = <value> <command>

ADD

兩種形式:

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

ADD指令從<src>複製新檔案,目錄或遠端檔案URL,並將它們新增到容器的檔案系統,路徑<dest>

可以指定多個<src>資源,但如果它們是檔案或目錄,那麼它們必須是相對於正在構建的源目錄(構建的context)。

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

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

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

ADD test relativeDir/          # adds "test" to `WORKDIR`/relativeDir/
ADD test /absoluteDir/         # adds "test" to /absoluteDir/
複製程式碼

所有新檔案和目錄都使用UID和GID為0建立。

<src>是遠端檔案URL的情況下,目標將具有600的許可權。如果正在檢索的遠端檔案具有HTTP Last-Modified標頭,則來自該標頭的時間戳將用於設定目的地上的mtime檔案。然而,像在ADD期間處理的任何其它檔案一樣,mtime將不包括在確定檔案是否已經改變並且快取記憶體應該被更新。

注意:如果通過傳遞一個Dockerfile通過STDIN(docker build - <somefile)構建,沒有構建上下文,所以Dockerfile只能包含一個基於URL的ADD指令。您還可以通過STDIN傳遞壓縮歸檔檔案:(docker build - <archive.tar.gz),歸檔根目錄下的Dockerfile和歸檔的其餘部分將在構建的上下文中使用。

注意:如果您的URL檔案使用身份驗證保護,則您需要使用RUN wgetRUN curl或從容器內使用其他工具,因為ADD指令不支援身份驗證。

注意:如果<src>的內容已更改,第一個遇到的ADD指令將使來自Dockerfile的所有後續指令的快取記憶體無效。這包括使用於RUN指令的快取記憶體無效。有關詳細資訊,請參閱Dockerfile最佳實踐指南

ADD遵守以下規則:

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

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

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

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

  • 如果<src>是任何其他型別的檔案,它會與其元資料一起單獨複製。在這種情況下,如果<dest>以尾部斜槓/結尾,它將被認為是一個目錄,並且<src>的內容將被寫在<dest>/base(<src>)
  • 如果直接或由於使用萬用字元指定了多個<src>資源,則<dest>必須是目錄,並且必須以斜槓/結尾。
  • 如果<dest>不以尾部斜槓結尾,它將被視為常規檔案,<src>的內容將寫在<dest>
  • 如果<dest>不存在,則會與其路徑中的所有缺少的目錄一起建立。

COPY

兩種形式:

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

基本和ADD類似,不過COPY<src>不能為URL。

ENTRYPOINT

兩種形式:

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

ENTRYPOINT允許您配置容器,執行執行的可執行檔案。

例如,以下將使用其預設內容啟動nginx,偵聽埠80:

docker run -i -t --rm -p 80:80 nginx
複製程式碼

docker run <image>的命令列引數將附跟在

exec 形式的ENTRYPOINT中的所有元素之後,並將覆蓋使用CMD指定的所有元素。這允許將引數傳遞到入口點,即docker run <image> -d將把-d引數傳遞給入口點。您可以使用docker run --entrypoint標誌覆蓋ENTRYPOINT指令。

shell 形式防止使用任何CMD或執行命令列引數,但是缺點是您的ENTRYPOINT將作/bin/sh -c的子命令啟動,它不傳遞訊號。這意味著可執行檔案將不是容器的PID 1,並且不會接收Unix訊號,因此您的可執行檔案將不會從docker stop <container>接收到SIGTERM

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

Exec form ENTRYPOINT example

您可以使用ENTRYPOINT的*exec*形式設定相當穩定的預設命令和引數,然後使用任一形式的CMD設定更可能更改的其他預設值。

FROM ubuntu
ENTRYPOINT ["top","-b"]
CMD ["-c"]
複製程式碼

執行容器時,您可以看到top是唯一的程式:

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

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

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

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

並且你可以優雅地請求top使用docker stop test關閉。

以下Dockerfile顯示使用ENTRYPOINT在前臺執行Apache(即,作為PID 1):

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

如果需要為單個可執行檔案編寫啟動指令碼,可以使用execgosu命令確保最終可執行檔案接收到Unix訊號:

#!/bin/bash
set -e

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

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

    exec gosu postgres "$@"
fi

exec "$@"
複製程式碼

最後,如果需要在關閉時進行一些額外的清理(或與其他容器通訊),或者協調多個可執行檔案,您可能需要確保ENTRYPOINT指令碼接收到Unix訊號,傳遞它們,然後做一些更多的工作:

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

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

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

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

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

echo "exited $0"
複製程式碼

如果你用docker run -it --rm -p 80:80 --name test apache執行image,則可以使用·docker exec·或·docker top·檢查容器的程式,然後請求指令碼停止Apache:

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

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

注意:*exec*形式作為JSON陣列解析,這意味著您必須在單詞之外使用雙引號(”)而不是單引號(’)。

注意:與shell形式不同,*exec*形式不呼叫命令shell。這意味著正常的shell處理不會發生。例如,ENTRYPOINT ["echo","$ HOME"]不會在$HOME上進行可變替換。如果你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:ENTRYPOINT ["sh","echo $HOME"]。當使用exec形式並直接執行shell時,正如shell形式的情況,它是做環境變數擴充套件的shell,而不是docker。

Shell form ENTRYPOINT example

您可以為ENTRYPOINT指定一個純字串,它將在/bin/sh -c中執行。這中形式將使用shell處理來替換shell環境變數,並且將忽略任何CMDdocker run命令列引數。要確保docker stop將正確地發出任何長時間執行的ENTRYPOINT可執行檔案,您需要記住用exec啟動它:

FROM ubuntu
ENTRYPOINT exec top -b
複製程式碼

執行此image時,您將看到單個PID 1程式:

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

它獎在docker stop乾淨的退出:

$ /usr/bin/time docker stop test
test
real    0m 0.20s
user    0m 0.02s
sys 0m 0.04s
複製程式碼

如果忘記將exec新增到您的ENTRYPOINT的開頭:

FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1
複製程式碼

然後,您可以執行它(給它一個名稱為下一步):

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

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

如果你然後執行docker停止測試,容器將不會完全退出 - 停止命令將強制傳送SIGKILL超時後:

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

Understand how CMD and ENTRYPOINT interact

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

  • Dockerfile應該至少指定一個CMDENTRYPOINT命令。
  • 當使用容器作為可執行檔案時,應該定義ENTRYPOINT
  • CMD應該用作定義ENTRYPOINT命令的預設引數或在容器中執行ad-hoc命令的一種方法。
  • 當執行帶有替代引數的容器時,CMD將被覆蓋。

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

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

VOLUME

VOLUME ["/data"]
複製程式碼

VOLUME指令建立具有指定名稱的掛載點,並將其標記為從本機主機或其他容器保留外部掛載的卷。該值可以是JSON陣列VOLUME ["/var/log/"]或具有多個引數的純字串,例如VOLUME /var/logVOLUME /var/log /var/db。有關通過Docker客戶端的更多資訊/示例和安裝說明,請參閱通過卷檔案共享目錄

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

FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
複製程式碼

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

注意:如果任何構建步驟在宣告後更改卷中的資料,那麼這些更改將被丟棄。

注意:該列表解析為JSON陣列,這意味著您必須在單詞之外使用雙引號(”)而不是單引號(’)。

USER

USER daemon
複製程式碼

USER指令設定執行image時使用的使用者名稱或UID,以及Dockerfile中的任何RUN,CMDENTRYPOINT指令。

WORKDIR

WORKDIR /path/to/workdir
複製程式碼

WORKDIR指令為Dockerfile中的任何RUNCMDENTRYPOINTCOPYADD指令設定工作目錄。如果WORKDIR不存在,它將被建立,即使它沒有在任何後續的Dockerfile指令中使用。

它可以在一個Dockerfile中多次使用。如果提供了相對路徑,它將相對於先前WORKDIR指令的路徑。 例如:

WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
複製程式碼

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

WORKDIR指令可以解析先前使用ENV設定的環境變數。您只能使用在Dockerfile中顯式設定的環境變數。 例如:

ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
複製程式碼

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

ARG

ARG <name>[=<default value>]
複製程式碼

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

One or more build-args were not consumed,failing build.
複製程式碼

Dockerfile作者可以通過指定ARG一個或多個變數,通過多次指定ARG來定義單個變數。例如,一個有效的Dockerfile

FROM busybox
ARG user1
ARG buildno
...
複製程式碼

Dockerfile作者可以可選地指定ARG指令的預設值:

FROM busybox
ARG user1=someuser
ARG buildno=1
...
複製程式碼

如果ARG值具有預設值,並且如果在構建時沒有傳遞值,則構建器使用預設值。

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

1 FROM busybox
2 USER ${user:-some_user}
3 ARG user
4 USER $user
...
複製程式碼

使用者構建此檔案如下:

$ docker build --build-arg user=what_user Dockerfile
複製程式碼

第2行的USER將評估為some_user,因為使用者變數在後續行3上定義。第4行的USER在定義使用者時估計為what_user,在命令列中傳遞what_user值。在通過ARG指令定義之前,變數的任何使用都將導致空字串。

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

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

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER v1.0.0
4 RUN echo $CONT_IMG_VER
複製程式碼

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

$ docker build --build-arg CONT_IMG_VER=v2.0.1 Dockerfile
複製程式碼

在這種情況下,RUN指令使用v1.0.0而不是使用者傳遞的ARG設定:v2.0.1此行為類似於shell指令碼,其中本地作用域變數覆蓋作為引數傳遞或從環境繼承的變數,從其定義點。

使用上述示例,但使用不同的ENV規範,您可以在ARGENV指令之間建立更有用的互動:

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
4 RUN echo $CONT_IMG_VER
複製程式碼

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

$ docker build Dockerfile
複製程式碼

使用這個Dockerfile示例,CONT_IMG_VER仍然保留在映像中,但它的值將是v1.0.0,因為它是ENV指令在第3行中的預設設定。

此示例中的變數擴充套件技術允許您從命令列傳遞引數,並通過利用ENV指令將它們持久儲存在最終image中。僅對一組有限的Dockerfile指令支援變數擴充套件

Docker有一組預定義的ARG變數,您可以在Dockerfile中使用相應的ARG指令。

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

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

--build-arg <varname>=<value>
複製程式碼

Impact on build caching

ARG變數不會持久化到構建的image中,因為ENV變數是。但是,ARG變數會以類似的方式影響構建快取。如果一個Dockerfile定義一個ARG變數,它的值不同於以前的版本,那麼在它的第一次使用時會出現一個“cache miss”,而不是它的定義。特別地,在ARG指令之後的所有RUN指令都隱式地使用ARG變數(作為環境變數),因此可能導致快取記憶體未命中。

例如,考慮這兩個Dockerfile:

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 RUN echo $CONT_IMG_VER
複製程式碼
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 RUN echo hello
複製程式碼

如果在命令列上指定--build-arg CONT_IMG_VER = <value>,則在這兩種情況下,第2行的規範不會導致快取記憶體未命中;行3確實導致快取記憶體未命中。ARG CONT_IMG_VER導致RUN行被標識為與執行CONT_IMG_VER = <value> echo hello相同,因此如果<value>更改,我們將得到快取記憶體未命中。

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

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER $CONT_IMG_VER
4 RUN echo $CONT_IMG_VER
複製程式碼

在此示例中,快取記憶體未命中發生在第3行。由於變數在ENV中的值引用ARG變數並且該變數通過命令列更改,因此發生了未命中。在此示例中,ENV命令使image包括該值。

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

1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER hello
4 RUN echo $CONT_IMG_VER
複製程式碼

第3行不會導致快取記憶體未命中,因為CONT_IMG_VER的值是一個常量(hello)。因此,RUN(第4行)上使用的環境變數和值在構建之間不會更改。

ONBUILD

ONBUILD [INSTRUCTION]
複製程式碼

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

任何構建指令都可以註冊為trigger。

如果您正在構建將用作構建其他image的基礎的影象,例如應用程式構建環境或可以使用使用者特定配置自定義的後臺駐留程式,這將非常有用。

例如,如果您的image是可重用的Python應用程式構建器,則需要將應用程式原始碼新增到特定目錄中,並且可能需要在此之後呼叫構建指令碼。你不能只是呼叫ADDRUN現在,因為你還沒有訪問應用程式原始碼,它將是不同的每個應用程式構建。您可以簡單地為應用程式開發人員提供一個樣板Dockerfile以將其複製貼上到其應用程式中,但這是低效,容易出錯,並且很難更新,因為它與應用程式特定的程式碼混合。

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

以下是它的工作原理:

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

STOPSIGNAL

STOPSIGNAL signal
複製程式碼

STOPSIGNAL指令設定將傳送到容器以退出的系統呼叫訊號。該訊號可以是與核心系統呼叫表中的位置匹配的有效無符號數,例如9,或者是SIGNAME格式的訊號名稱,例如SIGKILL。

HEALTHCHECK

兩種形式:

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

HEALTHCHECK指令告訴Docker如何測試容器以檢查它是否仍在工作。這可以檢測到諸如Web伺服器被卡在無限迴圈中並且無法處理新連線的情況,即使伺服器程式仍在執行。

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

在CMD之前可以出現的選項有:

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

執行狀況檢查將首先在容器啟動後執行interval秒,然後在每次上次檢查完成後再次執行interval秒。

如果檢查的單次執行所花費的時間超過timeout秒數,則該檢查被認為已失敗。

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

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

CMD關鍵字之後的命令可以是shell命令(例如HEALTHCHECK CMD /bin/check-running)或exec陣列(如同其他Dockerfile命令一樣;詳情參見ENTRYPOINT)。

命令的退出狀態表示容器的執行狀況。 可能的值為:

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

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

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

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

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

HEALTHCHECK功能在Docker 1.12中新增。

SHELL

SHELL ["executable","parameters"]
複製程式碼

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

SHELL指令在Windows上特別有用,其中有兩個常用的和完全不同的本機shell:cmdpowershell,以及包括sh的備用Shell。

SHELL指令可以多次出現。每個SHELL指令覆蓋所有先前的SHELL指令,並影響所有後續指令。 例如:

FROM windowsservercore

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

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

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

# Executed as cmd /S /C echo hello
SHELL ["cmd","/S"","/C"]
RUN echo hello
複製程式碼

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

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

...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...
複製程式碼

docker呼叫的命令將是:

cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
複製程式碼

這是低效的,有兩個原因。首先,有一個不必要的cmd.exe命令處理器(也稱為shell)被呼叫。其次,shell中的每個RUN指令都需要一個額外的powershell -command

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

...
RUN ["powershell","-command","Execute-MyCmdlet","-param1 \"c:\\foo.txt\""]
...
複製程式碼

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

# escape=`

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

結果是:

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


    Directory: C:\


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


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

SHELL指令還可以用於修改外殼操作的方式。例如,在Windows上使用SHELL cmd /S /C /V:ON|OFF,可以修改延遲的環境變數擴充套件語義。

SHELL指令也可以在Linux上使用,如果需要一個替代shell,如zshcshtcsh和其他。

SHELL功能在Docker 1.12中新增。

Dockerfile examples

下面你可以看到一些Dockerfile語法的例子。 如果你對更現實的東西感興趣,可以看看Dockerization的例子。

# Nginx
#
# VERSION               0.0.1

FROM      ubuntu
MAINTAINER Victor Vieux <[email protected]>

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.複製程式碼


Compose file 詳解

Compose file 是一個YAML檔案,用於定義 servicesnetworks, 和 volumes。其預設路徑是./docker-compose.yml

一個service定義包含了這個服務啟動的所有容器的配置,這個操作看起來很像是傳遞命令列引數給docker container create命令。同樣,network和volume定義類似於docker network create 和 docker volume create命令。

與 docker container create 一樣,在Dockerfile中指定的選項(比如:CMD、 EXPOSE、 VOLUME、 ENV等)也是一樣的,你不需要在docker-compose.yml中再次指定它們。

1.1. build

應用於構建時的配置選項

build指定了構建上下文路徑

或者,也可以用一個包含context和可選的dockerfile及args的物件類指定

如果在指定build的同時還指定了image,那麼將會用指定的映象來構建

1.2. context

指向包含Dockerfile目錄的路徑,或者指向git倉庫的url

如果這個值是相對路徑,那麼它相對的是compose file所在的位置(PS:其實就是當前目錄)

1.3. Dockerfile

你也可以用Dockerfile來構建,不過這個時候必須指定context

(PS:dockerfile是用來生成映象的,也就是說構建的時候可以從image構建,也可以從dockerfile構建,是一樣的)

1.4. args

新增構建引數,這些環境變數只能在構建過程中訪問

首先,在Dockerfile中定義變數

然後,在構建的時候給這些變數賦值

或者,下面這種寫法也是可以的

注意:如果在Dockerfile中,ARG在FROM指令之前,那麼在FROM指令下ARG不可用

你也可以在構建引數中省略它們的值,這種情況下會從Compose執行的環境中取值(PS:其實就是環境變數)

1.5. cache_from

快取的映象列表

1.6. shm_size

為這個構建的容器設定/dev/shm分割槽的大小

1.7. configs

授權某個服務可以訪問它下面配置的configs,支援兩種語法

1.7.1. 短語法

短語法只指定config名稱,授權容器可以訪問config,並將其掛載到該容器下的/<config_name>

下面的例子授權redis服務訪問my_config和my_other_config配置。my_config的值設定的是./my_config.txt,而my_other_config的值指定的是外部資源,這就意味著該值已經被定義在Docker中了。

1.7.2. 長語法

長語法提供了更細粒度的控制

  • source :config的名稱
  • target :被掛載到容器後的檔名稱,預設是/<source>
  • uid和gid :被掛載到容器的檔案的所有者和所屬組ID
  • mode :被掛載到容器中的檔案的許可權(PS:如果你不熟悉UNIX的許可權模式,可以用這個工具 permissions-calculator.org

下面這個例子將在容器下設定my_config和redis_config,設定許可權是0440,所有者和所屬組都是103,redis服務不可以訪問my_other_config配置

1.8. container_name

自定義容器名稱,而不是用預設生成的名稱

1.9. depends_on

表示服務之間的依賴關係,服務依賴關係導致以下行為:

  • docker-compose up 按照依賴順序啟動服務
  • docker-compose up SERVICE 自動包含服務的依賴
  • docker-compose stop 按照依賴順序停止服務

下面的例子中,db和redis會先於web啟動,啟動web的時候也會建立並啟動db和redis,web停止之前會先停止db和redis

注意:depends_on不會等待db和redis啟動好了再啟動web

1.10. deploy

只有在叢集方式部署的時候這個配置才有效

1.10.1. mode

global(每個叢集節點只有一個容器) 或者 replicated (指定數量的容器)。預設是 replicated

1.11. env_file

新增一個環境變數檔案,可以是單個值或者一個列表

如果同一個變量出現在多個檔案中,則後者覆蓋前者

1.12. environment

新增一個環境變數,可以覆蓋env_file中同名的變數值

1.13. expose

在不將埠釋出到主機的情況下公開埠

1.14. image

指定容器從哪個映象啟動,可以是映象ID,也可以是映象tag

1.15. network_mode

網路模式

1.16. ports

埠,兩種語法

短語法

長語法

1.17. restart

重啟策略,預設是no

1.18. ulimits

覆蓋容器預設的ulimits

1.19. volumes

掛載主機的路徑或volumes名稱

你可以為單個服務掛載一個主機路徑,這個時候就沒有定義頂級的volumes了。但是,如果你希望多個服務複用一個volumes,那麼這個時候就要定義在頂級了。

短語法

指定主機上的路徑(HOST:CONTAINER),或者一個訪問模式(HOST:CONTAINER:ro)

(PS:稍微解釋一下,比如/opt/data:/var/lib/mysql表示掛載到主機的路徑是/opt/data,掛載到容器的路徑是/var/lib/mysql,其實掛載可以理解為對映)

長語法

  • type :掛載型別(volume, bind,tmpfs)
  • source :掛載的源
  • target :volume被掛載到容器中的路徑
  • read_only :設定只讀
  • propagation :bind的額外選項
  • nocopy :volume的額外選項,表示當volume建立的時候是否禁止從容器上覆制資料
  • size :tmpfs的額外選項,表示掛載的位元組大小

1.20. 指定時長與位元組值

時長支援的單位:us,ms,s,m,h

位元組大小支援的單位:b,k,m,g 或者 b,kb,mb,gb

2. Volume configuration

下面的例子展示了兩個服務,一個資料庫的資料目錄以一個volumn的形式與另一個服務共享,以至於它可以週期性的備份資料:

頂級volumns可以是空的,此時它使用Docker引擎預設提供的驅動(大多數情況下是local)來配置。你也可以指定下列key

3. 示例


4. 參考檔案

docs.docker.com/compose/com…

docs.docker.com/compose/ref…

permissions-calculator.org

yaml.org