A container for my CI builds
Find a file
2025-12-11 00:06:08 +00:00
.woodpecker ci: fix variable expansion in Woodpecker pipelines 2025-11-16 07:26:04 +01:00
.hadolint.yaml fix: replace pushd/popd with cd commands for POSIX compliance 2025-11-01 23:54:50 +01:00
Dockerfile chore(deps): update ghcr.io/cocogitto/cog:latest docker digest to 10a5a58 2025-12-10 23:06:47 +00:00
LICENSE.md feat: add basic image 2025-11-01 18:00:57 +01:00
README.md fix: test release 2025-11-15 14:40:26 +00:00
renovate.json chore(deps): add renovate.json 2025-11-01 19:04:45 +00:00

rust-build-env

This is a ready-to-use Docker image for building and crosscompiling Rust projects. It ships with Rust (via rustup), common cross targets, Zig, cargozigbuild, cargoaudit, cargoedit, cocogitto (cog), sccache, yq, lipo, specdown, nfpm, and cosign. Its designed to feel at home in Woodpecker CI, but it works just as well on your laptop with docker run.

You can pull it from codeberg.org/purplebooth/rust-build-env. Most folks use the main tag for the latest build, or a specific version tag like vX.Y.Z when they want something pinned.

docker pull codeberg.org/purplebooth/rust-build-env:main

What's inside (in plain English)

You get the standard Rust toolchain managed by rustup and a bunch of targets preinstalled so you can crosscompile right away: macOS (x86_64-apple-darwin, aarch64-apple-darwin), Windows (aarch64-pc-windows-gnullvm, x86_64-pc-windows-gnu), and Linux (both glibc and musl for x86_64 and aarch64). Rustfmt and Clippy are there too.

Zig 0.15.1 is included so cargo-zigbuild works out of the box. The image also includes cargo-zigbuild 0.20.1, cargo-audit 0.21.2, cargo-binstall 1.14.1, cargo-edit 0.13.7 (so cargo add, rm, set-version, and upgrade are available), cog 6.4.0 (from cocogitto), sccache 0.12.0, yq 4.48.1, lipo 0.10.0, and specdown 1.2.112. Youll also find nfpm for packaging and cosign 3.0.2 for signing and verification. The base is Ubuntu with the usual build tools and OpenSSL headers, and theres a nonroot user (nonroot) already set up with sudo if you want it.

The containers working directory is /app. Rust lives under /usr/local/rustup and /usr/local/cargo, and the tools are on PATH.

Quick starts

If you just want to compile your project, mount it at /app and run Cargo like you normally would.

docker run --rm -it \
  -v "$PWD":/app \
  -w /app \
  codeberg.org/purplebooth/rust-build-env:main \
  cargo build

Crosscompiling to a static Linux binary is straightforward with cargo-zigbuild.

docker run --rm -it \
  -v "$PWD":/app \
  -w /app \
  codeberg.org/purplebooth/rust-build-env:main \
  cargo zigbuild --release --target x86_64-unknown-linux-musl

If you need a universal macOS binary, build both architectures and glue them together with lipo.

docker run --rm -it \
  -v "$PWD":/app \
  -w /app \
  codeberg.org/purplebooth/rust-build-env:main \
  bash -lc '
    cargo zigbuild --release --target aarch64-apple-darwin && \
    cargo zigbuild --release --target x86_64-apple-darwin && \
    lipo -create target/aarch64-apple-darwin/release/<binary> \
                 target/x86_64-apple-darwin/release/<binary> \
         -o target/<binary>-universal'

Windows builds work the same way; just point at a Windows target.

docker run --rm -it \
  -v "$PWD":/app \
  -w /app \
  codeberg.org/purplebooth/rust-build-env:main \
  cargo zigbuild --release --target x86_64-pc-windows-gnu

If you want to speed things up, enable sccache by setting two environment variables when you run the container. The cache directory already exists in the image at /var/cache/sccache.

docker run --rm -it \
  -e RUSTC_WRAPPER=/usr/local/bin/sccache \
  -e SCCACHE_DIR=/var/cache/sccache \
  -v "$PWD":/app \
  -w /app \
  codeberg.org/purplebooth/rust-build-env:main \
  cargo build

Using it in Woodpecker CI

You dont need anything fancy to use this image in Woodpecker. Point a step at the image and run Cargo. If you want builds to be snappy across pipelines, mount a couple of host volumes for the Cargo and sccache directories.

Heres a simple pipeline that runs on pushes and pull requests and builds and tests your Rust project. It turns on sccache and caches both Cargo and sccache between runs using host volumes on the Woodpecker agent.

when:
  - event: push
  - event: pull_request

steps:
  - name: build-and-test
    image: codeberg.org/purplebooth/rust-build-env:main
    environment:
      RUSTC_WRAPPER: /usr/local/bin/sccache
      SCCACHE_DIR: /var/cache/sccache
    volumes:
      - name: cargo-cache
        path: /usr/local/cargo
      - name: sccache-cache
        path: /var/cache/sccache
    commands:
      - cargo fetch
      - cargo build --locked
      - cargo test --all --locked

volumes:
  - name: cargo-cache
    host:
      path: /var/lib/woodpecker/cargo
  - name: sccache-cache
    host:
      path: /var/lib/woodpecker/sccache

If youre producing a crosscompiled release, you can add another step that targets musl and saves the binary somewhere your pipeline expects. This example writes to a dist/ folder, which many release plugins look for.

- name: build-musl-release
  image: codeberg.org/purplebooth/rust-build-env:main
  environment:
    RUSTC_WRAPPER: /usr/local/bin/sccache
    SCCACHE_DIR: /var/cache/sccache
  volumes:
    - name: cargo-cache
      path: /usr/local/cargo
    - name: sccache-cache
      path: /var/cache/sccache
  commands:
    - mkdir -p dist
    - cargo zigbuild --release --target x86_64-unknown-linux-musl
    - cp target/x86_64-unknown-linux-musl/release/<binary> dist/

And if you want a quick security check as part of CI, add a cargo-audit step. It takes seconds and will fail the build if known vulnerabilities are present in your dependency tree.

- name: audit
  image: codeberg.org/purplebooth/rust-build-env:main
  commands:
    - cargo generate-lockfile || true
    - cargo audit

Those examples are intentionally minimal. Feel free to sprinkle in formatting, packaging with nfpm, or signing artifacts with cosign 3.0.2 if your workflow needs it.

Notes on users and paths

The image creates a nonroot user with passwordless sudo, but it doesnt force you to use it. By default, containers run as root in CI unless you set user: nonroot (or --user) yourself. Either way, the Rust and Cargo directories under /usr/local are writable and already on the PATH.

License

This project is released under The Unlicense. See LICENSE.