建置環境

docker builddocker buildx build 指令會從 Dockerfile 和情境建置 Docker 映像檔。

什麼是建置情境?

建置情境是您的建置可以存取的一組檔案。您傳遞給建置指令的定位引數會指定您想用於建置的情境。

$ docker build [OPTIONS] PATH | URL | -
                         ^^^^^^^^^^^^^^

您可以傳遞以下任何輸入作為建置情境

  • 本機目錄的相對路徑或絕對路徑
  • Git 儲存庫、tar 壓縮檔或純文字檔的遠端 URL
  • 透過標準輸入傳輸到 docker build 指令的純文字檔或 tar 壓縮檔

檔案系統情境

當您的建置情境是本機目錄、遠端 Git 儲存庫或 tar 檔案時,這些檔案會成為建置器在建置期間可以存取的一組檔案。建置指令(例如 COPYADD)可以參照情境中的任何檔案和目錄。

檔案系統建置情境會遞迴處理

  • 當您指定本機目錄或 tar 壓縮檔時,所有子目錄都會包含在內
  • 當您指定遠端 Git 儲存庫時,該儲存庫和所有子模組都會包含在內

有關您可以與建置搭配使用的不同檔案系統情境類型的更多資訊,請參閱

文字檔情境

當您的建置情境是純文字檔時,建置器會將該檔案解釋為 Dockerfile。透過這種方法,建置不會使用檔案系統情境。

有關更多資訊,請參閱空建置情境

本機情境

若要使用本機建置情境,您可以向 docker build 指令指定相對或絕對檔案路徑。以下範例顯示了一個使用目前目錄 (.) 作為建置情境的建置指令

$ docker build .
...
#16 [internal] load build context
#16 sha256:23ca2f94460dcbaf5b3c3edbaaa933281a4e0ea3d92fe295193e4df44dc68f85
#16 transferring context: 13.16MB 2.2s done
...

這使得目前工作目錄中的檔案和目錄可供建置器使用。建置器會在需要時從建置情境載入其所需的檔案。

您也可以將本機 tar 壓縮檔的內容透過管道傳輸到 docker build 指令,以將其用作建置情境。請參閱tar 壓縮檔

本機目錄

考慮以下目錄結構

.
├── index.ts
├── src/
├── Dockerfile
├── package.json
└── package-lock.json

如果您將此目錄作為情境傳遞,Dockerfile 指令可以在建置中參照並包含這些檔案。

# syntax=docker/dockerfile:1
FROM node:latest
WORKDIR /src
COPY package.json package-lock.json .
RUN npm ci
COPY index.ts src .
$ docker build .

透過標準輸入 (stdin) 使用 Dockerfile 的本機情境

使用以下語法,利用本機檔案系統上的檔案來建置映像檔,同時從標準輸入 (stdin) 使用 Dockerfile。

$ docker build -f- <PATH>

此語法使用 -f (或 --file) 選項來指定要使用的 Dockerfile,並使用連字號 (-) 作為檔名,指示 Docker 從標準輸入讀取 Dockerfile。

以下範例使用目前目錄 (.) 作為建置情境,並使用透過標準輸入 (stdin) 傳遞的 Dockerfile (透過 here-document 方式) 建置映像檔。

# create a directory to work in
mkdir example
cd example

# create an example file
touch somefile.txt

# build an image using the current directory as context
# and a Dockerfile passed through stdin
docker build -t myimage:latest -f- . <<EOF
FROM busybox
COPY somefile.txt ./
RUN cat /somefile.txt
EOF

本機 tar 壓縮檔

當您將 tar 壓縮檔透過管道傳輸到建置指令時,建置會將 tar 壓縮檔的內容作為檔案系統情境使用。

例如,考慮以下專案目錄

.
├── Dockerfile
├── Makefile
├── README.md
├── main.c
├── scripts
├── src
└── test.Dockerfile

您可以建立該目錄的 tar 壓縮檔,並將其透過管道傳輸到建置中作為情境使用

$ tar czf foo.tar.gz *
$ docker build - < foo.tar.gz

建置會從 tar 壓縮檔情境中解析 Dockerfile。您可以使用 --file 旗標來指定 Dockerfile 的名稱和位置,相對於 tar 壓縮檔的根目錄。以下指令使用 tar 壓縮檔中的 test.Dockerfile 進行建置

$ docker build --file test.Dockerfile - < foo.tar.gz

遠端情境

您可以指定遠端 Git 儲存庫、tar 壓縮檔或純文字檔的位址作為您的建置情境。

  • 對於 Git 儲存庫,建置器會自動複製儲存庫。請參閱Git 儲存庫
  • 對於 tar 壓縮檔,建置器會下載並解壓縮 tar 壓縮檔的內容。請參閱tar 壓縮檔

如果遠端 tar 壓縮檔是文字檔,建置器將不會收到檔案系統情境,而是假定遠端檔案是一個 Dockerfile。請參閱空建置情境

Git 儲存庫

當您將指向 Git 儲存庫位置的 URL 作為引數傳遞給 docker build 時,建置器會使用該儲存庫作為建置情境。

建置器會對儲存庫執行淺層複製 (shallow clone),只下載 HEAD 提交,而非完整的歷史記錄。

建置器會遞迴複製儲存庫及其包含的任何子模組。

$ docker build https://github.com/user/myrepo.git

預設情況下,建置器會複製您指定儲存庫的預設分支上的最新提交。

URL 片段

您可以將 URL 片段附加到 Git 儲存庫位址,以讓建置器複製儲存庫的特定分支、標籤和子目錄。

URL 片段的格式為 #ref:dir,其中

  • ref 是分支、標籤或提交雜湊的名稱
  • dir 是儲存庫內的子目錄

例如,以下指令使用 container 分支及其中的 docker 子目錄作為建置情境

$ docker build https://github.com/user/myrepo.git#container:docker

下表列出了所有有效的後綴及其建置情境

建置語法後綴使用的提交使用的建置情境
myrepo.gitrefs/heads/<預設分支>/
myrepo.git#mytagrefs/tags/mytag/
myrepo.git#mybranchrefs/heads/mybranch/
myrepo.git#pull/42/headrefs/pull/42/head/
myrepo.git#:myfolderrefs/heads/<預設分支>/myfolder
myrepo.git#master:myfolderrefs/heads/master/myfolder
myrepo.git#mytag:myfolderrefs/tags/mytag/myfolder
myrepo.git#mybranch:myfolderrefs/heads/mybranch/myfolder

當您在 URL 片段中使用提交雜湊作為 ref 時,請使用提交的完整 40 字元 SHA-1 雜湊字串。不支援短雜湊,例如截斷為 7 個字元的雜湊。

# ✅ The following works:
docker build github.com/docker/buildx#d4f088e689b41353d74f1a0bfcd6d7c0b213aed2
# ❌ The following doesn't work because the commit hash is truncated:
docker build github.com/docker/buildx#d4f088e

保留 .git 目錄

預設情況下,使用 Git 情境時,BuildKit 不會保留 .git 目錄。您可以透過設定 BUILDKIT_CONTEXT_KEEP_GIT_DIR 建置引數 來配置 BuildKit 保留該目錄。如果您想在建置期間擷取 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/myrepo.git#main

私人儲存庫

當您指定同時也是私人儲存庫的 Git 情境時,建置器需要您提供必要的驗證憑證。您可以使用 SSH 或基於權杖的驗證。

如果您指定的 Git 情境是 SSH 或 Git 位址,Buildx 會自動偵測並使用 SSH 憑證。預設情況下,這會使用 $SSH_AUTH_SOCK。您可以透過 --ssh 旗標 配置要使用的 SSH 憑證。

$ docker buildx build --ssh default git@github.com:user/private.git

如果您想改用基於權杖的驗證,可以使用 --secret 旗標 傳遞權杖。

$ GIT_AUTH_TOKEN=<token> docker buildx build \
  --secret id=GIT_AUTH_TOKEN \
  https://github.com/user/private.git
注意

不要將 --build-arg 用於機密資訊。

透過標準輸入 (stdin) 使用 Dockerfile 的遠端情境

使用以下語法,利用本機檔案系統上的檔案來建置映像檔,同時從標準輸入 (stdin) 使用 Dockerfile。

$ docker build -f- <URL>

此語法使用 -f (或 --file) 選項來指定要使用的 Dockerfile,並使用連字號 (-) 作為檔名,指示 Docker 從標準輸入讀取 Dockerfile。

這在您想從不包含 Dockerfile 的儲存庫建置映像檔的情況下會很有用。或者,如果您想使用自訂 Dockerfile 進行建置,而無需維護儲存庫的自分支,這也會很有用。

以下範例使用來自標準輸入 (stdin) 的 Dockerfile 建置映像檔,並從 GitHub 上的 hello-world 儲存庫添加 hello.c 檔案。

docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF
FROM busybox
COPY hello.c ./
EOF

遠端 tar 壓縮檔

如果您將 URL 傳遞給遠端 tar 壓縮檔,URL 本身將傳送給建置器。

$ docker build http://server/context.tar.gz
#1 [internal] load remote build context
#1 DONE 0.2s

#2 copy /context /
#2 DONE 0.1s
...

下載操作將在 BuildKit 守護程式運行的主機上執行。請注意,如果您使用遠端 Docker 情境或遠端建置器,該主機不一定與您發出建置指令的主機相同。BuildKit 會擷取 context.tar.gz 並將其用作建置情境。Tar 壓縮檔情境必須是符合標準 tar Unix 格式的 tar 封存檔,並且可以使用 xzbzip2gzipidentity (無壓縮) 格式中的任何一種進行壓縮。

空情境

當您使用文字檔作為建置情境時,建置器會將該檔案解釋為 Dockerfile。使用文字檔作為情境表示建置沒有檔案系統情境。

當您的 Dockerfile 不依賴任何本機檔案時,您可以使用空建置情境進行建置。

如何在沒有情境下建置

您可以透過標準輸入流傳遞文字檔,或指向遠端文字檔的 URL。

$ docker build - < Dockerfile
Get-Content Dockerfile | docker build -
docker build -t myimage:latest - <<EOF
FROM busybox
RUN echo "hello world"
EOF
$ docker build https://raw.githubusercontent.com/dvdksn/clockbox/main/Dockerfile

當您在沒有檔案系統情境下進行建置時,Dockerfile 指令(例如 COPY)無法參照本機檔案

$ ls
main.c
$ docker build -<<< $'FROM scratch\nCOPY main.c .'
[+] Building 0.0s (4/4) FINISHED
 => [internal] load build definition from Dockerfile       0.0s
 => => transferring dockerfile: 64B                        0.0s
 => [internal] load .dockerignore                          0.0s
 => => transferring context: 2B                            0.0s
 => [internal] load build context                          0.0s
 => => transferring context: 2B                            0.0s
 => ERROR [1/1] COPY main.c .                              0.0s
------
 > [1/1] COPY main.c .:
------
Dockerfile:2
--------------------
   1 |     FROM scratch
   2 | >>> COPY main.c .
   3 |
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 7ab2bb61-0c28-432e-abf5-a4c3440bc6b6::4lgfpdf54n5uqxnv9v6ymg7ih: "/main.c": not found

.dockerignore 檔案

您可以使用 .dockerignore 檔案從建置情境中排除檔案或目錄。

# .dockerignore
node_modules
bar

這有助於避免將不需要的檔案和目錄傳送給建置器,從而提高建置速度,尤其是在使用遠端建置器時。

檔名與位置

當您執行建置指令時,建置用戶端會在情境的根目錄中尋找名為 .dockerignore 的檔案。如果此檔案存在,則在將匹配這些檔案中模式的檔案和目錄傳送給建置器之前,會將它們從建置情境中移除。

如果您使用多個 Dockerfile,您可以為每個 Dockerfile 使用不同的忽略檔案。您可以使用一種特殊的命名慣例來實現此目的。將您的忽略檔案放置在與 Dockerfile 相同的目錄中,並以 Dockerfile 的名稱作為忽略檔案的前綴,如下例所示。

.
├── index.ts
├── src/
├── docker
│   ├── build.Dockerfile
│   ├── build.Dockerfile.dockerignore
│   ├── lint.Dockerfile
│   ├── lint.Dockerfile.dockerignore
│   ├── test.Dockerfile
│   └── test.Dockerfile.dockerignore
├── package.json
└── package-lock.json

如果兩者都存在,Dockerfile 特定的忽略檔案優先於建置情境根目錄中的 .dockerignore 檔案。

語法

.dockerignore 檔案是一個以換行符分隔的模式列表,類似於 Unix Shell 的檔案 glob 模式。忽略模式中的前導和尾隨斜線會被忽略。以下所有模式都將排除建置情境根目錄下 foo 子目錄中名為 bar 的檔案或目錄

  • /foo/bar/
  • /foo/bar
  • foo/bar/
  • foo/bar

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

#/this/is/a/comment

如果您對 .dockerignore 模式匹配邏輯的精確細節感興趣,請查看 GitHub 上的 moby/patternmatcher 儲存庫,其中包含原始碼。

匹配

以下程式碼片段顯示了一個範例 .dockerignore 檔案。

# comment
*/temp*
*/*/temp*
temp?

此檔案會導致以下建置行為

規則行為
# 註解已忽略。
*/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 檔案來排除 Dockerfile.dockerignore 檔案。這些檔案仍會傳送給建置器,因為它們是執行建置所需的。但是,您無法使用 ADDCOPY 或綁定掛載將這些檔案複製到映像檔中。

否定匹配

您可以在行前加上 ! (驚嘆號) 來為排除項建立例外。以下是一個使用此機制的 .dockerignore 檔案範例

*.md
!README.md

情境目錄下所有 markdown 檔案,除了 README.md 之外,都將從情境中排除。請注意,子目錄下的 markdown 檔案仍會包含在內。

! 例外規則的位置會影響行為:.dockerignore 中匹配特定檔案的最後一行決定了該檔案是包含還是排除。考慮以下範例

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

情境中不包含任何 markdown 檔案,但排除 README-secret.md 的其他 README 檔案則包含在內。

現在考慮這個範例

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

所有 README 檔案都包含在內。中間那一行沒有作用,因為 !README*.md 匹配 README-secret.md 並且是最後一條規則。

命名環境

除了預設建置情境(docker build 指令的定位引數)之外,您還可以傳遞額外的具名情境給建置。

具名情境是使用 --build-context 旗標指定的,後面跟著一個名稱-值對。這讓您可以在建置期間包含來自多個來源的檔案和目錄,同時讓它們在邏輯上保持分離。

$ docker build --build-context docs=./docs .

在此範例中

  • 名為 docs 的情境指向 ./docs 目錄。
  • 預設情境 (.) 指向目前工作目錄。

在 Dockerfile 中使用具名情境

Dockerfile 指令可以參照具名情境,就像它們是多階段建置中的階段一樣。

例如,以下 Dockerfile

  1. 使用 COPY 指令將檔案從預設情境複製到目前的建置階段。
  2. 綁定掛載具名情境中的檔案,以將這些檔案作為建置的一部分進行處理。
# syntax=docker/dockerfile:1
FROM buildbase
WORKDIR /app

# Copy all files from the default context into /app/src in the build container
COPY . /app/src
RUN make bin

# Mount the files from the named "docs" context to build the documentation
RUN --mount=from=docs,target=/app/docs \
    make manpages

具名情境的應用案例

使用具名情境可以在建置 Docker 映像檔時提供更大的彈性和效率。以下是一些使用具名情境會很有用的情境

範例:結合本機和遠端來源

您可以為不同類型的來源定義單獨的具名情境。例如,考慮一個專案,其中應用程式原始碼是本機的,但部署腳本儲存在 Git 儲存庫中

$ docker build --build-context scripts=https://github.com/user/deployment-scripts.git .

在 Dockerfile 中,您可以獨立使用這些情境

# syntax=docker/dockerfile:1
FROM alpine:latest

# Copy application code from the main context
COPY . /opt/app

# Run deployment scripts using the remote "scripts" context
RUN --mount=from=scripts,target=/scripts /scripts/main.sh

範例:具有自訂依賴項的動態建置

在某些情境中,您可能需要從外部來源動態地將配置檔案或依賴項注入到建置中。具名情境透過允許您掛載不同的配置而無需修改預設建置情境,使得這一切變得簡單直接。

$ docker build --build-context config=./configs/prod .

範例 Dockerfile

# syntax=docker/dockerfile:1
FROM nginx:alpine

# Use the "config" context for environment-specific configurations
COPY --from=config nginx.conf /etc/nginx/nginx.conf

範例:固定或覆寫映像檔

您可以在 Dockerfile 中參照具名情境,就像參照映像檔一樣。這表示您可以透過具名情境覆寫 Dockerfile 中的映像檔參照。例如,考慮以下 Dockerfile

FROM alpine:3.21

如果您想強制映像檔參照解析為不同的版本,而無需更改 Dockerfile,您可以將具有相同名稱的情境傳遞給建置。例如

docker buildx build --build-context alpine:3.21=docker-image://alpine:edge .

docker-image:// 字首會將情境標記為映像檔參照。此參照可以是本機映像檔,也可以是您註冊表中的映像檔。

使用 Bake 的具名情境

Bake 是一個內建於 docker build 的工具,可讓您透過配置檔管理建置配置。Bake 完全支援具名情境。

若要在 Bake 檔案中定義具名情境

docker-bake.hcl
target "app" {
  contexts = {
    docs = "./docs"
  }
}

這等同於以下 CLI 呼叫

$ docker build --build-context docs=./docs .

將目標與具名情境連結

除了使複雜的建置更易於管理之外,Bake 還提供了比在 CLI 上使用 docker build 更多的功能。您可以使用具名情境來建立建置管道,其中一個目標依賴並建置在另一個目標之上。例如,考慮一個 Docker 建置設定,其中您有兩個 Dockerfile

  • base.Dockerfile:用於建置基礎映像檔
  • app.Dockerfile:用於建置應用程式映像檔

app.Dockerfile 使用由 base.Dockerfile 產生的映像檔作為其基礎映像檔

app.Dockerfile
FROM mybaseimage

通常,您必須先建置基礎映像檔,然後將其載入到 Docker Engine 的本機映像檔儲存區或推送到註冊表。透過 Bake,您可以直接參照其他目標,從而在 app 目標和 base 目標之間建立依賴關係。

docker-bake.hcl
target "base" {
  dockerfile = "base.Dockerfile"
}

target "app" {
  dockerfile = "app.Dockerfile"
  contexts = {
    # the target: prefix indicates that 'base' is a Bake target
    mybaseimage = "target:base"
  }
}

透過此配置,app.Dockerfile 中對 mybaseimage 的參照會使用建置 base 目標的結果。如果需要,建置 app 目標也會觸發 mybaseimage 的重建。

$ docker buildx bake app

延伸閱讀

有關使用具名情境的更多資訊,請參閱

© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.