1. 程式人生 > 實用技巧 >【Docker】Dockerfile 最佳實踐-RUN

【Docker】Dockerfile 最佳實踐-RUN

參考教程:https://docs.docker.com/develop/develop-images/dockerfile_best-practices/

環境

  1. virtual box 6.1
  2. centos 7.8
  3. docker 19.03

RUN

Split long or complex RUN statements on multiple lines separated with backslashes to make your Dockerfile more readable, understandable, and maintainable.

在多行上用反斜槓分隔長或複雜的 RUN 語句,以使您的 Dockerfile

更具可讀性,可理解性和可維護性。

apt-get

Probably the most common use-case for RUN is an application of apt-get. Because it installs packages, the RUN apt-get command has several gotchas to look out for.

RUN 的最常見用例可能是 apt-get 的應用程式。因為它安裝了軟體包,所以 RUN apt-get 命令需要注意一些陷阱。

Avoid RUN apt-get upgrade and dist-upgrade, as many of the “essential” packages from the parent images cannot upgrade inside an

unprivileged container. If a package contained in the parent image is out-of-date, contact its maintainers. If you know there is a particular package, foo, that needs to be updated, use apt-get install -y foo to update automatically.

避免使用 RUN apt-get upgradedist-upgrade,因為來自父映像的許多“基本”軟體包都無法在非特權容器

中進行升級。如果父映像中包含的軟體包已過期,請聯絡其維護者。如果您知道有一個特定的軟體包 foo 需要更新,請使用 apt-get install -y foo 自動更新。

Always combine RUN apt-get update with apt-get install in the same RUN statement. For example:

始終在同一 RUN 語句中將 RUN apt-get updateapt-get install 結合使用。例如:

RUN apt-get update && apt-get install -y \
    package-bar \
    package-baz \
    package-foo \
    && rm -rf /var/lib/apt/lists/*

Using apt-get update alone in a RUN statement causes caching issues and subsequent apt-get install instructions fail. For example, say you have a Dockerfile:

RUN 語句中單獨使用 apt-get update 會導致快取問題,隨後的 apt-get install 指令也會失敗。例如,假設您有一個 Dockerfile:

FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y curl

After building the image, all layers are in the Docker cache. Suppose you later modify apt-get install by adding extra package:

構建映象後,所有層都在 Docker 快取中。假設您以後通過新增額外的軟體包來修改 apt-get install

FROM ubuntu:18.04
RUN apt-get update
RUN apt-get install -y curl nginx

Docker sees the initial and modified instructions as identical and reuses the cache from previous steps. As a result the apt-get update is not executed because the build uses the cached version. Because the apt-get update is not run, your build can potentially get an outdated version of the curl and nginx packages.

Docker 將初始指令和修改後的指令視為相同,並重復使用先前步驟中的快取。結果,由於構建使用了快取的版本,因此未執行 apt-get update。因為沒有執行 apt-get update,所以您的構建可能會獲得 curlnginx 軟體包的過時版本。

Using RUN apt-get update && apt-get install -y ensures your Dockerfile installs the latest package versions with no further coding or manual intervention. This technique is known as “cache busting”. You can also achieve cache-busting by specifying a package version. This is known as version pinning, for example:

使用 RUN apt-get update && apt-get install -y 確保您的 Dockerfile 安裝最新的軟體包版本,而無需進一步的編碼或手動干預。這種技術稱為“快取清除”。您還可以通過指定軟體包版本來實現快取清除。這稱為版本固定,例如:

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

Version pinning forces the build to retrieve a particular version regardless of what’s in the cache. This technique can also reduce failures due to unanticipated changes in required packages.

版本固定會強制構建物檢索特定版本,而不管快取中的內容是什麼。該技術還可以減少由於所需包裝中的意外更改而導致的故障。

Below is a well-formed RUN instruction that demonstrates all the apt-get recommendations.

下面是格式正確的 RUN 指令,演示了所有 apt-get 建議。

RUN apt-get update && apt-get install -y \
    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/*

The s3cmd argument specifies a version 1.1.*. If the image previously used an older version, specifying the new one causes a cache bust of apt-get update and ensures the installation of the new version. Listing packages on each line can also prevent mistakes in package duplication.

s3cmd 引數指定版本 1.1。*。如果映象先前使用的是舊版本,則指定新版本會導致 apt-get update 快取崩潰,並確保安裝新版本。在每一行列出軟體包還可以防止軟體包重複中的錯誤。

In addition, when you clean up the apt cache by removing /var/lib/apt/lists it reduces the image size, since the apt cache is not stored in a layer. Since the RUN statement starts with apt-get update, the package cache is always refreshed prior to apt-get install.

另外,當您通過刪除 /var/lib/apt/lists 清理 apt 快取時,由於 apt 快取沒有儲存在圖層中,因此會減小映像大小。由於 RUN 語句以 apt-get update 開頭,因此軟體包快取總是在 apt-get install 之前重新整理。

Official Debian and Ubuntu images automatically run apt-get clean, so explicit invocation is not required.

官方 Debian 和 Ubuntu 映象自動執行 apt-get clean,因此不需要顯式呼叫。

Using pipes

Some RUN commands depend on the ability to pipe the output of one command into another, using the pipe character (|), as in the following example:

一些 RUN 命令取決於使用管道字元(|)將一個命令的輸出管道到另一個命令的能力,如以下示例所示:

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

Docker executes these commands using the /bin/sh -c interpreter, which only evaluates the exit code of the last operation in the pipe to determine success. In the example above this build step succeeds and produces a new image so long as the wc -l command succeeds, even if the wget command fails.

Docker 使用 /bin/sh -c 直譯器執行這些 命令,該直譯器僅評估管道中最後一個操作的退出程式碼來確定成功。在上面的示例中,即使 wget 命令失敗,只要wc -l 命令成功,該構建步驟就會成功並生成一個新映象。

If you want the command to fail due to an error at any stage in the pipe, prepend set -o pipefail && to ensure that an unexpected error prevents the build from inadvertently succeeding. For example:

如果您希望命令由於管道中任何階段的錯誤而失敗,請新增 set -o pipefail && 字首,以確保意外錯誤可以防止構建意外進行。例如:

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

Not all shells support the -o pipefail option.

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

In cases such as the dash shell on Debian-based images, consider using the exec form of RUN to explicitly choose a shell that does support the pipefail option. For example:

在諸如基於 Debian 的映象上的 dash 外殼的情況下,請考慮使用 RUN 的 exec 形式來明確選擇一個支援 pipefail 選項的外殼。例如:

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

總結

介紹了 Dockerfile 的 RUN 指令的最佳實踐。