Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optimising cargo build times in Docker

I am developing an API with Rust, and am managing the environments, including the external database with Docker. Every time I make a change to the API code, cargo rebuilds, and since Docker doesn't cache anything to do with the ADD statement to copy the Rust directory over to the container, it re-downloads all the packages, which is a fairly lengthy process since I'm using Nickel, which seems to have a boatload of dependencies.

Is there a way to bring those dependencies in prior to running cargo build? At least that way if the dependencies change it will only install what's required, similar to Cargo compiling locally.

Here's the Dockerfile I currently use:

FROM ubuntu:xenial
RUN apt-get update && apt-get install curl build-essential ca-certificates file xutils-dev nmap -y
RUN mkdir /rust
WORKDIR /rust
RUN curl https://sh.rustup.rs -s >> rustup.sh
RUN chmod 755 /rust/rustup.sh
RUN ./rustup.sh -y
ENV PATH=/root/.cargo/bin:$PATH SSL_VERSION=1.0.2h
RUN rustup default 1.11.0
RUN curl https://www.openssl.org/source/openssl-$SSL_VERSION.tar.gz -O && \
    tar -xzf openssl-$SSL_VERSION.tar.gz && \
    cd openssl-$SSL_VERSION && ./config && make depend && make install && \
    cd .. && rm -rf openssl-$SSL_VERSION*
ENV OPENSSL_LIB_DIR=/usr/local/ssl/lib \
    OPENSSL_INCLUDE_DIR=/usr/local/ssl/include \
    OPENSSL_STATIC=1
RUN mkdir /app
WORKDIR /app
ADD . /app/
RUN cargo build
EXPOSE 20000
CMD ./target/debug/api

And here's my Cargo.toml

[profile.dev]
debug = true

[package]
name = "api"
version = "0.0.1"
authors = ["Vignesh Sankaran <[email protected]>"]

[dependencies]
nickel = "= 0.8.1"
mongodb = "= 0.1.6"
bson = "= 0.3.0"
uuid = { version = "= 0.3.1", features = ["v4"] }
like image 470
Vignesh Sankaran Avatar asked Sep 23 '16 12:09

Vignesh Sankaran


People also ask

How do I speed up Docker build time?

The easiest way to increase the speed of your Docker image build is by specifying a cached image that can be used for subsequent builds. You can specify the cached image by adding the --cache-from argument in your build config file, which will instruct Docker to build using that image as a cache source.

Why is my Docker build taking too long?

If your Docker image builds takes a long time downloading dependencies, it's a good idea to check whether you're installing more than you need to. First, check if you might be downloading development dependencies which are not needed in your image at all.


1 Answers

Docker does cache the layer built from the ADD (preferably COPY) instruction, provided the sources haven't changed. You could make use of that and get your dependencies cached by copying the Cargo.toml in first, and doing a build.

But unfortunately you need something to build, so you could do it with a single source file and a dummy lib target in your manifest:

[lib]
name = "dummy"
path = "dummy.rs"

In your Dockerfile build the dummy separately:

COPY Cargo.toml /app/Cargo.toml
COPY dummy.rs /app/dummy.rs
RUN cargo build --lib

The output of this layer will be cached, with all the dependencies installed, and then you can go on to add the rest of your code (in the same Dockerfile):

COPY /src/ app/src/
RUN cargo build

The dummy stuff is ugly, but it means your normal build will be quick, as it comes from the cached layer, and when you change dependencies in your Cargo.toml then Docker will pick it up and build a new layer with updated dependencies.

like image 105
Elton Stoneman Avatar answered Sep 20 '22 10:09

Elton Stoneman