[Home](https://codefionn.eu/) · [About](https://codefionn.eu/about/) · [GitHub](https://github.com/codefionn)

---

# Rust Builkit CICD Pipeline

> A basic rust buildkit CICD pipeline with cross platform compilation

*Published on 2025-02-26 · [View as HTML](https://codefionn.eu/rust-builkit-cicd-pipeline/)*

---


The following files create an buildkit CICD pipeline with cross platform
compilation support for `x86-64`, `aarch64` and `riscv64gc` for *Rust*. Also,
the program is compiled with *musl*, so the resulting image is as small as
possible.

The tests output cobertura files (via `cargo-tarpaulin`) for use in your
git-platform (e.g. Gitlab).

Also, this whole pipeline has been run with *podman* in the background with
*docker-buildx* installed but using the *podman* context, so it can be run
without root privileges.

You will have to modify the pipeline further to fit your program and upload the
resulting docker images to a registry.

Run the whole pipeline with:

```sh
docker buildx bake default lint clippy test
```

Your `docker-bake.hcl`-file:

```hcl
target "default" {
  platforms = [
    "linux/amd64",
    "linux/arm64",
    "linux/riscv64",
  ]
  output = ["type=cacheonly"]
}


target "lint" {
    target = "lint"
    output = ["type=cacheonly"]
}

target "clippy" {
    target = "clippy"
    output = ["type=cacheonly"]
}

target "test" {
    target = "test-results"
    output = [
      "type=local,dest=.",
    ]
}
```

Your `Dockerfile`:

```Dockerfile
# syntax=docker/dockerfile:1

# Script for converting Go's TARGETPLATFORM to Rust's target triple
# (also comes with RUSTFLAGS settings)
FROM --platform=${BUILDPLATFORM} docker.io/python:3.14-rc-alpine AS build-env
ARG TARGETPLATFORM
RUN <<EOFCMD
python <(cat << EOF
import os

targetplatform = os.environ.get("TARGETPLATFORM")
default_flags = " -C target-feature=+crt-static"

with open ("/env", "w") as f:
    f.write("#!/bin/sh\n")
    if targetplatform == "linux/riscv64":
        f.write("export RUST_TARGET=riscv64gc-unknown-linux-musl\n")
        f.write("export RUSTFLAGS='-C linker=riscv64-linux-gnu-gcc" + default_flags + "'\n")
    elif targetplatform == "linux/arm64":
        f.write("export RUST_TARGET=aarch64-unknown-linux-musl\n")
        f.write("export RUSTFLAGS='-C linker=aarch64-linux-gnu-gcc" + default_flags + "'\n")
    elif targetplatform == "linux/amd64":
        f.write("export RUST_TARGET=x86_64-unknown-linux-musl\n")
        f.write("export RUSTFLAGS='" + default_flags + "'\n")
EOF
)
EOFCMD
RUN chmod uga+x /env

# Prepare the base image (for cross-compilation)
FROM --platform=${BUILDPLATFORM} docker.io/rust:1.85-bookworm AS base
# Install rust tools (with caching between target platforms)
RUN rustup component add rustfmt
RUN rustup component add clippy
RUN cargo install cargo-tarpaulin
# Install the correct compiler for the target platform
ARG TARGETPLATFORM
RUN apt-get update -y
RUN if [ "$TARGETPLATFORM" = "linux/riscv64" ]; then apt-get install -y gcc-riscv64-linux-gnu; fi
RUN if [ "$TARGETPLATFORM" = "linux/arm64" ]; then apt-get install -y gcc-aarch64-linux-gnu; fi
# Configure the rust target specific toolchain
COPY --from=build-env /env /env
RUN . /env; rustup target add $RUST_TARGET

FROM base AS toml-files
WORKDIR /src
RUN echo "// dummy file" > ./src/main.rs
COPY Cargo.toml Cargo.lock ./

FROM toml-files AS fetch
RUN . /env; cargo fetch --locked --target "$RUST_TARGET"

# Copy all source files to the container now
FROM fetch AS fetch-with-files
COPY . .

FROM fetch-with-files AS clippy
RUN cargo clippy --all-targets --all-features -- -D warnings

FROM fetch-with-files AS lint
RUN cargo fmt --check

FROM fetch-with-files AS test
RUN cargo-tarpaulin --engine llvm --out Html --out Xml --output-dir /target/coverage

FROM scratch AS test-results
COPY --from=test /target/coverage/ /target/coverage/

FROM fetch-with-files AS build
ARG TARGETPLATFORM
RUN --mount=type=cache,id=cargo-build-${TARGETPLATFORM},dst=/src/target . /env; cargo build --release --target $RUST_TARGET
RUN --mount=type=cache,id=cargo-build-${TARGETPLATFORM},dst=/src/target . /env; mkdir /app; cp -r ./target/$RUST_TARGET/release/* /app
RUN ls

FROM scratch AS final
COPY --from=build /app/ /app/
CMD ["/app/my-app"]
```

Your `.dockerignore`:

```gitignore
/.git
/.gitignore
/target
**/target
/docker-backe.hcl
/Dockerfile
/.vscode
/docs
/README.md
```

---

[Impressum](https://codefionn.eu/impressum/) · [Datenschutzerklärung](https://codefionn.eu/datenschutz/) · [Mastodon](https://c.im/@codefionn)

© Copyright 2022-2026 Fionn Langhans
