Skip to content

fix(docker): switch back to Alpine base image#7564

Merged
paulbalaji merged 2 commits intomainfrom
pbio/alpine-docker-image
Dec 8, 2025
Merged

fix(docker): switch back to Alpine base image#7564
paulbalaji merged 2 commits intomainfrom
pbio/alpine-docker-image

Conversation

@paulbalaji
Copy link
Collaborator

@paulbalaji paulbalaji commented Dec 8, 2025

Summary

Switches the monorepo Docker image back to Alpine, reducing image size by ~520 MB (6% smaller).

Background

In #7529 we switched from node:20-alpine to node:20-slim because Foundry's foundryup tool downloads glibc-linked binaries that don't work on Alpine (musl). However, Foundry now publishes Alpine-specific binaries in their GitHub releases.

Changes

  • Switch from node:20-slim to node:20-alpine
  • Download pre-built Alpine binaries directly from Foundry releases instead of using foundryup
  • Pass FOUNDRY_VERSION from solidity/.foundryrc as a build arg for reproducibility
  • Support both amd64 and arm64 architectures via TARGETARCH
  • Trigger Docker build when .foundryrc changes

Size Comparison (same commit, different base)

Image Base Size
22b6e35 (main) node:20-slim 8.69 GB
9433d99 (this PR) node:20-alpine 8.17 GB
Savings ~520 MB (6%)

Caching

Since FOUNDRY_VERSION is pinned via .foundryrc, the Foundry download layer will be cached for almost all builds. The layer is only ~80MB and downloads in ~3 seconds.

Test plan

  • CI Docker build succeeds
  • forge --version works: forge Version: 1.5.0-dev
  • hyperlane --version works: Hyperlane CLI 19.11.0
  • Compare final image size to previous slim-based image

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Chores
    • Switched to a lighter Alpine base to reduce image size and build artifacts.
    • Pinned and surfaced the Foundry tool version for reproducible, consistent builds.
    • Improved dependency installation and build reliability on the CI image.
    • Expanded build context to include additional subpackages and package metadata for comprehensive monorepo builds.

✏️ Tip: You can customize this high-level summary in your review settings.

Uses Foundry's official Alpine binaries instead of glibc-based foundryup,
reducing image size by ~1.8GB (26% smaller).

Changes:
- Switch from node:20-slim to node:20-alpine
- Download pre-built Alpine binaries from Foundry releases
- Pass FOUNDRY_VERSION from .foundryrc as build arg
- Support both amd64 and arm64 architectures
- Trigger Docker build on .foundryrc changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@changeset-bot
Copy link

changeset-bot bot commented Dec 8, 2025

⚠️ No Changeset found

Latest commit: 527e6a8

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@codecov
Copy link

codecov bot commented Dec 8, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (22b6e35) to head (527e6a8).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@          Coverage Diff          @@
##            main   #7564   +/-   ##
=====================================
  Coverage   0.00%       0           
=====================================
  Files          1       0    -1     
  Lines         14       0   -14     
=====================================
+ Misses        14       0   -14     
Components Coverage Δ
core ∅ <ø> (∅)
hooks ∅ <ø> (∅)
isms ∅ <ø> (∅)
token ∅ <ø> (∅)
middlewares ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@paulbalaji paulbalaji marked this pull request as ready for review December 8, 2025 18:43
@paulbalaji paulbalaji added this pull request to the merge queue Dec 8, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 8, 2025

📝 Walkthrough

Walkthrough

Switched the Docker base to Alpine, made Foundry installation architecture- and version-aware (FOUNDRY_VERSION from solidity/.foundryrc → build-arg), and expanded Docker COPY steps to accommodate monorepo package layouts and Yarn build steps.

Changes

Cohort / File(s) Summary
CI workflow
​.github/workflows/monorepo-docker.yml
Watch solidity/.foundryrc, read FOUNDRY_VERSION into env, and pass it as build-arg (FOUNDRY_VERSION) to Docker build.
Dockerfile & build context
Dockerfile
Changed base from node:20-slimnode:20-alpine; replaced apt-get with apk installs; added ARG FOUNDRY_VERSION and ARG TARGETARCH, implemented architecture-aware Foundry tarball download/install (forge, cast); expanded COPY steps to include multiple monorepo package.json/yarn configs and subpackages before yarn install and build.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant CI as GitHub Actions
participant Docker as Docker Build
participant Registry as Foundry Release Host
participant Image as Built Container

Note over CI: Trigger includes changes under solidity/.foundryrc
CI->>CI: Read `solidity/.foundryrc` → FOUNDRY_VERSION
CI->>Docker: docker build --build-arg FOUNDRY_VERSION, TARGETARCH
Docker->>Registry: HTTP GET foundry tarball (arch + version)
Registry-->>Docker: Tarball (forge, cast)
Docker->>Docker: Extract binaries → /usr/local/bin
Docker->>Docker: COPY monorepo files, yarn install, build
Docker->>Image: Produce final image (REGISTRY_VERSION set)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Verify Alpine package names and Python/pip availability (apk vs apt).
  • Confirm Foundry tarball URL pattern, architecture mapping, and binary permissions.
  • Ensure expanded COPY steps include all required files and don't bloat build context.
  • Validate workflow reads .foundryrc reliably and passes FOUNDRY_VERSION through CI matrix.

Possibly related PRs

Suggested reviewers

  • yjamin
  • troykessler

Poem

In a cozy build swamp, Alpine sings,
Foundry fetches bolts and handy things,
Packages copied, yarn takes a spin,
Images shrink — a grin grows within 🐸✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: switching Docker base image from node:20-slim back to Alpine, which is the primary objective and the most important change in the changeset.
Description check ✅ Passed The description is comprehensive, covering background context, specific changes, size comparisons, caching implications, and detailed test results. All major template sections are addressed with substantial, relevant information.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch pbio/alpine-docker-image

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9a5dd7a and 9433d99.

📒 Files selected for processing (2)
  • .github/workflows/monorepo-docker.yml (3 hunks)
  • Dockerfile (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6891
File: typescript/infra/config/environments/mainnet3/funding.ts:22-22
Timestamp: 2025-08-13T16:53:55.163Z
Learning: In Hyperlane mainnet3 configs, funding.ts uses 'gcr.io/abacus-labs-dev/hyperlane-monorepo' docker image while agent.ts uses 'gcr.io/abacus-labs-dev/hyperlane-agent' docker image. These are different images with independent tag cycles, so tag consistency across them is not expected.
📚 Learning: 2025-11-25T17:10:33.369Z
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 7410
File: solidity/foundry.toml:8-8
Timestamp: 2025-11-25T17:10:33.369Z
Learning: In the hyperlane-xyz/hyperlane-monorepo repository, when using pnpm (instead of Yarn), Foundry's `allow_paths` in solidity/foundry.toml should be set to `["./node_modules"]` rather than `["../node_modules"]` because pnpm's default node_modules structure places dependencies locally in the workspace subdirectory, not requiring access to the parent directory's node_modules.

Applied to files:

  • .github/workflows/monorepo-docker.yml
  • Dockerfile
📚 Learning: 2025-11-24T17:19:38.362Z
Learnt from: CR
Repo: hyperlane-xyz/hyperlane-monorepo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T17:19:38.362Z
Learning: Use Turbo for building all workspaces in the monorepo; use workspace-specific build commands for individual components (Solidity with Hardhat + Forge, TypeScript SDK, Rust agents with Cargo)

Applied to files:

  • Dockerfile
📚 Learning: 2025-08-13T16:53:55.163Z
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6891
File: typescript/infra/config/environments/mainnet3/funding.ts:22-22
Timestamp: 2025-08-13T16:53:55.163Z
Learning: In Hyperlane mainnet3 configs, funding.ts uses 'gcr.io/abacus-labs-dev/hyperlane-monorepo' docker image while agent.ts uses 'gcr.io/abacus-labs-dev/hyperlane-agent' docker image. These are different images with independent tag cycles, so tag consistency across them is not expected.

Applied to files:

  • Dockerfile
📚 Learning: 2025-11-26T13:28:51.658Z
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 7410
File: typescript/cli/package.json:20-20
Timestamp: 2025-11-26T13:28:51.658Z
Learning: In the hyperlane-xyz/hyperlane-monorepo repository, hyperlane-xyz/registry is maintained in a separate repository and published to npm, so it should use a pinned version (e.g., "23.6.0") rather than the workspace protocol ("workspace:*") that other internal Hyperlane packages use.

Applied to files:

  • Dockerfile
🔇 Additional comments (7)
.github/workflows/monorepo-docker.yml (3)

16-16: Path trigger properly surfaces Foundry version changes.

Adding solidity/.foundryrc ensures the Docker build is triggered whenever the Foundry version changes, keeping the image in sync.


103-107: Foundry version tracking is clean and follows the established pattern.

The new step mirrors the existing .registryrc approach, ensuring the Foundry version is consistently read from the source of truth and passed through to the Docker build.


128-131: Build-args are properly structured.

Both FOUNDRY_VERSION and REGISTRY_COMMIT are cleanly passed to the Docker build context.

Dockerfile (4)

1-1: Alpine base image swap reduces footprint without sacrificing functionality.

The switch from node:20-slim to node:20-alpine achieves the stated ~520 MB reduction while maintaining compatibility, like peeling back layers to get to what matters.


5-6: Alpine package installation is correct and follows best practices.

The apk add command properly targets Alpine's package manager, and bundling the yarn version set in the same layer keeps things efficient.


14-42: Monorepo layer caching strategy is well-structured.

The multi-step COPY approach (package manifests first, then yarn install, then source code) leverages Docker's layer caching effectively. When source code changes, the expensive yarn install step is skipped, which matters for monorepos with many workspaces.


44-64: Build flow and finalization are clean and follow the established patterns.

Copying source code after dependencies, running the full build via Turbo, cloning the registry for back-compatibility, and setting up the entrypoint are all standard and appropriate for this monorepo structure.

@paulbalaji paulbalaji removed this pull request from the merge queue due to a manual request Dec 8, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
Dockerfile (2)

5-6: Minor note on apk syntax.

The apk add --update --no-cache syntax on line 5 works (CI passed), but the standard apk idiom is either apk add -U --no-cache (short flag) or apk update && apk add --no-cache (explicit update). The --update long form isn't typical; if you're touching this again, consider aligning with standard Alpine patterns for consistency.


16-42: Comprehensive package.json coverage; consider consolidating COPY statements.

All typescript subpackages and solidity are accounted for—good. The .yarn config files (plugins, releases, patches) are present for Yarn 4. This is correct and necessary.

For future refactors (not blocking): listing every package.json individually works, but consolidating with a pattern like COPY typescript/ typescript/ and COPY solidity/ solidity/ would reduce verbosity and still enable Docker's layer caching to work correctly because the package.json files change less frequently than the source code in those directories.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9433d99 and 527e6a8.

📒 Files selected for processing (1)
  • Dockerfile (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6891
File: typescript/infra/config/environments/mainnet3/funding.ts:22-22
Timestamp: 2025-08-13T16:53:55.163Z
Learning: In Hyperlane mainnet3 configs, funding.ts uses 'gcr.io/abacus-labs-dev/hyperlane-monorepo' docker image while agent.ts uses 'gcr.io/abacus-labs-dev/hyperlane-agent' docker image. These are different images with independent tag cycles, so tag consistency across them is not expected.
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 7410
File: solidity/foundry.toml:8-8
Timestamp: 2025-11-25T17:10:33.369Z
Learning: In the hyperlane-xyz/hyperlane-monorepo repository, when using pnpm (instead of Yarn), Foundry's `allow_paths` in solidity/foundry.toml should be set to `["./node_modules"]` rather than `["../node_modules"]` because pnpm's default node_modules structure places dependencies locally in the workspace subdirectory, not requiring access to the parent directory's node_modules.
📚 Learning: 2025-11-25T17:10:33.369Z
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 7410
File: solidity/foundry.toml:8-8
Timestamp: 2025-11-25T17:10:33.369Z
Learning: In the hyperlane-xyz/hyperlane-monorepo repository, when using pnpm (instead of Yarn), Foundry's `allow_paths` in solidity/foundry.toml should be set to `["./node_modules"]` rather than `["../node_modules"]` because pnpm's default node_modules structure places dependencies locally in the workspace subdirectory, not requiring access to the parent directory's node_modules.

Applied to files:

  • Dockerfile
📚 Learning: 2025-11-24T17:19:38.362Z
Learnt from: CR
Repo: hyperlane-xyz/hyperlane-monorepo PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T17:19:38.362Z
Learning: Use Turbo for building all workspaces in the monorepo; use workspace-specific build commands for individual components (Solidity with Hardhat + Forge, TypeScript SDK, Rust agents with Cargo)

Applied to files:

  • Dockerfile
📚 Learning: 2025-08-13T16:53:55.163Z
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 6891
File: typescript/infra/config/environments/mainnet3/funding.ts:22-22
Timestamp: 2025-08-13T16:53:55.163Z
Learning: In Hyperlane mainnet3 configs, funding.ts uses 'gcr.io/abacus-labs-dev/hyperlane-monorepo' docker image while agent.ts uses 'gcr.io/abacus-labs-dev/hyperlane-agent' docker image. These are different images with independent tag cycles, so tag consistency across them is not expected.

Applied to files:

  • Dockerfile
📚 Learning: 2025-11-26T13:28:51.658Z
Learnt from: paulbalaji
Repo: hyperlane-xyz/hyperlane-monorepo PR: 7410
File: typescript/cli/package.json:20-20
Timestamp: 2025-11-26T13:28:51.658Z
Learning: In the hyperlane-xyz/hyperlane-monorepo repository, hyperlane-xyz/registry is maintained in a separate repository and published to npm, so it should use a pinned version (e.g., "23.6.0") rather than the workspace protocol ("workspace:*") that other internal Hyperlane packages use.

Applied to files:

  • Dockerfile
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (57)
  • GitHub Check: cli-evm-e2e-matrix (warp-rebalancer)
  • GitHub Check: cli-evm-e2e-matrix (warp-check-2)
  • GitHub Check: cli-evm-e2e-matrix (warp-check-5)
  • GitHub Check: cli-evm-e2e-matrix (warp-extend-basic)
  • GitHub Check: cli-evm-e2e-matrix (warp-deploy-2)
  • GitHub Check: cli-evm-e2e-matrix (warp-check-1)
  • GitHub Check: cli-evm-e2e-matrix (warp-init)
  • GitHub Check: cli-evm-e2e-matrix (warp-bridge-2)
  • GitHub Check: cli-evm-e2e-matrix (warp-read)
  • GitHub Check: cli-evm-e2e-matrix (warp-extend-config)
  • GitHub Check: cli-evm-e2e-matrix (warp-deploy-1)
  • GitHub Check: cli-evm-e2e-matrix (warp-send)
  • GitHub Check: cli-evm-e2e-matrix (warp-apply-submitters)
  • GitHub Check: cli-evm-e2e-matrix (warp-check-4)
  • GitHub Check: cli-evm-e2e-matrix (warp-check-3)
  • GitHub Check: cli-evm-e2e-matrix (warp-apply-rebalancing-config)
  • GitHub Check: cli-evm-e2e-matrix (warp-extend-recovery)
  • GitHub Check: cli-evm-e2e-matrix (warp-apply-hook-updates)
  • GitHub Check: cli-evm-e2e-matrix (core-read)
  • GitHub Check: cli-evm-e2e-matrix (warp-bridge-1)
  • GitHub Check: cli-evm-e2e-matrix (warp-apply-simple-updates)
  • GitHub Check: cli-evm-e2e-matrix (warp-apply-ownership-updates)
  • GitHub Check: cli-evm-e2e-matrix (relay)
  • GitHub Check: cli-evm-e2e-matrix (warp-apply-ism-updates)
  • GitHub Check: cli-evm-e2e-matrix (core-init)
  • GitHub Check: cli-evm-e2e-matrix (core-deploy)
  • GitHub Check: cli-evm-e2e-matrix (core-check)
  • GitHub Check: cli-evm-e2e-matrix (core-apply)
  • GitHub Check: env-test-matrix (mainnet3, arbitrum, igp)
  • GitHub Check: cli-radix-e2e-matrix (core-deploy)
  • GitHub Check: cosmos-sdk-e2e-run
  • GitHub Check: cli-radix-e2e-matrix (warp-apply-route-extension)
  • GitHub Check: aleo-sdk-e2e-run
  • GitHub Check: cli-radix-e2e-matrix (warp-apply-ownership-updates)
  • GitHub Check: env-test-matrix (mainnet3, ethereum, igp)
  • GitHub Check: env-test-matrix (mainnet3, optimism, core)
  • GitHub Check: cli-radix-e2e-matrix (warp-deploy)
  • GitHub Check: env-test-matrix (mainnet3, ethereum, core)
  • GitHub Check: env-test-matrix (mainnet3, optimism, igp)
  • GitHub Check: env-test-matrix (testnet4, sepolia, core)
  • GitHub Check: cli-cosmos-e2e-matrix (core-read)
  • GitHub Check: cli-cross-chain-e2e-matrix (warp-deploy)
  • GitHub Check: env-test-matrix (mainnet3, arbitrum, core)
  • GitHub Check: cli-cosmos-e2e-matrix (warp-deploy)
  • GitHub Check: cli-cosmos-e2e-matrix (core-deploy)
  • GitHub Check: cli-cosmos-e2e-matrix (warp-read)
  • GitHub Check: cli-cross-chain-e2e-matrix (warp-apply)
  • GitHub Check: cli-cosmos-e2e-matrix (core-check)
  • GitHub Check: cli-cosmos-e2e-matrix (core-apply)
  • GitHub Check: cli-install-test-run
  • GitHub Check: yarn-test-run
  • GitHub Check: infra-test
  • GitHub Check: build-and-push-to-gcr
  • GitHub Check: e2e-matrix (evm)
  • GitHub Check: test-rs
  • GitHub Check: lander-coverage
  • GitHub Check: lint-rs
🔇 Additional comments (1)
Dockerfile (1)

1-13: Alpine switch looks solid; Foundry installation is well-structured.

The shift from node:20-slim to node:20-alpine with pinned Alpine Foundry binaries is clean. Architecture detection (arm64 vs amd64) is correct, and set -o pipefail ensures the build fails fast if the download or extraction goes sideways. The FOUNDRY_VERSION as a build-arg keeps the install reproducible and cacheable.

@paulbalaji paulbalaji enabled auto-merge December 8, 2025 18:58
@hyper-gonk
Copy link
Contributor

hyper-gonk bot commented Dec 8, 2025

🐳 Monorepo Docker Image Built Successfully

Image Tags:

gcr.io/abacus-labs-dev/hyperlane-monorepo:pr-7564
gcr.io/abacus-labs-dev/hyperlane-monorepo:527e6a8-20251208-185357

@paulbalaji paulbalaji added this pull request to the merge queue Dec 8, 2025
Merged via the queue into main with commit 036e035 Dec 8, 2025
86 checks passed
@paulbalaji paulbalaji deleted the pbio/alpine-docker-image branch December 8, 2025 19:24
@github-project-automation github-project-automation bot moved this from In Review to Done in Hyperlane Tasks Dec 8, 2025
paulbalaji added a commit that referenced this pull request Dec 18, 2025
- Switch builder from node:20-slim to node:20-alpine
- Use direct Foundry binary download instead of foundryup
- Pin Foundry version from solidity/.foundryrc for reproducibility
- Add TARGETARCH support for multi-arch builds

Follows pattern from #7564

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants