Part 11 · Docker · 11.1.03

Build graph, cache và reproducible images

Dockerfile mô tả build graph; instruction order và inputs quyết định cache reuse, security và reproducibility. BuildKit giúp thực thi graph này hiệu quả hơn, nhưng một build nhanh chưa chắc đã là một build an toàn, lặp lại được hoặc dễ vận hành.

BuildKit

Hãy đọc Dockerfile như một dependency graph thay vì chỉ như một script tuyến tính. Mỗi instruction tạo ra một state mới dựa trên parent state và input liên quan. Vì vậy thay đổi ở một node có thể làm mất cache của chính node đó và toàn bộ phần downstream. Thiết kế build tốt cần đồng thời tối ưu bốn mục tiêu: tốc độ, reproducibility, security và khả năng điều tra khi build thất bại.

Mental model: giữ input ổn định ở đầu graph, đưa input thay đổi thường xuyên xuống sau; tách build-time toolchain khỏi runtime; không truyền secret như dữ liệu image; và coi digest/attestation là bằng chứng của artifact đã được build.

Cache model

BuildKit tính cache từ instruction, parent state và relevant inputs. COPY . . quá sớm khiến thay đổi source code làm invalidate các dependency layers. Với Java/Maven, nên copy manifest/lockfile và wrapper trước, restore dependency, rồi mới copy source. .dockerignore giúp giảm build context, giảm dữ liệu không cần thiết gửi cho builder và giảm nguy cơ vô tình đưa file nhạy cảm vào context.

Input thay đổiẢnh hưởng cacheThiết kế nên dùng
pom.xml, wrapper hoặc dependency manifestInvalidate dependency restore và downstreamĐặt trước source để chỉ rebuild dependency khi manifest thật sự đổi.
Source codeInvalidate từ bước COPY src ... trở xuốngCopy source sau dependency restore.
RUN command text không đổiCó thể reuse cache dù package repository bên ngoài đã đổiChủ động refresh cache khi cần patch; không giả định rebuild tự động kéo package mới.
Secret valueNội dung secret không tự làm cache missNếu thay secret phải kéo theo cache bust có chủ đích cho step cần chạy lại.

Cache mounts

Cache mount như Maven local repository giảm download lặp lại mà không cần bake cache đó vào final image. Cache là optimization, không phải source of truth: pipeline phải vẫn build đúng khi cache bị miss, bị prune hoặc không thể import.

Multi-stage

Builder chứa compiler/toolchain; runtime chỉ copy artifact/runtime files. Có thể dùng stage target cho test/debug. Final image nhỏ hơn giúp giảm attack surface và transfer time, nhưng size nhỏ không tự động đồng nghĩa an toàn: base image vẫn phải được patch, version/digest phải được pin theo risk model và runtime vẫn cần đủ khả năng quan sát/debug khi production có sự cố.

# syntax=docker/dockerfile:1
FROM eclipse-temurin:21-jdk AS build
WORKDIR /src
COPY mvnw pom.xml ./
COPY .mvn .mvn
RUN --mount=type=cache,target=/root/.m2 ./mvnw dependency:go-offline
COPY src src
RUN --mount=type=cache,target=/root/.m2 ./mvnw package -DskipTests

FROM eclipse-temurin:21-jre AS runtime
WORKDIR /app
COPY --from=build /src/target/app.jar /app/app.jar
ENTRYPOINT ["java","-jar","/app/app.jar"]

Nên đặt tên stage thay vì tham chiếu bằng số để việc reorder Dockerfile không làm vỡ COPY --from. Khi cần điều tra, có thể build tới một stage cụ thể bằng --target, ví dụ giữ một stage debug/test riêng nhưng không đưa toolchain đó vào production runtime.

Secrets and provenance

ARG, ENV hoặc COPY không phù hợp để truyền secret vì dữ liệu có thể xuất hiện trong image metadata, layer hoặc cache. Với BuildKit, dùng secret mount cho token/password và SSH mount cho private Git/SSH access để secret chỉ tồn tại tạm thời trong instruction cần nó.

# Build command
DOCKER_BUILDKIT=1 docker build \
  --secret id=maven_settings,src=$HOME/.m2/settings.xml \
  -t example/app:dev .

# Dockerfile instruction
RUN --mount=type=secret,id=maven_settings,target=/root/.m2/settings.xml \
    ./mvnw package -DskipTests

Network dependency và version cần được locked hoặc verify để build repeatable. Với base image, tag là mutable; nếu reproducibility/audit yêu cầu mạnh, pin digest và có quy trình cập nhật digest có kiểm soát thay vì để cùng Dockerfile âm thầm resolve sang bytes khác ở lần build sau.

SBOM, provenance và promote by digest

BuildKit/buildx có thể tạo SBOM và provenance attestations. Production pipeline nên gắn metadata này với artifact, scan/verify trước khi release, rồi promote cùng một image digest qua các environment thay vì rebuild lại source cho từng environment. Cách này giảm khoảng trống giữa artifact đã test và artifact thực sự deploy.

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  --sbom=true \
  --provenance=mode=max \
  --push \
  -t registry.example.com/team/app:1.4.0 .

Failure modes

Các failure mode quan trọng gồm mutable base tag, package index thay đổi, timestamp/non-deterministic archive, cross-platform emulation, cache poisoning, dependency download không verify, registry/build-cache outage và secret/credential hết hạn giữa pipeline.

Failure windowSignal nên quan sátRecovery / rollback
Dependency/base bị đổi hoặc biến mất trong lúc buildDigest mismatch, 404/5xx, checksum failure, dependency resolution latencyRetry có bounded backoff; dùng mirror/cache; quay lại known-good digest/version.
Cache bị miss hoặc cache backend unavailableCache hit ratio giảm, build duration tăng, network egress tăngBuild vẫn phải đúng khi không có cache; giới hạn concurrency để tránh thundering herd.
Cross-platform emulation quá chậm hoặc sai khácPer-platform duration, test failures chỉ trên một architectureDùng native builders cho critical platform; tách artifact theo platform digest; không promote platform fail.
Secret hết hạn / permission thay đổi401/403 trong dependency fetch hoặc signingRotate credential ngoài image; retry step sau khi credential hợp lệ; không log secret.
Artifact build được nhưng provenance/SBOM/signing failMissing attestation, verification/signature failureFail closed cho release path; giữ artifact ở trạng thái unpromoted cho tới khi metadata pass.

Capacity và operational signals

Builder cũng là production infrastructure. Theo dõi build queue time, build duration theo stage, cache hit/miss, cache storage usage, disk pressure, network/download throughput, registry latency/error rate, CPU/memory của builder và failure rate theo architecture. Cache backend cần quota/GC policy để không làm đầy disk và biến một optimization thành single point of failure.

Security boundaries

Reproducible không đồng nghĩa luôn mới nhất. Pinning giúp cùng input tạo lại cùng artifact, nhưng cũng có thể giữ nguyên dependency đã có lỗ hổng. Vì vậy cần hai luồng tách biệt: một luồng build repeatable và một luồng chủ động cập nhật base/dependency rồi test, scan và promote digest mới.

Production checklist

Tài liệu: Docker Build · Build Cache · Cache invalidation · Multi-stage builds · Build secrets · Build attestations · SBOM attestations · Build best practices · Dockerfile Reference

Scope note: examples target modern Docker BuildKit/buildx workflows. Exact defaults and feature support depend on Docker Engine/Desktop/buildx/BuildKit version and builder driver/image store; verify the environment used by CI before relying on a specific attestation or cache backend behavior.