Skip to content

About

Fork of woodpecker-ci/plugin-docker-buildx with purge fix and GC defaults

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

plugin-docker-buildx

Woodpecker CI plugin to build multiarch Docker images with buildx.

This is a fork of woodpecker-ci/plugin-docker-buildx maintained by GowerStreet. See upstream docs for the full settings reference.

Why we forked

The upstream plugin had two issues that caused disk exhaustion on the CI host:

  1. purge was a no-op. The setting was documented and defaulted to true, but the settings.Cleanup field was never read by Execute(). Every job created a new buildx_buildkit_* container and a ~4 GB state volume and left both running permanently. On a busy day this accumulated 80–90 GB of orphaned builders.

  2. No BuildKit GC policy. Even if builders had been cleaned up, their caches had no upper bound. A single builder could grow to fill the disk on long-running pipelines.

What we changed

1. purge now works (purge: true is the default)

Execute() captures the builder name from docker buildx create --use output, then runs docker buildx rm <name> after the build completes. The builder container and its state volume are removed at the end of every job.

Set purge: false only if you need to inspect the builder after a failed build.

2. BuildKit GC defaults are always applied

The auto-generated buildkit config now always includes a [worker.oci] section:

[worker.oci]
gc = true
gckeepstorage = 1000        # 1 GB max local cache

[[worker.oci.gcpolicy]]
keepBytes = 536870912       # evict above 512 MiB
keepDuration = 7200         # evict layers older than 2 hours

This bounds the local cache footprint of each builder while it is alive, acting as a backstop in case purge ever fails. If you set buildkit_config explicitly these defaults are not applied — your config is used as-is.

3. Registry cache is enabled by default (auto_cache: true)

When auto_cache is enabled (the default) and no explicit cache_from, cache_to, or cache_images settings are provided, the plugin automatically derives a registry cache image from the first repo value:

repo: gowerstreet/myapp               →  cache image: gowerstreet/myapp:buildcache
repo: gowerstreet/myapp, target: web  →  cache image: gowerstreet/myapp:buildcache-web

Each target gets its own ref. With mode=max a ref holds one build's cache, so targets sharing a ref would overwrite each other.

This gives every job free layer caching with zero per-pipeline config. The same credentials used to push the image cover the cache tag. The cache is written with mode=max so all intermediate layers are stored, making layer-cache hits as effective as possible.

Only pushes to the repo's default branch write the cache. Pull requests and other branches read it but never write it: a mode=max ref holds one build's cache, so a PR building a different Dockerfile, lockfile or build args would otherwise evict the default branch's cache for every later build (seen in GowerStreet/dagster on 2026-10-07: PR and main builds alternately overwrote buildcache-full and every build ran cold).

Auto-cache is suppressed when:

  • dry_run: true (no push, so no cache write)
  • Any of cache_from, cache_to, or cache_images is set explicitly

Opt out globally with auto_cache: false.

4. No SOURCE_DATE_EPOCH or rewrite-timestamp by default (reproducible: false)

Upstream always passes --build-arg SOURCE_DATE_EPOCH=<commit time> and --output ...,rewrite-timestamp=true. BuildKit folds SOURCE_DATE_EPOCH into the cache key of every layer, so every new commit missed the registry cache from the first WORKDIR/RUN on and auto_cache never hit. rewrite-timestamp then pulls and rewrites every layer, cached or not (116s on a 1 GB image in GowerStreet/dagster).

Both are now only applied with reproducible: true. For GowerStreet/dagster, turning them off cut the full-image step from 493s to 206s and the web/daemon steps from ~320s to 129s.

5. Startup timing in the log

The step log prints how long the inner docker daemon took to come up and how long registry login took.

Image

gowerstreet/plugin-docker-buildx:latest

Minimal example

steps:
  publish:
    image: gowerstreet/plugin-docker-buildx
    settings:
      repo: gowerstreet/myapp
      tags: ${CI_COMMIT_SHA}
      username:
        from_secret: docker_username
      password:
        from_secret: docker_password

This will:

  • Build and push gowerstreet/myapp:<sha>
  • Pull cache from gowerstreet/myapp:buildcache (first run: miss; subsequent runs: fast)
  • Push updated cache to gowerstreet/myapp:buildcache
  • Remove the ephemeral BuildKit builder and its state volume on completion

Keeping in sync with upstream

git remote add upstream https://github.com/woodpecker-ci/plugin-docker-buildx.git
git fetch upstream
git merge upstream/main

Our changes are confined to plugin/impl.go, cmd/docker-buildx/config.go, and plugin/impl_test.go, so merges are usually clean.

License

Apache-2.0 — see LICENSE.

About

Fork of woodpecker-ci/plugin-docker-buildx with purge fix and GC defaults

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages