feat: optimize Dockerfile build speed with BuildKit caching#665
feat: optimize Dockerfile build speed with BuildKit caching#665jeremyeder wants to merge 1 commit intoambient-code:mainfrom
Conversation
c0afd64 to
225c47b
Compare
|
this patch brings 5g -> 1g. I looked at using all alpine family images but that only got things down to 645mb total for all container images. |
This comment has been minimized.
This comment has been minimized.
Claude Code ReviewSummaryThis PR optimizes Dockerfiles across all components using BuildKit cache mounts and multi-stage builds. The changes are primarily infrastructure-level (no application code affected). The runner Dockerfile sees the most substantial refactoring (single-stage → multi-stage, Python 3.11 → 3.12, ~73% claimed size reduction). Backend, operator, and public-api builder stages switch from Overall direction is sound, but there are several correctness and consistency concerns that need attention before merge. Issues by Severity🚫 Blocker Issues1. # ❌ Non-deterministic, will silently pick up breaking UBI updates
FROM registry.access.redhat.com/ubi9/ubi-minimal:latestUsing # ✅ Pin to a specific version
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.4All other runtime stages in this project use pinned versions — this should too. 🔴 Critical Issues2. CGO compatibility risk: Alpine builder → UBI runtime (backend, operator, public-api) The builder stages for The build commands in the diff do not explicitly set # ⚠️ No CGO_ENABLED=0 — depends on environment default
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
go build -o /app/backend ./...Fix: Explicitly disable CGO when building on Alpine for a glibc runtime: RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/go-build \
CGO_ENABLED=0 go build -o /app/backend ./...This is critical — if any dependency uses CGO (even indirectly), the binary will silently build but fail to start. Verify with 3. Python 3.11 → 3.12 upgrade in runner with no dependency validation evidence
There is no mention of updated 🟡 Major Issues4. Inconsistent base image strategy across components The PR introduces a mixed image strategy:
The public-api runtime was changed to UBI-minimal, but this version uses 5. Implicit The public-api runtime stage installs only RUN microdnf install -y ca-certificates && microdnf clean all
HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \
CMD curl -sf http://localhost:8080/health || exit 1
RUN microdnf install -y ca-certificates curl && microdnf clean all🔵 Minor Issues6. Duplicate All four new 7. BuildKit requirement not documented The 8. Old (Alpine): The Positive Highlights
RecommendationsPriority order before merge:
🤖 Generated with Claude Code 🔍 View AI decision process (logs available for 90 days) 📋 View memory system files loaded (click to expand)What Amber Loaded for Code ReviewAmber automatically loaded these repository standards from the memory system:
Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines. |
Add BuildKit cache mounts and layer optimizations to speed up Docker builds across all components. Fix Go version mismatch in public-api that broke builds. Key changes: - Add BuildKit cache mounts for Go module/build cache (3 Go services) - Add npm cache mount for frontend dependency installs - Fix public-api Go version: 1.23 -> 1.24 (matches go.mod requirement) - Bump public-api alpine: 3.19 -> 3.21 - Upgrade runner from python-311 to python-312 - Merge runner dnf install layers into single RUN - Download jq binary directly (not available in ubi9/python-312 repos) - Move operator ARG declarations below cached layers - Remove unused procps from operator runtime - Add .dockerignore for Go components (public-api, backend, operator) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
225c47b to
fd6907f
Compare
|
Closing in favor of a minimal one-line fix for the Go version mismatch. The broader Dockerfile optimizations (BuildKit caching, Alpine migration, etc.) didn't yield meaningful wins with UBI base images. |
Claude Code ReviewSummaryPR #665 optimizes Docker build speed by adding BuildKit cache mounts across all components, fixes a Go version mismatch that was breaking public-api builds, and upgrades the Claude runner from Python 3.11 to 3.12 with a multi-stage build. The optimization intent is sound, but several issues warrant attention before merging — one supply-chain security concern stands out as the most important. Issues by Severity🔴 Critical Issues1. jq binary downloaded from GitHub with no integrity verification (runner Dockerfile:25) curl -Lo /usr/local/bin/jq https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-$(uname -m | sed 's/aarch64/arm64/;s/x86_64/amd64/') && \
chmod +x /usr/local/bin/jqThis downloads an arbitrary binary from the internet at build time and makes it executable without verifying its SHA256 checksum. This is a classic supply-chain attack vector — a compromised CDN, DNS hijack, or MITM between the builder and GitHub could silently substitute a malicious binary into every runner image. The PR description acknowledges jq isn't available in UBI9 python-312 repos, but the solution introduces a more serious risk than the problem it solves. Recommended fix — add integrity verification: curl -Lo /usr/local/bin/jq https://github.com/jqlang/jq/releases/download/jq-1.7.1/jq-linux-$(uname -m | sed 's/aarch64/arm64/;s/x86_64/amd64/') && \
echo "<sha256_hash> /usr/local/bin/jq" | sha256sum -c - && \
chmod +x /usr/local/bin/jqUse the published SHA256 hashes from the jq 1.7.1 release page for both amd64 and arm64. 2. Backend and operator base image switched from ubi9/go-toolset to golang:alpine # Before
FROM registry.access.redhat.com/ubi9/go-toolset:1.24 AS builder
# After
FROM golang:1.24-alpine AS builder
If the motivation is that 🟡 Major Issues3. Runner base image digest pin removed # Before (pinned)
FROM registry.access.redhat.com/ubi9/python-311@sha256:d0b35f779ca0ae87deaf17cd1923461904f52d3ef249a53dbd487e02bdabdde6
# After (floating tag)
FROM registry.access.redhat.com/ubi9/python-312Removing the SHA pin means builds are no longer reproducible — a routine registry update to 4. ARG declarations in operator Dockerfile are unused in the build command ARG GIT_COMMIT=unknown
ARG GIT_BRANCH=unknown
ARG GIT_REPO=unknown
ARG GIT_VERSION=unknown
ARG BUILD_DATE=unknown
ARG BUILD_USER=unknown
RUN ... CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o operator .The ARGs are declared but never referenced in the build command (e.g., via 5. BuildKit cache mount scope in multi-platform CI The Makefile and GitHub Actions CI builds images for both 🔵 Minor Issues6. Python packages copied to RUN pip install --no-cache-dir --prefix=/install '/build/claude-runner[all]' uv
# ...
COPY --from=builder /install /usr/localCopying the entire 7. This is correct for production builds. However, it means a future Dockerfile test stage (e.g., Positive Highlights
RecommendationsPriority order for follow-up:
Review performed by Claude Code against project standards in CLAUDE.md and 🔍 View AI decision process (logs available for 90 days) 📋 View memory system files loaded (click to expand)What Amber Loaded for Code ReviewAmber automatically loaded these repository standards from the memory system:
Impact: This review used your repository's specific code quality standards, security patterns, and best practices from the memory system (PRs #359, #360) - not just generic code review guidelines. |
Summary
Add BuildKit cache mounts and layer optimizations to speed up Docker builds across all components. Fixes Go version mismatch in public-api that broke builds.
npm cigolang:1.23-alpine→golang:1.24-alpine(go.mod requires >= 1.24.0)alpine:3.19→alpine:3.21ubi9/python-311toubi9/python-312with multi-stage pip installdnf installlayers into singleRUN(eliminates intermediate cache)ARGdeclarations below cached layers (prevents cache busting on every build)procpsfrom operator runtime.dockerignorefor Go components to reduce build contextBuild Speed Improvements
go modcachego buildcachenpm ciwhen lockfile unchanged.dockerignorefilesARGreorderingBug Fixes
public-api/Dockerfile:golang:1.23-alpine→golang:1.24-alpine—go.modrequiresgo 1.24.0, builds were failingTest plan
make kind-up-localto validate full stack🤖 Generated with Claude Code