Dockerfile、Docker Compose file 參考檔案
Dockerfile
Dockerfile
是由一系列命令和引數構成的指令碼,一個Dockerfile
裡麵包含了構建整個image
的完整命令。Docker通過docker build
執行Dockerfile
中的一系列命令自動構建image
。
Dockerfile
其語法非常簡單,此頁面描述了您可以在Dockerfile中使用的命令。 閱讀此頁面後,你可以參閱Dockerfile最佳實踐。
Usage
docker build
命令從Dockerfile
和context
構建image。context
是PATH
或URL
處的檔案。PATH
本地檔案目錄。 URL
是Git repository的位置。
context
PATH
包括任何子目錄,URL
包括repository及submodules。一個使用當前目錄作為context
的簡單構建命令:
$ docker build .
Sending build context to Docker daemon 6.51 MB
...
複製程式碼
構建由Docker守護程式執行,而不是由CLI執行。構建過程所做的第一件事是將整個context(遞迴地)傳送給守護程式。大多數情況下,最好是將Dockerfile
和所需檔案複製到一個空的目錄,再到這個目錄進行構建。
警告
:不要使用根目錄/
作為PATH,因為它會導致構建將硬碟驅動器的所有內容傳輸到Docker守護程式。
build時新增檔案,通過Dockerfile
引用指令中指定的檔案,例如COPY
指令。要增加構建的效能,請通過將.dockerignore
檔案新增到context
目錄中來排除檔案和目錄。有關如何建立.dockerignore檔案的資訊,請參閱此頁上的檔案。
一般的,Dockerfile
位於context
的根中。但使用-f
標誌可指定Dockerfile的位置。
$ docker build -f /path/to/a/Dockerfile .
複製程式碼
如果build成功,您可以指定要儲存新image的repository和tag:
$ docker build -t shykes/myapp .
複製程式碼
要在構建後將image標記為多個repositories,請在執行構建命令時新增多個-t
引數:
$ docker build -t shykes/myapp:1.0.2 -t shykes/myapp:latest .
複製程式碼
Docker守護程式一個接一個地執行Dockerfile
中的指令,如果需要,將每個指令的結果提交到一個新image,最後輸出新映像的ID。Docker守護程式將自動清理您傳送的context。
請注意,每個指令獨立執行,並導致建立一個新image - 因此RUN cd / tmp
對下一個指令不會有任何影響。
只要有可能,Docker將重新使用中間images(快取),以顯著加速docker build
過程。這由控制檯輸出中的使用快取訊息指示。(有關詳細資訊,請參閱Dockerfile
最佳實踐指南構建快取部分):
$ docker build -t svendowideit/ambassador .
Sending build context to Docker daemon 15.36 kB
Step 1 : FROM alpine:3.2
---> 31f630c65071
Step 2 : MAINTAINER [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
,因為它不是設定abc
為bye
的相同命令的一部分。
.dockerignore file
在docker CLI將上下文傳送到docker守護程式之前,它會在上下文的根目錄中查詢名為.dockerignore
的檔案。如果此檔案存在,CLI將修改上下文以排除匹配其中模式的檔案和目錄。這有助於避免不必要地向守護程式傳送大型或敏感檔案和目錄,並可能使用ADD
或COPY
將其新增到映像。
CLI將.dockerignore
檔案解釋為換行符分隔的模式列表,類似於Unix shell
的file globs。為了匹配的目的,上下文的根被認為是工作目錄和根目錄。例如,模式/foo/bar
和foo/bar
都排除了PATH
的foo
子目錄中的名為bar
的檔案或目錄,或者位於URL
處的git repository的根目錄中。也不排除任何其他。
如果.dockerignore
檔案中的一行以第1列中以#
開頭,則此行被視為註釋,並在CLI解釋之前被忽略。
這裡是一個例子.dockerignore
檔案:
# comment
*/temp*
*/*/temp*
temp?
複製程式碼
此檔案導致以下構建行為:
規則 | 行為 |
---|---|
# comment |
忽略 |
*/temp* |
在根的任何直接子目錄中排除其名稱以temp開頭的檔案和目錄。 例如,普通檔案/somedir/temporary.txt被排除,目錄/somedir/temp也被排除。 |
*/*/temp* |
從根目錄下兩級的任何子目錄中排除以temp開頭的檔案和目錄。 例如,排除了/somedir/subdir/temporary.txt。 |
temp? |
排除根目錄中名稱為temp的單字元副檔名的檔案和目錄。 例如,/tempa和/tempb被排除。 |
匹配是使用Go的filepath.Match規則完成的。 預處理步驟刪除前導和尾隨空格並消除.
和..
元素使用Go的filepath.Clean。預處理後為空的行將被忽略。
除了Go的filepath.Match規則,Docker還支援一個特殊的萬用字元字串**
,它匹配任何數量的目錄(包括零)。 例如,**/*.go
將排除所有目錄中找到的以.go
結尾的所有檔案,包括構建上下文的根。
行開頭!
(感嘆號)可用於排除例外。 以下是使用此機制的.dockerignore
檔案示例:
*.md
!README.md
複製程式碼
除了README.md
之外的所有markdown檔案都從上下文中排除。
放置!
異常規則影響行為:匹配特定檔案的.dockerignore
的最後一行確定它是包括還是排除。思考下面的例子:
*.md
!README*.md
README-secret.md
複製程式碼
除了README-secret.md
之外的README
檔案,上下文中排除所有markdown檔案。
現在思考這個例子:
*.md
README-secret.md
!README*.md
複製程式碼
包括所有README檔案。 中間行沒有效果,因為最後的!README*.md
與README-secret.md
匹配。
您甚至可以使用.dockerignore
檔案來排除Dockerfile
和.dockerignore
檔案。這些檔案仍然傳送到守護程式,因為它需要它們來完成它的工作。但是ADD
和COPY
命令不會將它們複製到映像。
最後,您可能需要指定要包括在上下文中的檔案,而不是要排除的檔案。 要實現這一點,指定*
作為第一個模式,後面跟一個或多個!
異常模式。
注意
:由於歷史原因.
模式。被忽略。
FROM
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。 -
tag
或digest
是可選的。如果省略其中任何一個,構建器將預設使用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
指令。
注意
:如果使用CMD
為ENTRYPOINT
指令提供預設引數,CMD
和ENTRYPOINT
指令都應以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
中指定的預設值。
注意
:不要將RUN
和CMD
混淆。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"
複製程式碼
標籤是新增的,包括LABEL
在FROM
images中。如果Docker遇到已經存在的label/key,則新值將覆蓋具有相同鍵的任何先前標籤。
要檢視image的labels,請使用docker inspect
命令。
"Labels": {
"com.example.vendor": "ACME Incorporated"
"com.example.label-with-value": "foo","version": "1.0","description": "This text illustrates that label-values can span multiple lines.","multi.label1": "value1","multi.label2": "value2","other": "value3"
},複製程式碼
EXPOSE
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 wget
,RUN curl
或從容器內使用其他工具,因為ADD指令不支援身份驗證。
注意
:如果<src>
的內容已更改,第一個遇到的ADD
指令將使來自Dockerfile
的所有後續指令的快取記憶體無效。這包括使用於RUN指令的快取記憶體無效。有關詳細資訊,請參閱Dockerfile最佳實踐指南。
ADD
遵守以下規則:
-
<src>
路徑必須在構建的上下文中;你不能ADD ../something /something
,因為docker構建的第一步是傳送上下文目錄(和子目錄)到docker守護程式。如果<src>
是URL並且<dest>
不以尾部斜槓結尾,則從URL下載檔案並將其複製到<dest>
。 - 如果
<src>
是URL並且<dest>
以尾部斜槓結尾,則從URL中推斷檔名,並將檔案下載到<dest>/<filename>
。例如,ADD http://example.com/foobar /
會建立檔案/ foobar
。網址必須有一個非平凡的路徑,以便在這種情況下可以發現一個適當的檔名(http://example.com
不會工作)。 - 如果
<src>
是目錄,則複製目錄的整個內容,包括檔案系統元資料。
注意
:目錄本身不被複制,只是其內容。
- 如果
<src>
是識別的壓縮格式(identity,gzip,bzip2或xz)的本地tar存檔,則將其解包為目錄。來自遠端URL的資源不會解壓縮。當目錄被複制或解壓縮時,它具有與tar -x
相同的行為:結果是以下的聯合:- 無論在目的地路徑和
- 源樹的內容,衝突以逐個檔案為基礎解析為“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>
的命令列引數將附跟在
ENTRYPOINT
中的所有元素之後,並將覆蓋使用CMD
指定的所有元素。這允許將引數傳遞到入口點,即docker run <image> -d
將把-d
引數傳遞給入口點。您可以使用docker run --entrypoint
標誌覆蓋ENTRYPOINT
指令。
shell 形式防止使用任何CMD
或執行命令列引數,但是缺點是您的ENTRYPOINT
將作/bin/sh -c
的子命令啟動,它不傳遞訊號。這意味著可執行檔案將不是容器的PID 1
,並且不會接收Unix訊號,因此您的可執行檔案將不會從docker stop <container>
接收到SIGTERM
。
只有Dockerfile
中最後一個ENTRYPOINT
指令會有效果。
Exec form ENTRYPOINT example
您可以使用ENTRYPOINT
的*exec*形式設定相當穩定的預設命令和引數,然後使用任一形式的CMD
設定更可能更改的其他預設值。
FROM ubuntu
ENTRYPOINT ["top","-b"]
CMD ["-c"]
複製程式碼
執行容器時,您可以看到top是唯一的程式:
$ docker run -it --rm --name test top -H
top - 08:25:00 up 7:27,0 users,load average: 0.00,0.01,0.05
Threads: 1 total,1 running,0 sleeping,0 stopped,0 zombie
%Cpu(s): 0.1 us,0.1 sy,0.0 ni,99.7 id,0.0 wa,0.0 hi,0.0 si,0.0 st
KiB Mem: 2056668 total,1616832 used,439836 free,99352 buffers
KiB Swap: 1441840 total,0 used,1441840 free. 1324440 cached Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 19744 2336 2080 R 0.0 0.1 0:00.04 top
複製程式碼
要進一步檢查結果,可以使用docker exec
:
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 2.6 0.1 19752 2352 ? Ss+ 08:24 0:00 top -b -H
root 7 0.0 0.1 15572 2164 ? R+ 08:25 0:00 ps aux
複製程式碼
並且你可以優雅地請求top
使用docker stop test
關閉。
以下Dockerfile
顯示使用ENTRYPOINT
在前臺執行Apache
(即,作為PID 1
):
FROM debian:stable
RUN apt-get update && apt-get install -y --force-yes apache2
EXPOSE 80 443
VOLUME ["/var/www","/var/log/apache2","/etc/apache2"]
ENTRYPOINT ["/usr/sbin/apache2ctl","-D","FOREGROUND"]
複製程式碼
如果需要為單個可執行檔案編寫啟動指令碼,可以使用exec
和gosu
命令確保最終可執行檔案接收到Unix訊號:
#!/bin/bash
set -e
if [ "$1" = 'postgres' ]; then
chown -R postgres "$PGDATA"
if [ -z "$(ls -A "$PGDATA")" ]; then
gosu postgres initdb
fi
exec gosu postgres "$@"
fi
exec "$@"
複製程式碼
最後,如果需要在關閉時進行一些額外的清理(或與其他容器通訊),或者協調多個可執行檔案,您可能需要確保ENTRYPOINT
指令碼接收到Unix訊號,傳遞它們,然後做一些更多的工作:
#!/bin/sh
# Note: I've written this using sh so it works in the busybox container too
# USE the trap if you need to also do manual cleanup after the service is stopped,
# or need to start multiple services in the one container
trap "echo TRAPed signal" HUP INT QUIT TERM
# start service in background here
/usr/sbin/apachectl start
echo "[hit enter key to exit] or run 'docker stop <container>'"
read
# stop service and clean up here
echo "stopping apache"
/usr/sbin/apachectl stop
echo "exited $0"
複製程式碼
如果你用docker run -it --rm -p 80:80 --name test apache
執行image,則可以使用·docker exec·或·docker top·檢查容器的程式,然後請求指令碼停止Apache:
$ docker exec -it test ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.1 0.0 4448 692 ? Ss+ 00:42 0:00 /bin/sh /run.sh 123 cmd cmd2
root 19 0.0 0.2 71304 4440 ? Ss 00:42 0:00 /usr/sbin/apache2 -k start
www-data 20 0.2 0.2 360468 6004 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
www-data 21 0.2 0.2 360468 6000 ? Sl 00:42 0:00 /usr/sbin/apache2 -k start
root 81 0.0 0.1 15572 2140 ? R+ 00:44 0:00 ps aux
$ docker top test
PID USER COMMAND
10035 root {run.sh} /bin/sh /run.sh 123 cmd cmd2
10054 root /usr/sbin/apache2 -k start
10055 33 /usr/sbin/apache2 -k start
10056 33 /usr/sbin/apache2 -k start
$ /usr/bin/time docker stop test
test
real 0m 0.27s
user 0m 0.03s
sys 0m 0.03s
複製程式碼
注意
:您可以使用--entrypoint
覆蓋ENTRYPOINT
設定,但這隻能將二進位制設定為*exec*(不使用sh -c
)。
注意
:*exec*形式作為JSON陣列解析,這意味著您必須在單詞之外使用雙引號(”)而不是單引號(’)。
注意
:與shell
形式不同,*exec*形式不呼叫命令shell。這意味著正常的shell處理不會發生。例如,ENTRYPOINT ["echo","$ HOME"]
不會在$HOME
上進行可變替換。如果你想要shell處理,那麼使用shell形式或直接執行一個shell,例如:ENTRYPOINT ["sh","echo $HOME"]
。當使用exec形式並直接執行shell時,正如shell形式的情況,它是做環境變數擴充套件的shell,而不是docker。
Shell form ENTRYPOINT example
您可以為ENTRYPOINT
指定一個純字串,它將在/bin/sh -c
中執行。這中形式將使用shell處理來替換shell環境變數,並且將忽略任何CMD
或docker run
命令列引數。要確保docker stop
將正確地發出任何長時間執行的ENTRYPOINT
可執行檔案,您需要記住用exec
啟動它:
FROM ubuntu
ENTRYPOINT exec top -b
複製程式碼
執行此image時,您將看到單個PID 1
程式:
$ docker run -it --rm --name test top
Mem: 1704520K used,352148K free,0K shrd,0K buff,140368121167873K cached
CPU: 5% usr 0% sys 0% nic 94% idle 0% io 0% irq 0% sirq
Load average: 0.08 0.03 0.05 2/98 6
PID PPID USER STAT VSZ %VSZ %CPU COMMAND
1 0 root R 3164 0% 0% top -b
複製程式碼
它獎在docker stop
乾淨的退出:
$ /usr/bin/time docker stop test
test
real 0m 0.20s
user 0m 0.02s
sys 0m 0.04s
複製程式碼
如果忘記將exec
新增到您的ENTRYPOINT
的開頭:
FROM ubuntu
ENTRYPOINT top -b
CMD --ignored-param1
複製程式碼
然後,您可以執行它(給它一個名稱為下一步):
$ docker run -it --name test top --ignored-param2
Mem: 1704184K used,352484K free,140621524238337K cached
CPU: 9% usr 2% sys 0% nic 88% idle 0% io 0% irq 0% sirq
Load average: 0.01 0.02 0.05 2/101 7
PID PPID USER STAT VSZ %VSZ %CPU COMMAND
1 0 root S 3168 0% 0% /bin/sh -c top -b cmd cmd2
7 1 root R 3164 0% 0% top -b
複製程式碼
您可以從top的輸出中看到指定的ENTRYPOINT不是PID 1。
如果你然後執行docker停止測試,容器將不會完全退出 - 停止命令將強制傳送SIGKILL超時後:
$ docker exec -it test ps aux
PID USER COMMAND
1 root /bin/sh -c top -b cmd cmd2
7 root top -b
8 root ps aux
$ /usr/bin/time docker stop test
test
real 0m 10.19s
user 0m 0.04s
sys 0m 0.03s
複製程式碼
Understand how CMD and ENTRYPOINT interact
CMD
和ENTRYPOINT
指令定義在執行容器時執行什麼命令。這裡有較少的規則描述他們的合作。
-
Dockerfile
應該至少指定一個CMD
或ENTRYPOINT
命令。 - 當使用容器作為可執行檔案時,應該定義
ENTRYPOINT
。 -
CMD
應該用作定義ENTRYPOINT
命令的預設引數或在容器中執行ad-hoc命令的一種方法。 - 當執行帶有替代引數的容器時,
CMD
將被覆蓋。
下表顯示了對不同ENTRYPOINT
/CMD
組合執行的命令:
no ENTRYPOINT | ENTRYPOINT exec_enty p1_entry | ENTRYPOINT [“exec_entry”,“p1_entry”] | |
---|---|---|---|
No CMD | error,not allowed | /bin/sh -c exec_entry p1_entry | exec_entry p1_entry |
CMD [“exec_cmd”,“p1_cmd”] | exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry exec_cmd p1_cmd | exec_entry p1_entry exec_cmd p1_cmd |
CMD [“p1_cmd”,“p2_cmd”] | p1_cmd p2_cmd | /bin/sh -c exec_entry p1_entry p1_cmd p2_cmd | exec_entry p1_entry p1_cmd p2_cmd |
CMD exec_cmd p1_cmd | /bin/sh -c exec_cmd p1_cmd | /bin/sh -c exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd | exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd |
VOLUME
VOLUME ["/data"]
複製程式碼
VOLUME
指令建立具有指定名稱的掛載點,並將其標記為從本機主機或其他容器保留外部掛載的卷。該值可以是JSON陣列VOLUME ["/var/log/"]
或具有多個引數的純字串,例如VOLUME /var/log
或VOLUME /var/log /var/db
。有關通過Docker客戶端的更多資訊/示例和安裝說明,請參閱通過卷檔案共享目錄。
docker run
命令用存在於基本image中指定位置的任何資料初始化新建立的卷。例如,思考以下Dockerfile
片段:
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol
複製程式碼
此Dockerfile docker run
的映像,在/myvol
上建立一個新的掛載點,並將greeting
檔案複製到新建立的卷中。
注意
:如果任何構建步驟在宣告後更改卷中的資料,那麼這些更改將被丟棄。
注意
:該列表解析為JSON陣列,這意味著您必須在單詞之外使用雙引號(”)而不是單引號(’)。
USER
USER daemon
複製程式碼
USER
指令設定執行image時使用的使用者名稱或UID,以及Dockerfile
中的任何RUN,CMD
和ENTRYPOINT
指令。
WORKDIR
WORKDIR /path/to/workdir
複製程式碼
WORKDIR
指令為Dockerfile
中的任何RUN
,CMD
,ENTRYPOINT
,COPY
和ADD
指令設定工作目錄。如果WORKDIR
不存在,它將被建立,即使它沒有在任何後續的Dockerfile
指令中使用。
它可以在一個Dockerfile
中多次使用。如果提供了相對路徑,它將相對於先前WORKDIR指令的路徑。 例如:
WORKDIR /a
WORKDIR b
WORKDIR c
RUN pwd
複製程式碼
在這個Dockerfile
中的最終pwd
命令的輸出是/a/b/c
。
WORKDIR
指令可以解析先前使用ENV
設定的環境變數。您只能使用在Dockerfile
中顯式設定的環境變數。 例如:
ENV DIRPATH /path
WORKDIR $DIRPATH/$DIRNAME
RUN pwd
複製程式碼
pwd
命令在該Dockerfile
中輸出的最後結果是/path/$DIRNAME
。
ARG
ARG <name>[=<default value>]
複製程式碼
ARG
指令定義一個變數,使用者可以使用docker build
命令使用--build-arg <varname> = <value>
標誌,在構建時將其傳遞給構建器。如果使用者指定了一個未在Dockerfile
中定義的構建引數,構建將輸出錯誤。
One or more build-args were not consumed,failing build.
複製程式碼
Dockerfile作者可以通過指定ARG
一個或多個變數,通過多次指定ARG
來定義單個變數。例如,一個有效的Dockerfile
:
FROM busybox
ARG user1
ARG buildno
...
複製程式碼
Dockerfile作者可以可選地指定ARG
指令的預設值:
FROM busybox
ARG user1=someuser
ARG buildno=1
...
複製程式碼
如果ARG
值具有預設值,並且如果在構建時沒有傳遞值,則構建器使用預設值。
ARG
變數定義從在Dockerfile
中定義的行開始生效,而不是從命令列或其他地方的引數使用。例如,考慮這個Dockerfile:
1 FROM busybox
2 USER ${user:-some_user}
3 ARG user
4 USER $user
...
複製程式碼
使用者構建此檔案如下:
$ docker build --build-arg user=what_user Dockerfile
複製程式碼
第2行的USER
將評估為some_user
,因為使用者變數在後續行3上定義。第4行的USER
在定義使用者時估計為what_user
,在命令列中傳遞what_user
值。在通過ARG
指令定義之前,變數的任何使用都將導致空字串。
警告
:不建議使用build-time變數來傳遞諸如github金鑰,使用者憑證等密碼。構建時變數值使用docker history
命令對影象的任何使用者可見。
可以使用ARG
或ENV
指令來指定RUN
指令可用的變數。使用ENV
指令定義的環境變數總是覆蓋同名的ARG
指令。思考這個Dockerfile
帶有ENV
和ARG
指令。
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER v1.0.0
4 RUN echo $CONT_IMG_VER
複製程式碼
然後,假設此image是使用此命令構建的:
$ docker build --build-arg CONT_IMG_VER=v2.0.1 Dockerfile
複製程式碼
在這種情況下,RUN
指令使用v1.0.0
而不是使用者傳遞的ARG
設定:v2.0.1
此行為類似於shell指令碼,其中本地作用域變數覆蓋作為引數傳遞或從環境繼承的變數,從其定義點。
使用上述示例,但使用不同的ENV
規範,您可以在ARG
和ENV
指令之間建立更有用的互動:
1 FROM ubuntu
2 ARG CONT_IMG_VER
3 ENV CONT_IMG_VER ${CONT_IMG_VER:-v1.0.0}
4 RUN echo $CONT_IMG_VER
複製程式碼
與ARG
指令不同,ENV
值始終保留在image中。考慮一個沒有-build-arg
標誌的docker構建:
$ docker build Dockerfile
複製程式碼
使用這個Dockerfile示例,CONT_IMG_VER
仍然保留在映像中,但它的值將是v1.0.0
,因為它是ENV
指令在第3行中的預設設定。
此示例中的變數擴充套件技術允許您從命令列傳遞引數,並通過利用ENV
指令將它們持久儲存在最終image中。僅對一組有限的Dockerfile指令支援變數擴充套件。
Docker有一組預定義的ARG
變數,您可以在Dockerfile中使用相應的ARG指令。
- 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應用程式構建器,則需要將應用程式原始碼新增到特定目錄中,並且可能需要在此之後呼叫構建指令碼。你不能只是呼叫ADD
和RUN
現在,因為你還沒有訪問應用程式原始碼,它將是不同的每個應用程式構建。您可以簡單地為應用程式開發人員提供一個樣板Dockerfile以將其複製貼上到其應用程式中,但這是低效,容易出錯,並且很難更新,因為它與應用程式特定的程式碼混合。
解決方案是使用ONBUILD
來註冊提前指令,以便稍後在下一個構建階段執行。
以下是它的工作原理:
- 當遇到
ONBUILD
指令時,構建器會向正在構建的image的元資料新增trigger。該指令不會另外影響當前構建。 - 在構建結束時,所有trigger的列表儲存在image清單中的OnBuild鍵下。可以使用
docker inspect
命令檢查它們。 - 稍後,可以使用
FROM
指令將image用作新構建的基礎。作為處理FROM
指令的一部分,下游構建器會查詢ONBUILD
triggers,並按照它們註冊的順序執行它們。如果任何觸發器失敗,則FROM
指令中止,這又導致構建失敗。如果所有觸發器都成功,則FROM
指令完成並且構建如常繼續。觸發器在執行後從最終image中清除。換句話說,它們不會被“grand-children”構建繼承。 例如,您可以新增如下:[...] ONBUILD ADD . /app/src ONBUILD RUN /usr/local/bin/python-build --dir /app/src [...]
>警告
:不允許使用ONBUILD ONBUILD
連結ONBUILD
指令。 >警告
:ONBUILD
指令可能不會觸發FROM
或MAINTAINER
指令。
STOPSIGNAL
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:cmd
和powershell
,以及包括sh
的備用Shell。
SHELL
指令可以多次出現。每個SHELL
指令覆蓋所有先前的SHELL
指令,並影響所有後續指令。 例如:
FROM windowsservercore
# Executed as cmd /S /C echo default
RUN echo default
# Executed as cmd /S /C powershell -command Write-Host default
RUN powershell -command Write-Host default
# Executed as powershell -command Write-Host hello
SHELL ["powershell","-command"]
RUN Write-Host hello
# Executed as cmd /S /C echo hello
SHELL ["cmd","/S"","/C"]
RUN echo hello
複製程式碼
以下指令可能受SHELL
指令的影響,當它們的shell形式用於Dockerfile:RUN
,CMD
和ENTRYPOINT
。
以下示例是Windows上的常見模式,可以使用SHELL指令進行簡化:
...
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
...
複製程式碼
docker呼叫的命令將是:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"
複製程式碼
這是低效的,有兩個原因。首先,有一個不必要的cmd.exe命令處理器(也稱為shell)被呼叫。其次,shell中的每個RUN
指令都需要一個額外的powershell -command
。
為了更有效率,可以採用兩種機制之一。 一種是使用JSON形式的RUN命令,如:
...
RUN ["powershell","-command","Execute-MyCmdlet","-param1 \"c:\\foo.txt\""]
...
複製程式碼
雖然JSON形式是明確的,並且不使用不必要的cmd.exe,但它需要通過雙引號和轉義更詳細。 備用機制是使用SHELL
指令和shell形式,為Windows使用者提供更自然的語法,特別是與escape
解析指令結合使用時:
# escape=`
FROM windowsservercore
SHELL ["powershell","-command"]
RUN New-Item -ItemType Directory C:\Example
ADD Execute-MyCmdlet.ps1 c:\example\
RUN c:\example\Execute-MyCmdlet -sample 'hello world'
複製程式碼
結果是:
PS E:\docker\build\shell> docker build -t shell .
Sending build context to Docker daemon 3.584 kB
Step 1 : FROM windowsservercore
---> 5bc36a335344
Step 2 : SHELL powershell -command
---> Running in 87d7a64c9751
---> 4327358436c1
Removing intermediate container 87d7a64c9751
Step 3 : RUN New-Item -ItemType Directory C:\Example
---> Running in 3e6ba16b8df9
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 6/2/2016 2:59 PM Example
---> 1f1dfdcec085
Removing intermediate container 3e6ba16b8df9
Step 4 : ADD Execute-MyCmdlet.ps1 c:\example\
---> 6770b4c17f29
Removing intermediate container b139e34291dc
Step 5 : RUN c:\example\Execute-MyCmdlet -sample 'hello world'
---> Running in abdcf50dfd1f
Hello from Execute-MyCmdlet.ps1 - passed hello world
---> ba0e25255fda
Removing intermediate container abdcf50dfd1f
Successfully built ba0e25255fda
PS E:\docker\build\shell>
複製程式碼
SHELL
指令還可以用於修改外殼操作的方式。例如,在Windows上使用SHELL cmd /S /C /V:ON|OFF
,可以修改延遲的環境變數擴充套件語義。
SHELL
指令也可以在Linux上使用,如果需要一個替代shell,如zsh
,csh
,tcsh
和其他。
SHELL
功能在Docker 1.12中新增。
Dockerfile 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檔案,用於定義 services, networks, 和 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. 參考檔案