Explosion Pills
Explosion Pills

Reputation: 191749

How can I get the Rust executable once it is built inside the Docker container?

I'm working on an macOS machine but I plan to run my executable on a Linux machine. I've found the jimmycuadra/rust Docker image which seems to suit my needs.

I do docker build . with the following Dockerfile in the current directory.

FROM jimmycuadra/rust

ADD my_project /my_project
WORKDIR /my_project
RUN cargo build --release --target=x86_64-unknown-linux-gnu

This seems to build the project properly, but once Docker exits, there is no target directory and there is no running container to docker cp from either.

How can I get the Rust executable once it is built inside the Docker container?

Upvotes: 2

Views: 2124

Answers (2)

mzabaluev
mzabaluev

Reputation: 892

You can directly run the images provided by the Rust development team on Docker Hub, and mount your source directory inside the image. You just need to be careful to also mount the directories that Cargo will use as cache, otherwise it will end up downloading packages and/or checking out source repositories for the dependencies with every new container run. Note that you should't bind-mount the entire /usr/local/cargo directory, because this is where the official images put the binaries and other stuff.

Here's the little shell script that I put in my executable path as cargo, and also symlinked as nightly-cargo:

#!/bin/sh

if [ $(basename "$0") = nightly-cargo ]; then
    rust_image=rustlang/rust:nightly
else
    rust_image=rust:latest
fi

echo "Running cargo in $rust_image"

docker run -t --rm --user $(id -u):$(id -g) \
    -v "$HOME"/.cargo/registry:/usr/local/cargo/registry \
    -v "$HOME"/.cargo/git:/usr/local/cargo/git \
    -v "$PWD":/mnt/crate --workdir /mnt/crate \
    $rust_image cargo "$@"

Updated: I have set up an automatically rebuilt image repository which allows the user to bind-mount the entire /usr/local/cargo. The caveat is that running rustup inside a container running one of these images with /usr/local/cargo bind-mounted may produce surprising results.

Upvotes: 0

joelnb
joelnb

Reputation: 1494

I think you are overcomplicating things here by having a Dockerfile (I could be wrong if your needs are actually more complex than what you have shown, if so please provide further information and I will edit this answer). When you run ADD in the Dockerfile you are copying your code into the built image but you never copy the built object out again (and in fact there is no way I know to do that using a Dockerfile). There is no 'nice' way to get the resulting binary out of the image.

I think something simpler like this command will suit your needs better (run it after changing to the directory containing your code):

docker run -it -v "$(pwd):/source" jimmycuadra/rust cargo build --release --target=x86_64-unknown-linux-gnu

This mounts the current directory as /source in the container (which is the default WORKDIR for the image you are using) and then builds your code, meaning the resulting executable will end up in the current folder:

ls target/x86_64-unknown-linux-gnu/release/

There is a slight problem with this - everything in the container runs as root and therefore the build artifacts get created with the owner set to the root user. This may cause issues for you trying to modify/remove them on your host later. To get around that you may be able to use something like this:

docker run -it -v "$(pwd):/source" jimmycuadra/rust sh -c "cargo build --release --target=x86_64-unknown-linux-gnu && chown -R $(id -u):$(id -g) ."

I say 'may' because I'm not sure if that will work on a Mac. I'm sure there is a way to achieve the same thing though.

Upvotes: 2

Related Questions