注意
目前僅支援八進位表示法。非八進位的支援記錄在 moby/buildkit#1951
COPY [--chown=
從建置上下文複製的所有檔案和目錄都會以 UID 和 GID 為 0 建立,除非選用的 --chown 旗標指定了給定的使用者名稱、群組名稱或 UID/GID 組合,以要求複製內容的特定所有權。--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/
COPY --chown=myuser:mygroup --chmod=644 files* /somedir/如果容器根檔案系統不包含 /etc/passwd 或 /etc/group 檔案,並且在 --chown 旗標中使用了使用者或群組名稱,則建置將會在 COPY 操作時失敗。使用數字 ID 不需要查詢,也不依賴容器根檔案系統的內容。
在 Dockerfile 語法版本 1.10.0 及更高版本中,--chmod 旗標支援變數插值,讓您可以使用建置參數定義權限位元
# syntax=docker/dockerfile:1.10
FROM alpine
WORKDIR /src
ARG MODE=440
COPY --chmod=$MODE . .COPY --link(連結)
COPY [--link[=
使用 --link 時,您的來源檔案會被複製到一個空的目標目錄中。該目錄會變成一個連結到您先前狀態之上的圖層。
# syntax=docker/dockerfile:1
FROM alpine
COPY --link /foo /bar相當於進行兩次建置
FROM alpine以及
FROM scratch
COPY /foo /bar然後將兩個映像檔的所有圖層合併在一起。
使用 --link 的好處使用 --link 可以在後續使用 --cache-from 的建置中重複使用已建置的層,即使先前的層已更改。這對於多階段建置尤其重要,在多階段建置中,如果同一階段中的任何先前指令發生更改,COPY --from 語句先前會失效,導致需要重新建置中間階段。使用 --link,先前建置生成的層將被重複使用並合併到新層之上。這也意味著當基礎映像收到更新時,您可以輕鬆地重新基底化您的映像,而無需再次執行整個建置。在支援它的後端中,BuildKit 可以執行此重新基底化操作,而無需在客戶端和 registry 之間推送或拉取任何層。BuildKit 將會偵測這種情況,並且只建立包含新層和舊層以正確順序排列的新映像清單。
當使用 --link 且沒有其他需要存取基礎映像中檔案的指令時,BuildKit 也可以避免下載基礎映像,其行為與上述相同。在這種情況下,BuildKit 只會建置 COPY 指令的層,並將它們直接推送到 registry 中,放在基礎映像的層之上。
與 --link=false 的不相容性使用 --link 時,不允許 COPY/ADD 指令從先前狀態讀取任何檔案。這表示如果在先前狀態中,目標目錄是包含符號連結的路徑,則 COPY/ADD 無法追蹤它。在最終映像中,使用 --link 建立的目標路徑將始終是僅包含目錄的路徑。
如果您不依賴追蹤目標路徑中符號連結的行為,則始終建議使用 --link。--link 的效能等同於或優於預設行為,並且它為快取重複使用創造了更好的條件。
COPY --parents(保留父目錄結構) 注意
穩定語法中尚不支援,請使用 docker/dockerfile:1.7-labs 版本。
COPY [--parents[=
# syntax=docker/dockerfile:1-labs
FROM scratch
COPY ./x/a.txt ./y/a.txt /no_parents/
COPY --parents ./x/a.txt ./y/a.txt /parents/
# /no_parents/a.txt
# /parents/x/a.txt
# /parents/y/a.txt此行為類似於 Linux cp 工具程式 的 --parents 或 rsync 的 --relative 旗標。
與 Rsync 一樣,可以透過在來源路徑中插入點和斜線 (./) 來限制保留哪些父目錄。如果存在此類點,則只會保留它之後的父目錄。這在使用 --from 在階段之間複製時可能特別有用,其中來源路徑需要是絕對路徑。
# syntax=docker/dockerfile:1-labs
FROM scratch
COPY --parents ./x/./y/*.txt /parents/
# Build context:
# ./x/y/a.txt
# ./x/y/b.txt
#
# Output:
# /parents/y/a.txt
# /parents/y/b.txt請注意,如果未指定 --parents 旗標,任何檔名衝突都會導致 Linux cp 操作失敗並顯示明確的錯誤訊息 (cp: will not overwrite just-created './x/a.txt' with './y/a.txt'),而 Buildkit 將會以靜默方式覆寫目標檔案。
雖然可以為僅包含一個 src 條目的 COPY 指令保留目錄結構,但通常將結果映像中的層數保持盡可能低會更有利。因此,使用 --parents 旗標,Buildkit 能夠將多個 COPY 指令打包在一起,保持目錄結構完整。
COPY --exclude(排除) 注意
穩定語法中尚不支援,請使用 docker/dockerfile:1.7-labs 版本。
COPY [--exclude=
路徑表達式遵循與
# syntax=docker/dockerfile:1-labs
FROM scratch
COPY --exclude=*.txt hom* /mydir/您可以為 COPY 指令多次指定 --exclude 選項。多個 --excludes 表示符合其模式的檔案不會被複製,即使檔案路徑符合
# syntax=docker/dockerfile:1-labs
FROM scratch
COPY --exclude=*.txt --exclude=*.md hom* /mydir/ENTRYPOINT(入口點)ENTRYPOINT 允許您設定將以可執行檔形式執行的容器。
ENTRYPOINT 有兩種可能的格式
exec 格式,這是首選格式
ENTRYPOINT ["executable", "param1", "param2"]shell 格式
ENTRYPOINT command param1 param2有關不同格式的更多資訊,請參閱 Shell 和 exec 格式。
以下指令會從 nginx 啟動一個容器,使用其預設內容,監聽端口 80
$ docker run -i -t --rm -p 80:80 nginx
docker run
這允許將參數傳遞給入口點,例如,docker run
shell 格式的 ENTRYPOINT 會阻止使用任何 CMD 命令列參數。它還會將您的 ENTRYPOINT 作為 /bin/sh -c 的子命令啟動,這不會傳遞信號。這表示可執行檔將不會是容器的 PID 1,並且不會接收 Unix 信號。在這種情況下,您的可執行檔不會從 docker stop
只有 Dockerfile 中最後一個 ENTRYPOINT 指令才會生效。
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(即作為 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 信號
#!/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
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 設定,但这只能設定要執行的二進制檔(不會使用 sh -c)。
Shell 格式 ENTRYPOINT 範例您可以為 ENTRYPOINT 指定一個純文字字串,它將在 /bin/sh -c 中執行。這種形式將使用 shell 處理來替換 shell 環境變數,並且會忽略任何 CMD 或 docker run 命令列參數。為了確保 docker stop 能夠正確地向任何長時間運行的 ENTRYPOINT 可執行檔發送信號,您需要記住使用 exec 來啟動它。
FROM ubuntu
ENTRYPOINT exec top -b當您運行此映像時,您將看到單個 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
如果您忘記在 ENTRYPOINT 的開頭添加 exec
FROM ubuntu
ENTRYPOINT top -b
CMD -- --ignored-param1您可以運行它(為下一步指定一個名稱)
$ docker run -it --name test top --ignored-param2
top - 13:58:24 up 17 min, 0 users, load average: 0.00, 0.00, 0.00
Tasks: 2 total, 1 running, 1 sleeping, 0 stopped, 0 zombie
%Cpu(s): 16.7 us, 33.3 sy, 0.0 ni, 50.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
MiB Mem : 1990.8 total, 1354.6 free, 231.4 used, 404.7 buff/cache
MiB Swap: 1024.0 total, 1024.0 free, 0.0 used. 1639.8 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1 root 20 0 2612 604 536 S 0.0 0.0 0:00.02 sh
6 root 20 0 5956 3188 2768 R 0.0 0.2 0:00.00 top
您可以從 top 的輸出中看到,指定的 ENTRYPOINT 並不是 PID 1。
如果您接著運行 docker stop test,容器將不會乾淨地退出 - stop 命令將在逾時後被迫發送 SIGKILL。
$ docker exec -it test ps waux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.4 0.0 2612 604 pts/0 Ss+ 13:58 0:00 /bin/sh -c top -b --ignored-param2
root 6 0.0 0.1 5956 3188 pts/0 S+ 13:58 0:00 top -b
root 7 0.0 0.1 5884 2816 pts/1 Rs+ 13:58 0:00 ps waux
$ /usr/bin/time docker stop test
test
real 0m 10.19s
user 0m 0.04s
sys 0m 0.03s
了解 CMD 和 ENTRYPOINT 的互動方式CMD 和 ENTRYPOINT 指令都定義了在運行容器時執行的命令。有一些規則描述了它們的合作方式。
Dockerfile 應至少指定 CMD 或 ENTRYPOINT 命令之一。
當將容器用作可執行檔時,應定義 ENTRYPOINT。
CMD 應該用作定義 ENTRYPOINT 命令的預設參數或在容器中執行臨時命令的方式。
當使用其他參數運行容器時,CMD 將被覆蓋。
下表顯示了針對不同的 ENTRYPOINT / CMD 組合執行的命令。
無 ENTRYPOINTENTRYPOINT exec_entry p1_entryENTRYPOINT ["exec_entry", "p1_entry"]無 CMD錯誤,不允許/bin/sh -c exec_entry p1_entryexec_entry p1_entryCMD ["exec_cmd", "p1_cmd"]exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry exec_cmd p1_cmdCMD exec_cmd p1_cmd/bin/sh -c exec_cmd p1_cmd/bin/sh -c exec_entry p1_entryexec_entry p1_entry /bin/sh -c exec_cmd p1_cmd 注意
如果 CMD 是從基礎映像定義的,則設定 ENTRYPOINT 將會把 CMD 重設為空值。在這種情況下,必須在目前的映像中定義 CMD 才能擁有值。
VOLUME(儲存空間)
VOLUME ["/data"]VOLUME 指令會建立一個具有指定名稱的掛載點,並將其標記為持有來自原生主機或其他容器的外部掛載磁碟區。該值可以是一個 JSON 陣列,例如 VOLUME ["/var/log/"],或者是一個具有多個參數的純文字字串,例如 VOLUME /var/log 或 VOLUME /var/log /var/db。更多資訊/範例以及透過 Docker 用戶端進行掛載的說明,請參閱 透過磁碟區共享目錄 文件。
docker run 命令會使用基礎映像中指定位置存在的任何資料來初始化新建立的磁碟區。例如,考慮以下 Dockerfile 程式碼片段
FROM ubuntu
RUN mkdir /myvol
RUN echo "hello world" > /myvol/greeting
VOLUME /myvol此 Dockerfile 會產生一個映像,導致 docker run 在 /myvol 建立一個新的掛載點,並將 greeting 檔案複製到新建立的磁碟區中。
指定儲存空間的注意事項請記住以下關於 Dockerfile 中磁碟區的事項。
**基於 Windows 的容器上的磁碟區**: 使用基於 Windows 的容器時,容器內磁碟區的目標必須是以下其中之一
一個不存在或空的目錄一個不是 C: 的磁碟機**從 Dockerfile 內部變更磁碟區**: 如果任何建置步驟在宣告磁碟區後變更磁碟區內的資料,則使用舊版建置器時,這些變更將會被捨棄。使用 Buildkit 時,這些變更將會被保留。
**JSON 格式**: 列表會被解析為 JSON 陣列。您必須使用雙引號 (") 而不是單引號 (') 將文字括起來。
**主機目錄是在容器運行時宣告的**: 主機目錄(掛載點)的本質是依主機而定。這是為了保持映像的可攜性,因為無法保證所有主機上都存在指定的主機目錄。因此,您無法從 Dockerfile 內部掛載主機目錄。VOLUME 指令不支援指定 host-dir 參數。您必須在建立或運行容器時指定掛載點。
USER(使用者)
USER
USER
請注意,當為使用者指定群組時,該使用者將 *僅* 具有指定的群組成員資格。任何其他設定的群組成員資格都將被忽略。
警告
當使用者沒有主要群組時,映像(或後續指令)將以 root 群組身份運行。
在 Windows 上,如果使用者不是內建帳戶,則必須先建立使用者。這可以使用在 Dockerfile 中呼叫的 net user 命令來完成。
FROM microsoft/windowsservercore
# Create Windows user in the container
RUN net user /add patrick
# Set it for subsequent commands
USER patrickWORKDIR(工作目錄)
WORKDIR /path/to/workdirWORKDIR 指令設定 Dockerfile 中後續任何 RUN、CMD、ENTRYPOINT、COPY 和 ADD 指令的工作目錄。如果 WORKDIR 不存在,即使它未在任何後續的 Dockerfile 指令中使用,也會建立它。
WORKDIR 指令可以在 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此 Dockerfile 中最後一個 pwd 命令的輸出將是 /path/$DIRNAME
如果未指定,預設的工作目錄是 /。實際上,如果您不是從頭開始建置 Dockerfile (FROM scratch),則 WORKDIR 很可能會由您正在使用的基礎映像設定。
因此,為了避免在未知目錄中進行非預期的操作,最佳實務是明確地設定您的 WORKDIR。
ARG(建置參數)
ARG
警告
不建議使用建置參數來傳遞機密資訊,例如使用者憑證、API 令牌等。建置參數會顯示在 docker history 命令和 max 模式來源證明中,如果您使用 Buildx GitHub Actions 且您的 GitHub 儲存庫是公開的,則預設情況下會將這些證明附加到映像。
請參閱 RUN --mount=type=secret 章節,瞭解在建置映像時使用機密的 安全方法。
Dockerfile 可以包含一個或多個 ARG 指令。例如,以下是有效的 Dockerfile
FROM busybox
ARG user1
ARG buildno
# ...預設值ARG 指令可以選擇性地包含預設值
FROM busybox
ARG user1=someuser
ARG buildno=1
# ...如果 ARG 指令具有預設值,並且在建置時沒有傳遞任何值,則建置器會使用預設值。
作用範圍ARG 變數從 Dockerfile 中宣告它的那一行開始生效。例如,考慮這個 Dockerfile
FROM busybox
USER ${username:-some_user}
ARG username
USER $username
# ...使用者透過呼叫以下命令來建置此檔案
$ docker build --build-arg username=what_user .
第 2 行的 USER 指令會評估為 some_user 後備值,因為尚未宣告 username 變數。`username` 變數在第 3 行宣告,並從該點開始可在 Dockerfile 指令中參考。第 4 行的 `USER` 指令會被評估為 `what_user`,因為此時 `username` 參數的值為在命令列中傳遞的 `what_user`。在 `ARG` 指令定義之前,任何變數的使用都會導致空字串。在建置階段中宣告的 `ARG` 變數會自動被基於該階段的其他階段繼承。不相關的建置階段無法存取該變數。要在多個不同的階段中使用參數,每個階段都必須包含 `ARG` 指令,或者它們都必須基於同一個 Dockerfile 中宣告變數的共享基礎階段。
更多資訊,請參閱變數範圍。
使用 ARG 變數您可以使用 `ARG` 或 `ENV` 指令來指定 `RUN` 指令可用的變數。使用 `ENV` 指令定義的環境變數將始終覆蓋同名的 `ARG` 指令。請考慮這個包含 `ENV` 和 `ARG` 指令的 Dockerfile。
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=v1.0.0
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` 規範,您可以建立 `ARG` 和 `ENV` 指令之間更有用的互動
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=${CONT_IMG_VER:-v1.0.0}
RUN echo $CONT_IMG_VER與 `ARG` 指令不同,`ENV` 值始終會保留在建置的映像檔中。考慮一個沒有 `--build-arg` 旗標的 docker build
$ docker build .
使用此 Dockerfile 範例,`CONT_IMG_VER` 仍然保留在映像檔中,但其值將為 `v1.0.0`,因為它是 `ENV` 指令在第 3 行設定的預設值。
此範例中的變數展開技術允許您從命令列傳遞參數,並透過利用 `ENV` 指令將它們保留在最終映像檔中。變數展開僅支援一組有限的 Dockerfile 指令。
預定義 ARGDocker 有一組預定義的 `ARG` 變數,您可以在 Dockerfile 中不使用對應的 `ARG` 指令即可使用它們。
HTTP_PROXYhttp_proxyHTTPS_PROXYhttps_proxyFTP_PROXYftp_proxyNO_PROXYno_proxyALL_PROXYall_proxy要使用這些變數,請使用 `--build-arg` 旗標在命令列中傳遞它們,例如
$ docker build --build-arg HTTPS_PROXY=https://my-proxy.example.com .
預設情況下,這些預定義的變數會從 `docker history` 的輸出中排除。排除它們可以降低在 `HTTP_PROXY` 變數中意外洩露敏感驗證資訊的風險。
例如,考慮使用 `--build-arg HTTP_PROXY=http://user:pass@proxy.lon.example.com` 建置以下 Dockerfile
FROM ubuntu
RUN echo "Hello World"在這種情況下,`HTTP_PROXY` 變數的值在 `docker history` 中不可用,也不會被快取。如果您要更改位置,並且您的代理伺服器更改為 `http://user:pass@proxy.sfo.example.com`,則後續的建置不會導致快取未命中。
如果您需要覆蓋此行為,則可以透過在 Dockerfile 中新增 `ARG` 陳述式來實現,如下所示
FROM ubuntu
ARG HTTP_PROXY
RUN echo "Hello World"建置此 Dockerfile 時,`HTTP_PROXY` 會保留在 `docker history` 中,並且更改其值會使建置快取失效。
全域作用範圍中的自動平台 ARG此功能僅在使用 BuildKit
FROM alpine
ARG TARGETPLATFORM
RUN echo "I'm building for $TARGETPLATFORM"BuildKit 內建建置參數參數類型說明BUILDKIT_CACHE_MOUNT_NS字串設定選用的快取 ID 命名空間。BUILDKIT_CONTEXT_KEEP_GIT_DIR布林值觸發 Git context 以保留 `.git` 目錄。`BUILDKIT_INLINE_CACHE`2布林值是否將快取中繼資料內嵌到映像檔設定中。BUILDKIT_MULTI_PLATFORM布林值選擇是否使用確定性輸出,不論多平台輸出為何。BUILDKIT_SANDBOX_HOSTNAME字串設定主機名稱(預設為 `buildkitsandbox`)BUILDKIT_SYNTAX字串設定前端映像檔SOURCE_DATE_EPOCH整數設定建立的映像檔和圖層的 Unix 時間戳記。更多資訊請參考 可重現建置。Dockerfile 1.5 和 BuildKit 0.11 以後版本皆支援。範例:保留 .git 目錄使用 Git context 時,.git 目錄不會保留在 checkout 中。如果您希望在建置過程中擷取 git 資訊,保留它會很有用。
# syntax=docker/dockerfile:1
FROM alpine
WORKDIR /src
RUN --mount=target=. \
make REVISION=$(git rev-parse HEAD) build
$ docker build --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1 https://github.com/user/repo.git#main
對建置快取的影響ARG 變數不會像 ENV 變數一樣被保存到建置的映像檔中。但是,ARG 變數會以類似的方式影響建置快取。如果 Dockerfile 定義了一個 ARG 變數,其值與先前的建置不同,則在第一次使用它時會發生「快取未命中」,而不是在定義它時。特別是,所有在 ARG 指令之後的 RUN 指令都會隱式地使用 ARG 變數(作為環境變數),因此可能會導致快取未命中。所有預定義的 ARG 變數都免於快取,除非 Dockerfile 中有匹配的 ARG 陳述式。
例如,考慮這兩個 Dockerfile
FROM ubuntu
ARG CONT_IMG_VER
RUN echo $CONT_IMG_VER
FROM ubuntu
ARG CONT_IMG_VER
RUN echo hello如果您在命令列上指定 --build-arg CONT_IMG_VER=
在相同的命令列下考慮另一個範例
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=$CONT_IMG_VER
RUN echo $CONT_IMG_VER在此範例中,快取未命中發生在第 3 行。發生未命中的原因是因為 ENV 中變數的值參考了 ARG 變數,而該變數是透過命令列更改的。在此範例中,ENV 命令會導致映像檔包含該值。
如果 ENV 指令覆蓋了同名的 ARG 指令,例如這個 Dockerfile
FROM ubuntu
ARG CONT_IMG_VER
ENV CONT_IMG_VER=hello
RUN echo $CONT_IMG_VER第 3 行不會導致快取未命中,因為 CONT_IMG_VER 的值是一個常數 (hello)。因此,在 RUN(第 4 行)上使用的環境變數和值在建置之間不會改變。
ONBUILD(建置觸發器)
ONBUILD
如果您正在建置一個將用作基礎來建置其他映像檔的映像檔,例如應用程式建置環境或可以使用使用者特定配置自訂的守護程式,這將會很有用。
例如,如果您的映像檔是一個可重複使用的 Python 應用程式建置器,它將需要將應用程式原始程式碼添加到特定目錄中,並且可能需要在此之後呼叫建置腳本。您現在不能只呼叫 ADD 和 RUN,因為您還沒有存取應用程式原始程式碼的權限,而且每個應用程式建置都會有所不同。您可以簡單地為應用程式開發人員提供一個樣板 Dockerfile 以複製貼上到他們的應用程式中,但這是低效的、容易出錯的,並且難以更新,因為它與應用程式特定的程式碼混合在一起。
解決方案是使用 ONBUILD 來註冊稍後在下一個建置階段執行的預先指令。
以下是它的工作原理
當遇到 ONBUILD 指令時,建置器會將觸發器添加到正在建置的映像檔的詮釋資料中。否則,該指令不會影響目前的建置。在建置結束時,所有觸發器的清單都會儲存在映像檔資訊清單中,位於索引鍵 OnBuild 下。可以使用 docker inspect 命令檢查它們。稍後,可以使用 FROM 指令將映像檔用作新建置的基礎。作為處理 FROM 指令的一部分,下游建置器會尋找 ONBUILD 觸發器,並以它們註冊的相同順序執行它們。如果任何觸發器失敗,FROM 指令將會中止,進而導致建置失敗。如果所有觸發器都成功,則 FROM 指令完成,建置將照常繼續。觸發器在執行後會從最終映像檔中清除。換句話說,它們不會被「孫子」建置繼承。例如,您可以添加如下內容
ONBUILD ADD . /app/src
ONBUILD RUN /usr/local/bin/python-build --dir /app/src從階段、映像檔或上下文複製或掛載從 Dockerfile 語法 1.11 開始,您可以將 ONBUILD 與從其他階段、映像檔或建置上下文複製或掛載檔案的指令一起使用。例如
# syntax=docker/dockerfile:1.11
FROM alpine AS baseimage
ONBUILD COPY --from=build /usr/bin/app /app
ONBUILD RUN --mount=from=config,target=/opt/appconfig ...如果 from 的來源是建置階段,則必須在觸發 ONBUILD 的 Dockerfile 中定義該階段。如果它是具名上下文,則必須將該上下文傳遞到下游建置。
ONBUILD 限制不允許使用 ONBUILD ONBUILD 鏈式 ONBUILD 指令。ONBUILD 指令可能不會觸發 FROM 或 MAINTAINER 指令。STOPSIGNAL(停止訊號)
STOPSIGNAL signalSTOPSIGNAL 指令設定將發送到容器以使其退出的系統呼叫訊號。此訊號可以是 SIG
可以使用 docker run 和 docker create 上的 --stop-signal 旗標,針對每個容器覆蓋映像檔的預設停止訊號。
HEALTHCHECK(健康檢查)HEALTHCHECK 指令有兩種形式
HEALTHCHECK [OPTIONS] CMD command(透過在容器內執行命令來檢查容器健康狀況)HEALTHCHECK NONE(停用從基礎映像檔繼承的任何健康檢查)HEALTHCHECK 指令告訴 Docker 如何測試容器以檢查它是否仍在工作。這可以偵測諸如 Web 伺服器卡在無限迴圈中且無法處理新連線的情況,即使伺服器程序仍在執行。
當容器指定了健康檢查時,除了其正常狀態之外,它還具有健康狀態。此狀態最初為「啟動中」。每當健康檢查通過時,它就會變為「健康」(無論之前的狀態為何)。在一定數量的連續失敗之後,它就會變為「不健康」。
可以出現在 CMD 之前的選項有
--interval=DURATION(預設值:30s)--timeout=DURATION(預設值:30s)--start-period=DURATION(預設值:0s)--start-interval=DURATION (預設值: `5s`)--retries=N(預設值:3)健康檢查將在容器啟動後 **interval** 秒鐘第一次運行,然後在每次先前檢查完成後 **interval** 秒鐘再次運行。
如果單次檢查執行時間超過 **timeout** 秒,則認為檢查失敗。
健康檢查需要連續 **retries** 次失敗,容器才會被視為「不健康」。
啟動期間 (start period) 為需要時間進行啟動的容器提供初始化時間。在此期間,探測失敗次數不會計入最大重試次數。但是,如果在啟動期間健康檢查成功,則容器將被視為已啟動,並且所有後續失敗都將計入最大重試次數。
啟動間隔 (start interval) 是啟動期間健康檢查之間的時間間隔。此選項需要 Docker Engine 25.0 或更高版本。
一個 Dockerfile 中只能有一個 HEALTHCHECK 指令。如果您列出多個,則只有最後一個 HEALTHCHECK 會生效。
CMD 關鍵字後面的命令可以是 shell 命令(例如 HEALTHCHECK CMD /bin/check-running)或 exec 陣列(與其他 Dockerfile 命令一樣;有關詳細資訊,請參閱例如 ENTRYPOINT)。
命令的退出狀態碼指示容器的健康狀態。可能的值為:
0:成功 - 容器健康且可供使用1:不健康 - 容器無法正常工作2:保留 - 請勿使用此退出代碼例如,要大約每五分鐘檢查一次 Web 服務器是否能夠在三秒內提供網站的主頁:
HEALTHCHECK --interval=5m --timeout=3s \
CMD curl -f http://localhost/ || exit 1為了幫助調試失敗的探測,命令在 stdout 或 stderr 上寫入的任何輸出文本(UTF-8 編碼)都將存儲在健康狀態中,並且可以使用 docker inspect 進行查詢。此類輸出應保持簡短(目前僅存儲前 4096 個位元組)。
當容器的健康狀態發生變化時,會生成一個帶有新狀態的 health_status 事件。
SHELL(Shell)
SHELL ["executable", "parameters"]SHELL 指令允許覆蓋 shell 形式的命令所使用的預設 shell。Linux 上的預設 shell 是 ["/bin/sh", "-c"],Windows 上的預設 shell 是 ["cmd", "/S", "/C"]。SHELL 指令必須以 JSON 形式寫入 Dockerfile 中。
SHELL 指令在 Windows 上特別有用,因為 Windows 上有兩個常用的且截然不同的原生 shell:cmd 和 powershell,以及其他可用的 shell,包括 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當在 Dockerfile 中使用 shell 形式時,以下指令會受到 SHELL 指令的影響:RUN、CMD 和 ENTRYPOINT。
以下範例是在 Windows 上找到的常見模式,可以使用 SHELL 指令簡化:
RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt"建構器調用的命令將是:
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:\myproject> 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:\myproject>
SHELL 指令還可以用於修改 shell 的操作方式。例如,在 Windows 上使用 SHELL cmd /S /C /V:ON|OFF,可以修改延遲的環境變數擴展語義。
如果需要替代 shell,例如 zsh、csh、tcsh 等,則也可以在 Linux 上使用 SHELL 指令。
Here-Documents(嵌入式文件)Here-documents 允許將後續的 Dockerfile 行重定向到 RUN 或 COPY 命令的輸入。如果此類命令包含 here-document,Dockerfile 會將直到僅包含 here-doc 分隔符的行視為同一命令的一部分。
範例:執行多行腳本
# syntax=docker/dockerfile:1
FROM debian
RUN < set -ex apt-get update apt-get install -y vim EOT如果命令僅包含 here-document,則其內容將使用預設 shell 進行評估。 # syntax=docker/dockerfile:1 FROM debian RUN < mkdir -p foo/bar EOT或者,可以使用 shebang 標頭來定義直譯器。 # syntax=docker/dockerfile:1 FROM python:3.6 RUN < #!/usr/bin/env python print("hello world") EOT更複雜的範例可能會使用多個 here-documents。 # syntax=docker/dockerfile:1 FROM alpine RUN < I am first FILE1 I am second FILE2範例:建立嵌入式檔案使用 COPY 指令,您可以將來源參數替換為 here-doc 指示符,以將 here-document 的內容直接寫入檔案。以下範例使用 COPY 指令建立一個包含 hello world 的 greeting.txt 檔案。 # syntax=docker/dockerfile:1 FROM alpine COPY < hello world EOF一般的 here-doc 變數展開和Tab鍵去除規則會套用。以下範例顯示了一個小型 Dockerfile,它使用帶有 here-document 的 COPY 指令建立一個 hello.sh 腳本檔案。 # syntax=docker/dockerfile:1 FROM alpine ARG FOO=bar COPY <<-EOT /script.sh echo "hello ${FOO}" EOT ENTRYPOINT ash /script.sh在這種情況下,檔案腳本會印出「hello bar」,因為變數會在執行 COPY 指令時展開。 $ docker build -t heredoc . $ docker run heredoc hello bar 如果您改為引用 here-document 字詞 EOT 的任何部分,則變數在建構時將不會展開。 # syntax=docker/dockerfile:1 FROM alpine ARG FOO=bar COPY <<-"EOT" /script.sh echo "hello ${FOO}" EOT ENTRYPOINT ash /script.sh請注意,這裡的 ARG FOO=bar 是多餘的,可以刪除。變數會在執行時(調用腳本時)被直譯。 $ docker build -t heredoc . $ docker run -e FOO=world heredoc hello world Dockerfile 範例有關 Dockerfile 的範例,請參閱: 建構最佳實務頁面「入門」教學特定語言的入門指南必填值 ↩︎ ↩︎ ↩︎ 適用於 Docker 整合的 BuildKit 和 docker buildx build ↩︎ 要求變更 目錄概觀格式剖析器指令語法跳脫字元檢查環境變數替換.dockerignore 檔案Shell 和 exec 格式Exec 格式Shell 格式使用不同的 ShellFROM(來源映像檔)了解 ARG 和 FROM 的互動方式RUN(執行指令)RUN 指令的快取失效RUN --mount(掛載)RUN --mount=type=bind(繫結掛載)RUN --mount=type=cache(快取掛載)RUN --mount=type=tmpfs(記憶體檔案系統掛載)RUN --mount=type=secret(密鑰掛載)RUN --mount=type=ssh(SSH 掛載)RUN --network(網路)RUN --network=default(預設網路)RUN --network=none(無網路)RUN --network=host(主機網路)RUN --security(安全性)CMD(預設指令)LABEL(標籤)MAINTAINER(維護者)(已棄用)EXPOSE(暴露埠口)ENV(環境變數)ADD(新增檔案)來源目的地ADD --keep-git-dir(保留 Git 目錄)ADD --checksum(檢查碼)ADD --chown --chmod(變更擁有者和權限)ADD --link(連結)ADD --exclude(排除)COPY(複製檔案)來源目的地COPY --from(從階段複製)COPY --chown --chmod(變更擁有者和權限)COPY --link(連結)COPY --parents(保留父目錄結構)COPY --exclude(排除)ENTRYPOINT(入口點)Exec 格式 ENTRYPOINT 範例Shell 格式 ENTRYPOINT 範例了解 CMD 和 ENTRYPOINT 的互動方式VOLUME(儲存空間)指定儲存空間的注意事項USER(使用者)WORKDIR(工作目錄)ARG(建置參數)預設值作用範圍使用 ARG 變數預定義 ARG全域作用範圍中的自動平台 ARGBuildKit 內建建置參數對建置快取的影響ONBUILD(建置觸發器)從階段、映像檔或上下文複製或掛載ONBUILD 限制STOPSIGNAL(停止訊號)HEALTHCHECK(健康檢查)SHELL(Shell)Here-Documents(嵌入式文件)範例:執行多行腳本範例:建立嵌入式檔案Dockerfile 範例