跳轉到主要內容
Dockerfile layer cache 理解 layer cache 才知道為什麼 Dockerfile 的指令順序會影響 build 速度。

核心原則

  • 每條指令是一層,是 cache 的基本單位。Docker 比對指令字串與相關檔案的 checksum,完全相同才命中快取。
  • 失效會串聯:某一層 cache 失效,後面所有層一律重建,不管它們本身有沒有變。
各指令的失效條件:
指令觸發失效
FROMbase image digest 改變
RUN指令字串改變(不看實際輸出apt-get update 抓到新版本不會讓 cache 失效)
COPY / ADD來源檔案的 checksum 改變(mtime 不計)
ENV / ARG / WORKDIR指令字串改變

指令排序最佳化

原則:變動頻率低的指令放前面,高的放後面。
# 低效(原始碼改動 → 重新 install 依賴)
COPY . .
RUN pip install -r requirements.txt

# 最佳化(依賴改動才失效)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
RUN apt-get update 的雷:updateinstall 要寫在同一條 RUN,否則 update 那層被快取後,install 可能裝到舊版本:
RUN apt-get update && apt-get install -y curl \
    && rm -rf /var/lib/apt/lists/*

強制跳過與清理

docker build --no-cache -t myapp .              # 整個 build 跳過快取
docker build --no-cache-filter install -t myapp .   # 只跳過某個 stage
docker builder prune                            # 清掉 build cache

Cache mount(跨 build 持久化套件快取)

讓套件下載快取跨 build 持久化(不進映像層):
# pip
RUN --mount=type=cache,target=/root/.cache/pip \
    pip install -r requirements.txt

# npm
RUN --mount=type=cache,target=/root/.npm \
    npm install

# apt
RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \
    apt-get update && apt-get install -y gcc
--mount=type=cache 的快取不進 image layer,只在 builder 端持久化,比傳統做法省 build 時間。

最佳實踐範本

把原則收成一份可直接抄的範本:
# syntax=docker/dockerfile:1
FROM python:3.12-slim

LABEL org.opencontainers.image.authors="dev@example.com"

# 合併 RUN、裝完清掉 apt 快取,少一層也少佔空間
RUN apt-get update && apt-get install -y --no-install-recommends \
    libpq-dev \
    && rm -rf /var/lib/apt/lists/*

# 建非 root 使用者
RUN groupadd -r appuser && useradd --no-log-init -r -g appuser appuser

WORKDIR /app

# 相依清單在前,原始碼在後(layer cache 最佳化)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appuser . .

# 切非 root 執行
USER appuser

EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
  CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" || exit 1

CMD ["python", "app.py"]
重點:合併 RUN 並清 apt 快取(rm -rf /var/lib/apt/lists/*)、pip install --no-cache-dir 不把 pip 快取留進映像、固定基底 tag、切非 root USER、用 .dockerignore 縮小 context、WORKDIR 用絕對路徑取代 RUN cd

注意事項與安全

  • 別用 latest:基底固定 major.minor(或更嚴格用 digest @sha256:...),避免基底悄悄換版本。
  • 切非 root USER:預設 root 跑容器風險高,建專用使用者再切過去。
  • 機密別進 DockerfileARG / ENV 會留在 docker history,密碼金鑰用執行期注入(docker run --env / Compose env_file / secrets),不要寫死在 Dockerfile。
  • ADD 下載 URL 要當心:快取與認證行為複雜,需要下載多用 RUN curl 並驗 checksum;一般複製優先 COPY

接下來

官方參考:docs.docker.com/build/cachebuild 最佳實踐