Recompile Docker Rust image without completly deleting it

Hi,

I'm currently running my Rust binary via a Dockerfile:

# Build stage
FROM rust:slim as builder

RUN apt-get update && \
  apt-get install -y pkg-config make g++ libssl-dev cmake libmariadb-dev-compat && \
  rustup target add x86_64-unknown-linux-gnu 

WORKDIR /var/www/app

COPY . .

RUN cargo build --release

# Prod stage
FROM gcr.io/distroless/cc
COPY --from=builder /var/www/app/target/release/isumis /

CMD ["./isumis"]

After every change in my code I have to delete the Docker image and rebuild it completly. Is there a solution to run the Container with my changes?

A simple way would be using Docker cache mount, i.e. replacing RUN cargo build --release with something like RUN --mount=type=cache,target=target cargo build --release.

A more specialized way is using cargo-chef

1 Like

You can optimize this by splitting your dependency build and updates, but in practice it's a pain to get cargo to actually build dependencies without actually using them in code.

For quicker turnaround, you might want to have a build from a "known good" version of the source first, something like:

# Build stage
FROM rust:slim as builder

RUN apt-get update && \
  apt-get install -y pkg-config make g++ libssl-dev cmake libmariadb-dev-compat && \
  rustup target add x86_64-unknown-linux-gnu 

WORKDIR /var/www/app

# other build files...
COPY Cargo.toml Cargo.lock .

# first build last known good, so we can at least already have the dependencies
COPY src-lkg src
RUN cargo build --release

COPY src src
RUN cargo build --release

And then you can copy over your src to src-lkg when you make major changes you don't want to have to rebuild.

There's a few other steps you can further decrease build times like not using --release or otherwise enable incremental builds.

Another option is to simply mount your local directory to the rust image using something docker run -v /your/host/project:/your/container/project, and use docker as essentially just a super-jail for the rust install, but that loses most of the value of being in docker in the first place, and performance of mounts may be an issue (depends on your OS and docker config)

1 Like

When I'm using cargo chef then my actix web program stops directly.

How are you using it?

# Build stage
FROM lukemathwalker/cargo-chef:latest-rust-1 AS chef

RUN apt-get update && \
  apt-get install -y pkg-config make g++ libssl-dev cmake libmariadb-dev-compat && \
  rustup target add x86_64-unknown-linux-gnu 

WORKDIR /var/www/app

FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

FROM chef AS builder
COPY --from=planner /var/www/app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json

COPY . .

RUN cargo build --release

# Prod stage, removing the Rust toolchain
FROM debian:buster-slim AS runtime
WORKDIR /var/www/app
COPY --from=builder /var/www/app/target/release/isumis /usr/local/bin

CMD ["/usr/local/bin/isumis"]

I don't see anything particularly problematic, except maybe that you might have to install ca-certificates in the prod stage if you use openssl in for actix-web https. You could also try using the gcr.io/distroless/cc image for the prod stage as you were doing before.

Instead of using cargo chef I test everything on my local machine and then create a Docker container afterwards. This is way more easier and it is not a waste of time testing everything.