Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 62 additions & 4 deletions docs/BUILD-CACHE.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ As each build often requires all the same packages, it can be very inefficient t

## How to use it

When you run `melange build`, you can specify a cache directory with the `--cache-dir` flag. The value you provide here should be a path to a directory on your local filesystem. This local directory will be mounted into the build workspace (e.g. a running container) at the path `/var/cache/melange` as a read/write volume.
When you run `melange build`, you can specify a cache directory with the `--cache-dir` flag. The value you provide here should be a path to a directory on your local filesystem. This local directory will be mounted into the build workspace (e.g. a running container) at the path `/var/cache/melange`.

This enables you to speed up builds by preloading data into the cache before you run `melange build`. You can additionally use this mounted directory to persist cache data generated by the build itself, taking advantage of the cache in subsequent builds.
This enables you to speed up builds by preloading data into the cache before you run `melange build`. Depending on the runner you use, you may also be able to persist cache data generated by the build itself for use in subsequent builds (see [Cache Persistence by Runner](#cache-persistence-by-runner) below).

### Example: Go Modules

Expand Down Expand Up @@ -45,7 +45,7 @@ pipeline:

Now you're all set! If you've already downloaded the Go modules you need for your Go project to your local filesystem, you'll no longer need to wait for Melange to download those Go modules during every build. This can significantly speed up builds!

Keep in mind that because the build cache is a read/write-able mount, modifications to data in this directory during a Melange build **will affect** your local filesystem.
**Note:** Whether modifications to the cache during a build persist to your local filesystem depends on which runner you use. See [Cache Persistence by Runner](#cache-persistence-by-runner) for details.

### Example: Python UV

Expand Down Expand Up @@ -123,4 +123,62 @@ pipeline:
pip install -r requirements.txt
```

This caching support helps significantly speed up Python builds by avoiding repeated downloads of packages across builds.
This caching support helps significantly speed up Python builds by avoiding repeated downloads of packages across builds.

### Example: Maven Dependencies

Maven caching is automatically enabled when using the `maven/configure-mirror` or `maven/pombump` pipelines. When a cache directory is mounted at `/var/cache/melange`, the pipelines automatically configure Maven to use `/var/cache/melange/m2repository` as the local repository.

To use Maven caching, simply provide a cache directory:

```shell
melange build --cache-dir /path/to/my/cache ...
```

No additional configuration is required in your Melange config. The Maven pipelines detect the mounted cache directory and configure the local repository path automatically. This is useful for Java projects with many dependencies (e.g., apicurio-registry requires over 1 GB of dependencies).

On subsequent builds, Maven will reuse the downloaded dependencies from the cache, avoiding redundant downloads.

## Cache Persistence by Runner

The cache directory mount behavior varies depending on which runner you use:

| Runner | Mount Type | Writes Persist to Host |
|--------|------------|------------------------|
| Docker | Bind mount (read-write) | Yes |
| Bubblewrap | Bind mount (read-write) | Yes |
| QEMU (default) | 9p (read-only) + overlay | No |
| QEMU (virtiofs) | virtiofs (read-write) | Yes |

### Docker and Bubblewrap

Both Docker and Bubblewrap mount the cache directory as a standard read-write bind mount. Any modifications made to `/var/cache/melange` during the build **will directly affect** your local filesystem. This allows builds to populate the cache for use in subsequent builds.

### QEMU (default, without virtiofs)

By default, QEMU mounts the cache directory using the 9p protocol with a read-only flag. To allow builds to write to the cache, an overlay filesystem is layered on top:

- **Lower layer:** Read-only 9p mount of your host cache directory
- **Upper layer:** Temporary writable directory inside the guest

This means builds can read from your pre-populated cache, but any writes during the build go to the overlay's upper directory and **are discarded** when the build completes. To persist cache writes with QEMU, enable virtiofs (see below).

## QEMU Runner: virtiofs for Cache Directory

When using the QEMU runner, the default 9p mount does not persist cache writes to the host. To enable cache persistence (and improve I/O performance), you can use virtiofs instead.

To enable virtiofs for the cache directory, set the `QEMU_USE_VIRTIOFS` environment variable:

```shell
QEMU_USE_VIRTIOFS=1 melange build --runner qemu --cache-dir /path/to/cache ...
```

**Requirements:**
- The `virtiofsd` binary must be available on the host system (checked at `/usr/libexec/virtiofsd`, `/usr/lib/qemu/virtiofsd`, or in `$PATH`). Alternatively, set `QEMU_VIRTIOFS_PATH` to a directory containing the `virtiofsd` binary (useful for macOS/brew or non-standard installations).
- The host system must support virtiofs (Linux with appropriate kernel support)

When virtiofs is enabled, the cache directory is mounted as a read-write virtiofs share, providing:
- **Cache persistence:** Writes during the build are saved to your host filesystem
- **Better I/O performance:** virtiofs offers improved performance compared to 9p

If `QEMU_USE_VIRTIOFS=1` is set but `virtiofsd` is not found, melange will return an error. If the environment variable is not set or set to `0`, the default 9p+overlay mount is used and cache writes are not persisted.
9 changes: 9 additions & 0 deletions pkg/build/pipelines/maven/configure-mirror.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,19 @@ needs:
- busybox
pipeline:
- runs: |
# Use melange's build cache for downloaded dependencies if mounted from host
MAVEN_LOCAL_REPO="/var/cache/melange/m2repository"
LOCAL_REPO_CONFIG=""
if [ -d "/var/cache/melange" ]; then
mkdir -p "$MAVEN_LOCAL_REPO"
LOCAL_REPO_CONFIG="<localRepository>${MAVEN_LOCAL_REPO}</localRepository>"
fi

# Maven checks $USER/.m2, we set $HOME to /home/build but it hardcodes $USER somehow
mkdir -p /root/.m2
cat > /root/.m2/settings.xml <<EOF
<settings>
${LOCAL_REPO_CONFIG}
<mirrors>
<mirror>
<id>google-maven-central</id>
Expand Down
12 changes: 12 additions & 0 deletions pkg/build/pipelines/maven/pombump.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ inputs:

pipeline:
- runs: |
# Use melange's build cache for downloaded dependencies if mounted from host
MAVEN_LOCAL_REPO="/var/cache/melange/m2repository"
if [ -d "/var/cache/melange" ]; then
mkdir -p "$MAVEN_LOCAL_REPO"
mkdir -p /root/.m2
cat > /root/.m2/settings.xml <<EOF
<settings>
<localRepository>${MAVEN_LOCAL_REPO}</localRepository>
</settings>
EOF
fi

PATCH_FILE_FLAG=""
PROPERTIES_FILE_FLAG=""
DEPENDENCIES_FLAG=""
Expand Down
5 changes: 5 additions & 0 deletions pkg/container/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,9 @@ type Config struct {
SSHControlClient *ssh.Client // SSH client for unrestricted control environment, has privileges
QemuPID int
RunAsGID string

// Virtiofs-related fields for cache directory
VirtiofsEnabled bool // Whether virtiofs is enabled for cache
VirtiofsdPID int // PID of virtiofsd daemon for cleanup
VirtiofsdSocketPath string // Path to Unix socket for virtiofsd
}
Loading
Loading