建置最佳實務

使用多階段建置

多階段建置可讓您透過在映像建置和最終輸出之間建立更清晰的分離,來縮小最終映像的大小。將您的 Dockerfile 指令分割成不同的階段,以確保最終輸出只包含執行應用程式所需的檔案。

使用多個階段還可以讓您透過平行執行建置步驟來提高建置效率。

如需更多資訊,請參閱多階段建置

建立可重複使用的階段

如果您有多個映像有許多共同點,請考慮建立一個包含共用元件的可重複使用階段,並將您的獨特階段建立在此基礎上。Docker 只需建置共同階段一次。這表示您的衍生映像能更有效地使用 Docker 主機上的記憶體,並載入得更快。

維護一個共同的基礎階段(「不要重複自己」)也比擁有多個執行相似任務的不同階段更容易。

選擇正確的基礎映像

實現安全映像的第一步是選擇正確的基礎映像。選擇映像時,請確保它來自可信任的來源並保持其精簡。

  • Docker 官方映像是精選的集合,它們具有清晰的文件、推廣最佳實踐並定期更新。它們為許多應用程式提供了可信任的起點。

  • 經驗證的發布者映像是由與 Docker 合作的組織發布和維護的高品質映像,Docker 會驗證其儲存庫中內容的真實性。

  • Docker 贊助的開源專案映像是由 Docker 透過開源計畫贊助的開源專案發布和維護的。

當您選擇基礎映像時,請注意指示映像是否屬於這些計畫的徽章。

Docker Hub Official and Verified Publisher images

當您從 Dockerfile 建置自己的映像時,請確保選擇符合您需求的最小基礎映像。較小的基礎映像不僅提供可攜性和快速下載,還能縮小映像大小並最大限度地減少透過依賴項引入的漏洞數量。

您還應考慮使用兩種類型的基礎映像:一種用於建置和單元測試,另一種(通常更精簡)用於生產環境。在開發的後期階段,您的映像可能不需要編譯器、建置系統和偵錯工具等建置工具。具有最小依賴項的小型映像可以顯著降低攻擊面。

經常重新建置您的映像

Docker 映像是不可變的。建置映像是在那一刻拍攝該映像的快照。這包括您在建置中使用的任何基礎映像、函式庫或其他軟體。為了使您的映像保持最新和安全,請務必經常重新建置您的映像,並更新依賴項。

為了確保您的建置獲得最新版本的依賴項,您可以使用 --no-cache 選項來避免快取命中。

$ docker build --no-cache -t my-image:my-tag .

以下 Dockerfile 使用 ubuntu 映像的 24.04 標籤。隨著時間的推移,該標籤可能會解析為 ubuntu 映像的不同底層版本,因為發布者會使用新的安全性修補程式和更新的函式庫重新建置映像。使用 --no-cache,您可以避免快取命中,並確保重新下載基礎映像和依賴項。

# syntax=docker/dockerfile:1
FROM ubuntu:24.04
RUN apt-get -y update && apt-get install -y --no-install-recommends python3

同時考慮釘選基礎映像版本

使用 .dockerignore 排除檔案

若要排除與建置無關的檔案,而無需重構您的原始碼儲存庫,請使用 .dockerignore 檔案。此檔案支援類似於 .gitignore 檔案的排除模式。

例如,若要排除所有副檔名為 .md 的檔案

*.md

有關如何建立此檔案的資訊,請參閱Dockerignore 檔案

建立短暫容器

您的 Dockerfile 定義的映像應產生盡可能短暫的容器。短暫意味著容器可以停止和銷毀,然後以最少的設定和配置重新建置和替換。

請參閱《十二要素應用程式》方法論中的流程,以了解以無狀態方式執行容器的動機。

不要安裝不必要的套件

避免安裝額外或不必要的套件,只因為它們可能「不錯」。例如,您不需要在資料庫映像中包含文字編輯器。

當您避免安裝額外或不必要的套件時,您的映像將減少複雜性、減少依賴項、減少檔案大小並縮短建置時間。

解耦應用程式

每個容器都應該只有一個關注點。將應用程式解耦到多個容器中,可以更容易地水平擴展和重複使用容器。例如,一個 Web 應用程式堆疊可能由三個獨立的容器組成,每個容器都有自己獨特的映像,以解耦的方式管理 Web 應用程式、資料庫和記憶體快取。

將每個容器限制為一個程序是一個很好的經驗法則,但這並不是一成不變的規則。例如,容器不僅可以透過 init 程序產生,有些程式也可能自行產生額外的程序。例如,Celery 可以產生多個 worker 程序,而Apache 可以為每個請求建立一個程序。

請盡量運用您的判斷力,使容器盡可能保持乾淨和模組化。如果容器之間相互依賴,您可以使用Docker 容器網路來確保這些容器可以通訊。

排序多行引數

在可能的情況下,將多行引數按字母數字順序排序,以簡化維護。這有助於避免套件重複,並使列表更容易更新。這也讓 PR 更容易閱讀和審閱。在反斜線 (\) 之前添加一個空格也有幫助。

以下是來自buildpack-deps 映像的範例

RUN apt-get update && apt-get install -y --no-install-recommends \
  bzr \
  cvs \
  git \
  mercurial \
  subversion \
  && rm -rf /var/lib/apt/lists/*

利用建置快取

建置映像時,Docker 會依照指定順序逐步執行 Dockerfile 中的指令。對於每個指令,Docker 會檢查是否可以從建置快取中重複使用該指令。

了解建置快取如何運作以及快取失效如何發生,對於確保更快的建置至關重要。有關 Docker 建置快取以及如何優化建置的更多資訊,請參閱Docker 建置快取

釘選基礎映像版本

映像標籤是可變的,這表示發布者可以更新標籤以指向新的映像。這很有用,因為它允許發布者更新標籤以指向映像的更新版本。對於映像使用者來說,這意味著當您重新建置映像時,您會自動獲得新版本。

例如,如果您在 Dockerfile 中指定 FROM alpine:3.21,則 3.21 將解析為 3.21 的最新修補版本。

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

在某個時間點,3.21 標籤可能指向映像的 3.21.1 版本。如果您在 3 個月後重新建置映像,同一個標籤可能指向不同的版本,例如 3.21.4。這種發布工作流程是最佳實踐,大多數發布者都使用這種標籤策略,但它並非強制執行。

這樣做的缺點是,您無法保證每次建置都得到相同的結果。這可能導致破壞性變更,並且這也意味著您沒有您正在使用的確切映像版本的稽核追蹤。

為了完全確保您的供應鏈完整性,您可以將映像版本釘選到特定的摘要。透過將您的映像釘選到摘要,您保證始終使用相同的映像版本,即使發布者用新映像替換了標籤。例如,以下 Dockerfile 將 Alpine 映像釘選到與之前相同的標籤 3.21,但這次也帶有摘要引用。

# syntax=docker/dockerfile:1
FROM alpine:3.21@sha256:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c

有了這個 Dockerfile,即使發布者更新了 3.21 標籤,您的建置仍將使用釘選的映像版本:a8560b36e8b8210634f77d9f7f9efd7ffa463e380b75e2e74aff4511df3ef88c

雖然這有助於您避免意外變更,但每次您想要更新時,手動查找並包含基礎映像版本的映像摘要也更加繁瑣。而且您正在放棄自動安全修復,這很可能是您想要獲得的。

Docker Scout 的預設最新基礎映像政策會檢查您正在使用的基礎映像版本是否確實是最新版本。此政策還會檢查 Dockerfile 中釘選的摘要是否對應到正確的版本。如果發布者更新了您已釘選的映像,政策評估會傳回非合規狀態,表示您應該更新您的映像。

Docker Scout 還支援自動修復工作流程,以保持您的基礎映像最新。當有新的映像摘要可用時,Docker Scout 可以自動在您的儲存庫上提出 pull request,以更新您的 Dockerfile 以使用最新版本。這比使用自動變更版本的標籤更好,因為您可以控制,並且有關於變更何時以及如何發生的稽核追蹤。

有關使用 Docker Scout 自動更新基礎映像的更多資訊,請參閱修復

在 CI 中建置和測試您的映像

當您將變更提交到原始碼控制或建立 pull request 時,請使用GitHub Actions 或其他 CI/CD 管線來自動建置、標記 Docker 映像並進行測試。

Dockerfile 指令

請遵循這些建議,了解如何正確使用Dockerfile 指令來建立高效且可維護的 Dockerfile。

提示

若要在 Visual Studio Code 中改進 Dockerfile 的 linting、程式碼導航和漏洞掃描,請參閱Docker VS Code 擴充功能

FROM

在可能的情況下,請使用當前的官方映像作為您的映像的基礎。Docker 建議使用Alpine 映像,因為它受到嚴格控制且體積小(目前小於 6 MB),同時仍然是一個完整的 Linux 發行版。

有關 FROM 指令的更多資訊,請參閱Dockerfile 的 FROM 指令參考

LABEL

您可以為映像添加標籤,以幫助按專案組織映像、記錄授權資訊、輔助自動化或用於其他原因。對於每個標籤,請添加一行以 LABEL 開頭的內容,其中包含一個或多個鍵值對。以下範例顯示了不同的可接受格式。解釋性註解已內嵌。

包含空格的字串必須加引號或空格必須進行轉義。內部引號字元 (") 也必須轉義。例如

# Set one or more individual labels
LABEL com.example.version="0.0.1-beta"
LABEL vendor1="ACME Incorporated"
LABEL vendor2=ZENITH\ Incorporated
LABEL com.example.release-date="2015-02-12"
LABEL com.example.version.is-production=""

一個映像可以有多個標籤。在 Docker 1.10 之前,建議將所有標籤合併到單一的 LABEL 指令中,以防止建立額外的層。現在這不再是必需的,但合併標籤仍然受支援。例如

# Set multiple labels on one line
LABEL com.example.version="0.0.1-beta" com.example.release-date="2015-02-12"

上述範例也可以寫成

# Set multiple labels at once, using line-continuation characters to break long lines
LABEL vendor=ACME\ Incorporated \
      com.example.is-beta= \
      com.example.is-production="" \
      com.example.version="0.0.1-beta" \
      com.example.release-date="2015-02-12"

有關可接受標籤鍵和值的準則,請參閱了解物件標籤。有關查詢標籤的資訊,請參閱管理物件上的標籤中與篩選相關的項目。另請參閱 Dockerfile 參考中的LABEL

RUN

將長或複雜的 RUN 語句分割成多行,並用反斜線分隔,使您的 Dockerfile 更具可讀性、可理解性和可維護性。

例如,您可以使用 && 運算子串聯命令,並使用轉義字元將長命令分解為多行。

RUN apt-get update && apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo

預設情況下,反斜線會轉義換行字元,但您可以使用escape 指令來更改它。

您也可以使用這裡文件來執行多個命令,而無需使用管道運算子將它們串聯起來

RUN <<EOF
apt-get update
apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo
EOF

有關 RUN 的更多資訊,請參閱Dockerfile 的 RUN 指令參考

apt-get

在基於 Debian 的映像中,RUN 指令的一個常見用例是使用 apt-get 安裝軟體。由於 apt-get 安裝套件,RUN apt-get 命令有幾種需要注意的反直覺行為。

務必在相同的 RUN 語句中將 RUN apt-get updateapt-get install 結合使用。例如

RUN apt-get update && apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo

單獨在 RUN 語句中使用 apt-get update 會導致快取問題,並使後續的 apt-get install 指令失敗。例如,以下 Dockerfile 中會出現此問題

# syntax=docker/dockerfile:1

FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends curl

建置映像後,所有層都位於 Docker 快取中。假設您稍後透過添加額外套件來修改 apt-get install,如下列 Dockerfile 所示

# syntax=docker/dockerfile:1

FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends curl nginx

Docker 認為初始指令和修改後的指令是相同的,並重複使用前幾個步驟的快取。因此,apt-get update 不會執行,因為建置使用的是快取版本。由於 apt-get update 未執行,您的建置可能會獲得過時版本的 curlnginx 套件。

使用 RUN apt-get update && apt-get install -y --no-install-recommends 可確保您的 Dockerfile 安裝最新套件版本,而無需進一步編碼或手動干預。此技術稱為快取清除 (cache busting)。您也可以透過指定套件版本來實現快取清除。這稱為版本釘選 (version pinning)。例如

RUN apt-get update && apt-get install -y --no-install-recommends \
    package-bar \
    package-baz \
    package-foo=1.3.*

版本釘選會強制建置擷取特定版本,無論快取中有什麼。此技術還可以減少因所需套件中意外變更而導致的失敗。

以下是一個格式良好的 RUN 指令,展示了所有 apt-get 建議。

RUN apt-get update && apt-get install -y --no-install-recommends \
    aufs-tools \
    automake \
    build-essential \
    curl \
    dpkg-sig \
    libcap-dev \
    libsqlite3-dev \
    mercurial \
    reprepro \
    ruby1.9.1 \
    ruby1.9.1-dev \
    s3cmd=1.1.* \
    && rm -rf /var/lib/apt/lists/*

s3cmd 引數指定了 1.1.* 版本。如果映像先前使用了舊版本,指定新版本會導致 apt-get update 的快取失效,並確保安裝新版本。每行列出套件還可以防止套件重複的錯誤。

此外,當您透過移除 /var/lib/apt/lists 來清理 apt 快取時,由於 apt 快取未儲存在層中,因此會減少映像大小。由於 RUN 語句以 apt-get update 開頭,因此套件快取總是在 apt-get install 之前重新整理。

官方 Debian 和 Ubuntu 映像會自動執行 apt-get clean,因此不需要明確呼叫。

使用管道

有些 RUN 命令依賴於將一個命令的輸出透過管道傳輸到另一個命令的能力,使用管道字元 (|),如下例所示

RUN wget -O - https://some.site | wc -l > /number

Docker 使用 /bin/sh -c 解譯器執行這些命令,該解譯器只評估管道中最後一個操作的退出碼來判斷成功。在上面的範例中,只要 wc -l 命令成功,即使 wget 命令失敗,此建置步驟也會成功並產生一個新映像。

如果您希望命令由於管道中任何階段的錯誤而失敗,請在前面加上 set -o pipefail && 以確保意外錯誤阻止建置意外成功。例如

RUN set -o pipefail && wget -O - https://some.site | wc -l > /number
注意

並非所有 shell 都支援 -o pipefail 選項。

在 Debian 型映像上的 dash shell 等情況下,請考慮使用 RUN執行形式來明確選擇支援 pipefail 選項的 shell。例如

RUN ["/bin/bash", "-c", "set -o pipefail && wget -O - https://some.site | wc -l > /number"]

CMD

CMD 指令應用於執行您的映像中包含的軟體以及任何引數。CMD 幾乎總是應以 CMD ["executable", "param1", "param2"] 的形式使用。因此,如果映像是用於服務,例如 Apache 和 Rails,您將執行類似 CMD ["apache2","-DFOREGROUND"] 的命令。實際上,這種形式的指令建議用於任何基於服務的映像。

在大多數其他情況下,CMD 應該獲得一個互動式 shell,例如 bash、Python 和 perl。例如,CMD ["perl", "-de0"]CMD ["python"]CMD ["php", "-a"]。使用這種形式意味著當您執行類似 docker run -it python 的命令時,您將進入一個可用的 shell,準備就緒。CMD 很少應該以 CMD ["param", "param"] 的方式與 ENTRYPOINT 結合使用,除非您和您預期的使用者已經非常熟悉 ENTRYPOINT 的運作方式。

有關 CMD 的更多資訊,請參閱Dockerfile 的 CMD 指令參考

EXPOSE

EXPOSE 指令表示容器監聽連線的埠。因此,您應該為您的應用程式使用常見的傳統埠。例如,包含 Apache Web 伺服器的映像會使用 EXPOSE 80,而包含 MongoDB 的映像會使用 EXPOSE 27017 等等。

為了外部存取,您的使用者可以使用一個標誌執行 docker run,該標誌指示如何將指定埠映射到他們選擇的埠。對於容器連結,Docker 提供了從接收容器到來源的路徑的環境變數(例如,MYSQL_PORT_3306_TCP)。

有關 EXPOSE 的更多資訊,請參閱Dockerfile 的 EXPOSE 指令參考

ENV

為了使新軟體更容易執行,您可以使用 ENV 來更新容器安裝的軟體的 PATH 環境變數。例如,ENV PATH=/usr/local/nginx/bin:$PATH 可確保 CMD ["nginx"] 正常運作。

ENV 指令對於提供您想要容器化的服務所需的特定環境變數也很有用,例如 Postgres 的 PGDATA

最後,ENV 也可用於設定常用版本號,以便更容易維護版本升級,如下例所示

ENV PG_MAJOR=9.3
ENV PG_VERSION=9.3.4
RUN curl -SL https://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgres &&
ENV PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH

與程式中擁有常數變數而不是硬編碼值類似,這種方法讓您可以更改單一的 ENV 指令,以自動升級容器中軟體的版本。

每行 ENV 都會建立一個新的中間層,就像 RUN 命令一樣。這表示即使您在未來的層中取消設定環境變數,它仍然會保留在此層中,並且其值可以被傾印。您可以透過建立如下所示的 Dockerfile,然後建置它來測試這一點。

# syntax=docker/dockerfile:1
FROM alpine
ENV ADMIN_USER="mark"
RUN echo $ADMIN_USER > ./mark
RUN unset ADMIN_USER
$ docker run --rm test sh -c 'echo $ADMIN_USER'

mark

為了防止這種情況並取消設定環境變數,請使用帶有 shell 命令的 RUN 命令,以在單一層中設定、使用和取消設定變數。您可以使用 ;&& 分隔命令。如果您使用第二種方法,並且其中一個命令失敗,則 docker build 也會失敗。這通常是個好主意。使用 \ 作為 Linux Dockerfile 的行續接字元可提高可讀性。您也可以將所有命令放入 shell 腳本中,並讓 RUN 命令只執行該 shell 腳本。

# syntax=docker/dockerfile:1
FROM alpine
RUN export ADMIN_USER="mark" \
    && echo $ADMIN_USER > ./mark \
    && unset ADMIN_USER
CMD sh
$ docker run --rm test sh -c 'echo $ADMIN_USER'

有關 ENV 的更多資訊,請參閱Dockerfile 的 ENV 指令參考

ADD 或 COPY

ADDCOPY 在功能上相似。COPY 支援將檔案基本複製到容器中,來源可以是建置上下文,也可以是多階段建置中的一個階段。ADD 支援從遠端 HTTPS 和 Git URL 擷取檔案,以及在從建置上下文添加檔案時自動解壓縮 tar 檔案的功能。

在多階段建置中,您主要會想使用 COPY 來將檔案從一個階段複製到另一個階段。如果您需要臨時將建置上下文中的檔案添加到容器中以執行 RUN 指令,您通常可以用綁定掛載 (bind mount) 代替 COPY 指令。例如,要臨時為 RUN pip install 指令添加 requirements.txt 檔案

RUN --mount=type=bind,source=requirements.txt,target=/tmp/requirements.txt \
    pip install --requirement /tmp/requirements.txt

對於將建置上下文中的檔案包含在容器中,綁定掛載 (bind mounts) 比 COPY 更有效率。請注意,綁定掛載的檔案僅在單一 RUN 指令期間臨時添加,不會保留在最終映像中。如果您需要將建置上下文中的檔案包含在最終映像中,請使用 COPY

當您需要下載遠端產物作為建置的一部分時,ADD 指令是最佳選擇。ADD 比手動使用 wgettar 等工具添加檔案更好,因為它能確保更精確的建置快取。ADD 還內建支援遠端資源的校驗和驗證,以及從Git URL解析分支、標籤和子目錄的協定。

以下範例使用 ADD 下載 .NET 安裝程式。結合多階段建置,最終階段只會保留 .NET 執行階段,沒有中間檔案。

# syntax=docker/dockerfile:1

FROM scratch AS src
ARG DOTNET_VERSION=8.0.0-preview.6.23329.7
ADD --checksum=sha256:270d731bd08040c6a3228115de1f74b91cf441c584139ff8f8f6503447cebdbb \
    https://dotnetcli.azureedge.net/dotnet/Runtime/$DOTNET_VERSION/dotnet-runtime-$DOTNET_VERSION-linux-arm64.tar.gz /dotnet.tar.gz

FROM mcr.microsoft.com/dotnet/runtime-deps:8.0.0-preview.6-bookworm-slim-arm64v8 AS installer

# Retrieve .NET Runtime
RUN --mount=from=src,target=/src <<EOF
mkdir -p /dotnet
tar -oxzf /src/dotnet.tar.gz -C /dotnet
EOF

FROM mcr.microsoft.com/dotnet/runtime-deps:8.0.0-preview.6-bookworm-slim-arm64v8

COPY --from=installer /dotnet /usr/share/dotnet
RUN ln -s /usr/share/dotnet/dotnet /usr/bin/dotnet

有關 ADDCOPY 的更多資訊,請參閱以下內容

ENTRYPOINT

ENTRYPOINT 最好的用途是設定映像的主要命令,允許該映像像該命令一樣執行,然後使用 CMD 作為預設旗標。

以下是命令列工具 s3cmd 的映像範例

ENTRYPOINT ["s3cmd"]
CMD ["--help"]

您可以使用以下命令來執行映像並顯示命令的說明

$ docker run s3cmd

或者,您可以使用正確的參數來執行命令,如下例所示

$ docker run s3cmd ls s3://mybucket

這很有用,因為映像名稱可以兼作二進位檔的參考,如上述命令所示。

ENTRYPOINT 指令也可以與輔助腳本結合使用,使其能夠以與上述命令類似的方式運作,即使啟動工具可能需要多個步驟。

例如,Postgres 官方映像使用以下腳本作為其 ENTRYPOINT

#!/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 "$@"

此腳本使用exec Bash 命令,以便最終執行的應用程式成為容器的 PID 1。這允許應用程式接收發送到容器的任何 Unix 訊號。有關更多資訊,請參閱ENTRYPOINT 參考

在以下範例中,輔助腳本被複製到容器中,並在容器啟動時透過 ENTRYPOINT 執行

COPY ./docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]
CMD ["postgres"]

此腳本讓您可以透過多種方式與 Postgres 互動。

它可以簡單地啟動 Postgres

$ docker run postgres

或者,您可以使用它來執行 Postgres 並將參數傳遞給伺服器

$ docker run postgres postgres --help

最後,您可以使用它來啟動一個完全不同的工具,例如 Bash

$ docker run --rm -it postgres bash

有關 ENTRYPOINT 的更多資訊,請參閱Dockerfile 的 ENTRYPOINT 指令參考

VOLUME

您應該使用 VOLUME 指令來公開任何資料庫儲存區域、配置儲存或由您的 Docker 容器建立的檔案和資料夾。強烈建議您將 VOLUME 用於映像中任何可變或使用者可維護的部分。

有關 VOLUME 的更多資訊,請參閱Dockerfile 的 VOLUME 指令參考

USER

如果服務可以在沒有權限的情況下運行,請使用 USER 切換到非 root 使用者。首先在 Dockerfile 中建立使用者和群組,例如以下範例

RUN groupadd -r postgres && useradd --no-log-init -r -g postgres postgres
注意

考慮明確的 UID/GID。

映像中的使用者和群組被分配非確定性 UID/GID,因為「下一個」UID/GID 的分配與映像重建無關。因此,如果情況關鍵,您應該分配明確的 UID/GID。

注意

由於 Go archive/tar 套件在處理稀疏檔案時存在一個未解決的錯誤,嘗試在 Docker 容器內創建具有顯著大 UID 的使用者可能會導致磁碟耗盡,因為容器層中的 /var/log/faillog 會被 NULL (\0) 字元填滿。一個解決方法是將 --no-log-init 旗標傳遞給 useradd。Debian/Ubuntu 的 adduser 包裝器不支援此旗標。

避免安裝或使用 sudo,因為它具有不可預測的 TTY 和訊號轉發行為,可能導致問題。如果您絕對需要類似 sudo 的功能,例如以 root 身份初始化守護程式但以非 root 身份運行它,請考慮使用「gosu」

最後,為了減少層數和複雜性,請避免頻繁地來回切換 USER

有關 USER 的更多資訊,請參閱Dockerfile 的 USER 指令參考

WORKDIR

為了清晰和可靠性,您應該始終為您的 WORKDIR 使用絕對路徑。此外,您應該使用 WORKDIR,而不是擴散諸如 RUN cd … && do-something 之類的指令,這些指令難以閱讀、疑難排解和維護。

有關 WORKDIR 的更多資訊,請參閱Dockerfile 的 WORKDIR 指令參考

ONBUILD

ONBUILD 命令在當前 Dockerfile 建置完成後執行。ONBUILD 在從當前映像衍生出的任何子映像中執行。您可以將 ONBUILD 命令視為父 Dockerfile 給子 Dockerfile 的指令。

Docker 建置會先執行 ONBUILD 命令,然後才執行子 Dockerfile 中的任何命令。

ONBUILD 對於將從給定映像建置的映像很有用。例如,您會將 ONBUILD 用於語言堆疊映像,該映像在 Dockerfile 中建置以該語言編寫的任意使用者軟體,如您在Ruby 的 ONBUILD 變體中所見。

使用 ONBUILD 建置的映像應獲得單獨的標籤。例如,ruby:1.9-onbuildruby:2.0-onbuild

ONBUILD 中放置 ADDCOPY 時要小心。如果新建置的上下文缺少要添加的資源,onbuild 映像將會災難性地失敗。如上所述,添加單獨的標籤有助於透過允許 Dockerfile 作者做出選擇來緩解此問題。

有關 ONBUILD 的更多資訊,請參閱Dockerfile 的 ONBUILD 指令參考

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