When installing Rust toolchain in Docker, Bash `source` command doesn't work

You have to add the sourcing inside the .bashrc.

This works:

FROM ubuntu:16.04

# Update default packages
RUN apt-get update

# Get Ubuntu packages
RUN apt-get install -y \
    build-essential \
    curl

# Update new packages
RUN apt-get update

# Get Rust
RUN curl https://sh.rustup.rs -sSf | bash -s -- -y

RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc

EDIT

Instead of

RUN echo 'source $HOME/.cargo/env' >> $HOME/.bashrc

you can use

ENV PATH="/root/.cargo/bin:${PATH}"

which is a less bash-only solution


The only thing source ~/.cargo/env does is

export PATH="$HOME/.cargo/bin:$PATH"

So my suggestion is to set PATH explicitly in your Dockerfile:

FROM ubuntu:16.04

# Update default packages
RUN apt-get -qq update

# Get Ubuntu packages
RUN apt-get install -y -q \
    build-essential \
    curl

# NOTE: no need to run update again at this point
# RUN apt-get update

# Get Rust; NOTE: using sh for better compatibility with other base images
RUN curl https://sh.rustup.rs -sSf | sh -s -- -y

# Add .cargo/bin to PATH
ENV PATH="/root/.cargo/bin:${PATH}"

# Check cargo is visible
RUN cargo --help

This is slightly more transparent than source .cargo/env, and easier to grasp if you're not familiar with Rust.

Also, note that there are rust images on DockerHub, you can use them (in FROM, instead of ubuntu:16.04) for running or building Rust apps. It will be faster and easier than installing everything via apt and curl.

For building apps there's a possibility you will find multistage docker builds useful. They are pretty flexible.


I think you may be misunderstanding what source does. This built-in command tells the current shell to load the following code (almost) as if it were being run at the current prompt (you can also use source inside other scripts). It's basically an "include file here" command. It's mostly used to set up your environment (PATH, LIBPATH, and other shell functions), not to do real work.

Running "source" in a RUN command is thus (almost always) useless. It will load up the cargo environment and then exit, thus losing all the environment changes.

This leaves you with two basic options. One is to do as michael_bitard suggests, and get it added to your .bashrc. This will mean that all commands forevermore in that container (by that user) will have the environment set up. If you only need this for setup, then it pollutes your shell environment at runtime.

The second option is to basically run the source as part of every RUN command that needs it in the rest of your Dockerfile. RUN bash -c 'source $HOME/.cargo/env; command goes here for example. This is more work on each RUN line, but the environment will be explicitly there when you need it, and not when you don't.

Most of the time, the first option is what you want. Rarely you want the second. That is, sometimes you only need this environment for setup purposes, and you don't want it to persist - this is rare, though I've had that scenario come up a few times.

Tags:

Linux

Docker

Bash