構建最佳實踐
使用多階段構建
多階段構建可以透過在映象構建和最終輸出之間建立更清晰的分離來減小最終映象的大小。將 Dockerfile 指令拆分為不同的階段,以確保最終輸出只包含執行應用程式所需的檔案。
使用多階段還可以透過並行執行構建步驟來提高構建效率。
有關更多資訊,請參閱多階段構建。
建立可重用階段
如果您有多個具有很多共同點的映象,請考慮建立一個包含共享元件的可重用階段,並將您的獨特階段基於該階段。Docker 只需構建一次公共階段。這意味著您的派生映象可以更有效地利用 Docker 主機上的記憶體,並更快地載入。
維護一個公共基礎階段(“不要重複自己”)也比擁有多個執行類似事情的不同階段更容易。
選擇正確的基礎映象
實現安全映象的第一步是選擇正確的基礎映象。選擇映象時,請確保它來自受信任的來源並保持其小巧。
Docker 官方映象是經過精選的集合,它們具有清晰的文件,遵循最佳實踐,並定期更新。它們為許多應用程式提供了可靠的起點。
經過驗證的釋出者映象是與 Docker 合作的組織釋出和維護的高質量映象,Docker 會驗證其倉庫中內容的真實性。
Docker 贊助的開源映象是透過開源計劃由 Docker 贊助的開源專案釋出和維護的。
選擇基礎映象時,請注意指示該映象屬於這些程式的徽章。


從 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 可以生成多個工作程序,而 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 可以自動在您的倉庫中發起拉取請求,以更新您的 Dockerfile 以使用最新版本。這比使用自動更改版本的標籤更好,因為您可以控制,並且您可以擁有更改發生的時間和方式的審計追蹤。
有關使用 Docker Scout 自動更新基礎映象的更多資訊,請參閱修復。
在 CI 中構建和測試映象
當您將更改提交到原始碼管理或建立拉取請求時,使用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
指令進行更改。
您還可以使用 here-document 來執行多個命令,而無需使用管道運算子將它們連結起來
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 update
和 apt-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
未執行,您的構建可能會獲取過時的 curl
和 nginx
包版本。
使用 RUN apt-get update && apt-get install -y --no-install-recommends
可確保您的 Dockerfile 安裝最新軟體包版本,無需進一步編碼或手動干預。這種技術稱為快取失效。您還可以透過指定軟體包版本來實現快取失效。這稱為版本固定。例如
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
的exec形式來明確選擇支援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
很少與 ENTRYPOINT
結合使用 CMD ["param", "param"]
的方式,除非您和您的預期使用者已經非常熟悉 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
ADD
和 COPY
功能相似。COPY
支援從構建上下文或多階段構建中的某個階段將檔案基本複製到容器中。ADD
支援從遠端 HTTPS 和 Git URL 獲取檔案,並在從構建上下文新增檔案時自動提取 tar 檔案。
在多階段構建中,您通常希望使用 COPY
將檔案從一個階段複製到另一個階段。如果您需要將構建上下文中的檔案臨時新增到容器中以執行 RUN
指令,您通常可以用繫結掛載代替 COPY
指令。例如,要臨時新增 requirements.txt
檔案用於 RUN pip install
指令
RUN --mount=type=bind,source=requirements.txt,target=/tmp/requirements.txt \
pip install --requirement /tmp/requirements.txt
對於將構建上下文中的檔案包含到容器中,繫結掛載比 COPY
更高效。請注意,繫結掛載的檔案只為單個 RUN
指令臨時新增,並且不會保留在最終映象中。如果需要將構建上下文中的檔案包含在最終映象中,請使用 COPY
。
當您需要在構建過程中下載遠端工件時,ADD
指令是最佳選擇。ADD
比手動使用 wget
和 tar
等工具新增檔案更好,因為它能確保更精確的構建快取。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
有關 ADD
或 COPY
的更多資訊,請參閱以下內容
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 包在處理稀疏檔案時存在一個未解決的 bug,在 Docker 容器內嘗試建立具有非常大 UID 的使用者可能會導致磁碟耗盡,因為容器層中的
/var/log/faillog
會被 NULL (\0) 字元填滿。一個解決方法是向useradd
傳遞--no-log-init
標誌。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 構建在任何子 Dockerfile 中的任何命令之前執行 ONBUILD
命令。
ONBUILD
對於那些將從給定映象構建的映象非常有用。例如,您將為語言堆疊映象使用 ONBUILD
,該映象在 Dockerfile 中構建用該語言編寫的任意使用者軟體,如您在Ruby 的 ONBUILD
變體中看到的那樣。
使用 ONBUILD
構建的映象應該獲得一個單獨的標籤。例如,ruby:1.9-onbuild
或 ruby:2.0-onbuild
。
將 ADD
或 COPY
放入 ONBUILD
時要小心。如果新構建的上下文缺少要新增的資源,`onbuild 映象會災難性地失敗。如上所述新增單獨的標籤有助於緩解此問題,允許 Dockerfile 作者做出選擇。
有關 ONBUILD
的更多資訊,請參閱 Dockerfile 參考中的 ONBUILD 指令。