Skip to content

feat(build): keep Dockerfile cache mounts between ARC image builds - #359

Merged
JesperTerkelsen merged 2 commits into
mainfrom
feat/arc-docker-cache-mounts
Sep 29, 2026
Merged

JesperTerkelsen merged 2 commits into
mainfrom
feat/arc-docker-cache-mounts

Conversation

@JesperTerkelsen

@JesperTerkelsen JesperTerkelsen commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

What?

On ARC (use-arc-runners: true), component-build.yml now keeps the Dockerfile's RUN --mount=type=cache contents between image builds:

  • runs-on/cache (S3, monta-github-ci-cache), or actions/cache as a fallback, restores them into a workspace directory;
  • reproducible-containers/buildkit-cache-dance (pinned to v3.4.0) injects them into the buildx builder, then extracts them after the build so they can be saved.

The action finds the mounts by parsing the Dockerfile given in docker-file-name, so nothing is hardcoded.

Why?

All 44 Kotlin service Dockerfiles run Gradle inside the image build:

RUN --mount=type=cache,target=/root/.gradle ... ./gradlew --no-daemon clean buildLayers

On Blacksmith, the builder's disk persists between runs, so /root/.gradle stays warm. On ARC:

  • every buildx builder starts empty;
  • the ECR registry cache (cache-to ... mode=max) doesn't carry cache mounts;
  • COPY . /home/src before the Gradle RUN means any code change invalidates that layer anyway.

So every ARC deploy would re-download all Gradle dependencies. They'd also come straight from Maven Central: the runner's CodeArtifact init script and its AWS identity don't reach Gradle inside docker build. That's slower, and it's exactly the traffic behind the Maven Central 429s on ARC. This is a prerequisite for making ARC the default runner.

The cache key is the Dockerfile path plus a hash of the Gradle build files, with a prefix restore-key, so a dependency bump still starts from the previous cache.

Storage: S3 via runs-on/cache, like the PR workflows

  • S3 is used when the caller passes GH_ACTION_ACCESS_KEY_ID/GH_ACTION_SECRET_ACCESS_KEY, which component-build and deploy-kotlin(-v2) now accept as optional secrets. Otherwise the GitHub cache is used, as in feat(kotlin): make ARC the default runner for the Kotlin workflows #360.
  • It's the combined runs-on/cache action (the same pin as the Sonar cache in sonar-cloud.yml), not runs-on/cache/restore + save. cache-dance only extracts the mounts from the builder in its post step. Post steps run after every normal step, so a separate save step would save an empty directory, while the combined action's own post-step save runs after the extraction.
  • The S3 step sets AWS_SESSION_TOKEN: "". The job has already exported the target account's ecr-put-image session into the environment, and that token would otherwise pair with the bucket keys.

QA

Carried by https://github.com/monta-app/service-openadr/pull/262. Its staging deploy points at this branch and passes the S3 secrets. Results to follow: a cold run, then a warm run to show the cache hit.

Gaps

  • Without the S3 secrets the fallback GitHub cache holds up to ~1 GB per Dockerfile, which counts against the repo's 10 GB limit.
  • A cold cache (first build, or a dependency change without a usable prefix match) still resolves from Maven Central directly inside the build.

🤖 Generated with Claude Code

@JesperTerkelsen
JesperTerkelsen marked this pull request as ready for review September 29, 2026 10:40
@JesperTerkelsen
JesperTerkelsen requested a review from a team as a code owner September 29, 2026 10:40
@JesperTerkelsen
JesperTerkelsen requested review from prasad-manu and removed request for a team September 29, 2026 10:40
JesperTerkelsen and others added 2 commits September 29, 2026 12:44
ARC builders start empty and the ECR registry cache doesn't carry
RUN --mount=type=cache contents, so every Kotlin image build on ARC
re-downloaded all Gradle dependencies from Maven Central. Restore and
save the cache mounts with actions/cache and buildkit-cache-dance,
which discovers them from the Dockerfile.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Matches the PR workflows: S3 when the caller passes the GH_ACTION_*
secrets (now accepted by component-build and deploy-kotlin(-v2)), the
GitHub cache otherwise.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@JesperTerkelsen
JesperTerkelsen force-pushed the feat/arc-docker-cache-mounts branch from d4f2f97 to 12f35a5 Compare September 29, 2026 10:44
@JesperTerkelsen
JesperTerkelsen merged commit e80d5b1 into main Sep 29, 2026
2 checks passed
@JesperTerkelsen
JesperTerkelsen deleted the feat/arc-docker-cache-mounts branch September 29, 2026 10:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants