Build optimization for CI/CD

Dear rust community,

Firstly, I hope that all of you are fine and is ready for a better 2021 than 2020.

I'm trying to optimize our gitlab CI/CD workflow, because a very small codebase (2 endpoints using actix-web, and sending mails with lettre). I'm not author of this codebase, just acting as a devops for this.

I have many stages, that you can figure with this graph (please see dot code for this graph, if someone wants to edit)

digraph G {
    rankdir="LR";
    subgraph cluster_pre {
        label="Fetch";
        fetch
    }
    subgraph cluster_build {
        label="Build";
        buildDebug
        buildRelease
    }
    subgraph cluster_docker {
        label="Docker build";
        buildDocker
    }
    subgraph cluster_test {
        label="Tests";
        runTests
        runFmt
    }
    subgraph cluster_deploy {
        label="Deploy";
        deployment
    }
	fetch -> {buildDebug,buildRelease,runFmt}
    buildRelease->buildDocker->deployment
    buildDebug->runTests
}

So, as far as I know, I need a build with debug to run cargo test, and and need a build with --release for my docker build that will be deployed.

But a build is really expansive, so this kind of pipeline took ~40min.

Is it possible to build debug & release in the same time, with the same command, to be more efficient ? Maybe sharing cache with sccache while buildling debug and release builds ?

Other question, buildRelease and buildDocker are both musl linux, and I don't know why build into docker rebuild dependencies, even when I copy .cargo and target, both have exactly the same toolchain.
Currently my workaround is to add an if condition in dockerfile, to run cargo build only if the binary doesnt exists.

Thanks for your help,
Gaël

Replying here rather than Matrix because it feels more public.

It futurenhs-platform/workspace-service-branch.yaml at master · FutureNHS/futurenhs-platform · GitHub we used cargo build --release and cargo test --release because we found that it was quicker and used less space in our CI's build cache than running cargo test in debug mode (assets built in debug mode are not usable by the compiler in release mode and vice versa, so it will need to rebuild everything).

We also don't allow docker to build images at all, because it's dog-slow. Our dockerfile explodes if you try to docker build on your mac. futurenhs-platform/Dockerfile at master · FutureNHS/futurenhs-platform · GitHub. Originally we were building everything inside docker, but we realised that we don't ever need to build docker images on our macs (we just run the mac binaries locally with cargo watch -x run for local development, and the branch-build pushes to our docker repo so we can argocd app sync if we need it running in a cluster). Switching from building-inside-docker to building-in-ci allowed us to go from >10minute builds to ~3 minute builds: Speed up Rust builds: build outside Docker and caching cargo dirs by frigus02 · Pull Request #231 · FutureNHS/futurenhs-platform · GitHub.

Hopefully there's answers to your questions in there somewhere.

Ahhhh ! With cargo test --release, it should be the right answer, with that I will not longer needs the buildDebug !
With RUN [ -f /tmp/target/release/<binary> ] || cargo build --release --frozen in CI, the dockerfile will not require to rebuild the whole project, and being working outside this context.

I still needs to understand why I cannot copy cache into dockerfile to fasten development :confused:

My needs are not quite the same but the way I reuse artifacts between docker builds is by mapping /usr/local/cargo/registry to the same volume between docker builds:

I'm not sure, debug, release and bench profiles can use different compiler flags and optimisations so there might not be enough room for sharing. See e.g. Saving Recompilations with --release - #11 by mbrubeck for inspiration.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.