Here's an overview of the possibilities. (Scroll down for my original answer.)
- Add Cargo files, create fake
main.rs
/lib.rs
, then compile dependencies. Afterwards remove the fake source and add the real ones. [Caches dependencies, but several fake files with workspaces]. - Add Cargo files, create fake
main.rs
/lib.rs
, then compile dependencies. Afterwards create a new layer with the dependencies and continue from there. [Similar to above]. - Externally mount a volume for the cache dir. [Caches everything, relies on caller to pass
--mount
]. - Use
RUN --mount=type=cache,target=/the/path cargo build
in the Dockerfile in new Docker versions. [Caches everything, seems like a good way, but currently too new to work for me. Executable not part of image. Edit: See here for a solution.] - Run sccache in another container or on the host, then connect to that during the build process. See this comment in Cargo issue 2644.
- Use cargo-build-deps. [Might work for some, but does not support Cargo workspaces (in 2019)].
- Wait for Cargo issue 2644. [There's willingness to add this to Cargo, but no concrete solution yet].
- Using
VOLUME ["/the/path"]
in the Dockerfile does NOT work, this is per-layer (per command) only.
Note: one can set CARGO_HOME
and ENV CARGO_TARGET_DIR
in the Dockerfile to control where download cache and compiled output goes.
Also note: cargo fetch
can at least cache downloading of dependencies, although not compiling.
Cargo workspaces suffer from having to manually add each Cargo file, and for some solutions, having to generate a dozen fake main.rs
/lib.rs
. For projects with a single Cargo file, the solutions work better.
I've got caching to work for my particular case by adding
ENV CARGO_HOME /code/dockerout/cargoENV CARGO_TARGET_DIR /code/dockerout/target
Where /code
is the directory where I mount my code.
This is externally mounted, not from the Dockerfile.
EDIT1: I was confused why this worked, but @b.enoit.be and @BMitch cleared up that it's because volumes declared inside the Dockerfile only live for one layer (one command).