There are many ready-to-use images on Docker Hub. You can also find an official image here: https://hub.docker.com/_/rust/. But we will create our own image since official images contain a stable compiler version only. If it's enough for you, it's better to use official images, but if you use crates such as diesel, which need the nightly version of the Rust compiler, you will have to build your own image to build microservices.
Create a new Dockerfile and add the following content to it:
FROM buildpack-deps:stretch
ENV RUSTUP_HOME=/usr/local/rustup
CARGO_HOME=/usr/local/cargo
PATH=/usr/local/cargo/bin:$PATH
RUN set -eux;
url="https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init";
wget "$url";
chmod +x rustup-init;
./rustup-init -y --no-modify-path --default-toolchain nightly;
rm rustup-init;
chmod -R a+w $RUSTUP_HOME $CARGO_HOME;
rustup --version;
cargo --version;
rustc --version;
I've borrowed this Dockerfile from the official Rust Docker image located here: https://github.com/rust-lang-nursery/docker-rust-nightly/blob/master/nightly/Dockerfile. This file is a good starting point for good practices when creating images with the Rust compiler.
Our Rust image is based on the buildpack-deps image, which contains all of the necessary dependencies commonly used by developers. This dependency is indicated in the first line with the FROM command.
The next line, which contains the ENV command, sets three environment variables in the image:
- RUSTUP_HOME: Sets the root folder of the rustup utility, which contains a configuration and installs toolchains
- CARGO_HOME: Contains cached files used by the cargo utility
- PATH: The system environment variable that contains paths to executable binaries
We target all utilities to the /usr/local folder by setting these environment variables.
The last Dockerfile command, RUN, is complex and we will analyze this set of commands line by line. The first shell command is the following:
set -eux
Since the default shell in Ubuntu is the Bash shell, we can set three useful flags:
- -e: This flag tells the shell to run the next line (command) only if the previous one finished successfully
- -u: With this flag, the shell will print an error to stderr if the command tries to expand a variable that is not set
- -x: With this flag, the shell will print every command to stderr before running it
The next three lines download the rustup-init binary and set the executable flag to the downloaded file:
url="https://static.rust-lang.org/rustup/dist/x86_64-unknown-linux-gnu/rustup-init";
wget "$url";
chmod +x rustup-init;
The next pair runs the rustup-init command with parameters and removes the binary after running:
./rustup-init -y --no-modify-path --default-toolchain nightly;
rm rustup-init;
The following flags were used:
- -y: Suppresses any confirmation prompts
- --no-modify-path: Won't modify the PATH environment variable (we set it manually before, for the image)
- --default-toolchain: The type of the default toolchain (we will use nightly)
The remaining lines set write permissions to the RUSTUP_HOME and CARGO_HOME folders and print the version for all the installed tools:
chmod -R a+w $RUSTUP_HOME $CARGO_HOME;
rustup --version;
cargo --version;
rustc --version;
Now you can build the Dockerfile to get an image that contains the preconfigured Rust compiler:
docker build -t rust:nightly .
This command takes some time to complete, but after it has finished, you will have an image that you can use as a base for building images for microservices. If you type the docker images command, you will see something like this:
REPOSITORY TAG IMAGE ID CREATED SIZE
rust nightly 91e52fb2cea5 About an hour ago 1.67GB
Now we will use the image tagged as rust:nightly and create images for microservices from it. Let's start by creating an image for the users microservice.