[Rust - Docker] Docker build and run Rust Rocket Web app with multi-stage builds

Rust Rocket Docker with multiple build stages

Rocket is a web framework for Rust. Rocket aims to be fast, easy, and flexible while offering guaranteed safety and security where it can. Importantly, Rocket also aims to be fun, and it accomplishes this by ensuring that you write as little code as needed to accomplish your task.

Multistage builds are useful to anyone who has struggled to optimize Dockerfiles while keeping them easy to read and maintain. See Use multi-stage builds | Docker Documentation - https://docs.docker.com/develop/develop-images/multistage-build/ to learn more.

Prerequites

Docker

Docker is an open platform for developing, shipping, and running applications. Docker enables you to separate your applications from your infrastructure so you can deliver software quickly. With Docker, you can manage your infrastructure in the same ways you manage your applications. By taking advantage of Docker’s methodologies for shipping, testing, and deploying code quickly, you can significantly reduce the delay between writing code and running it in production.

See Get Docker | Docker Documentation - https://docs.docker.com/get-docker/ to learn more.

Installing Rust

Rocket makes use of the latest Rust features. Because of this, we’ll need a recent release of Rust to run Rocket applications. If you already have a working installation of the latest Rust compiler, feel free to skip to the next section.

1
2
3
4
5
# Install rustup by following the instructions
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Ensure the latest toolchain is installled by running the command
$ rustup default stable

See rustup.rs - The Rust toolchain installer - https://rustup.rs/ to learn more.


Note: You may prefer to develop using the nightly channel.

The nightly Rust toolchain enables certain improved developer experiences, such as better compile-time diagnostics, when developing with Rocket. You may choose to develop on the nightly channel to take advantage of these improved experiences. Note that all Rocket features are available across all Rust channels.

To set the nightly toolchain as your default, run rustup default nightly.


Initialize

Let’s write our first Rocket application! Start by creating a new binary-based Cargo project and changing into the new directory:

1
2
3
$ cargo new col-rust-rocket-docker-example --bin

cd col-rust-rocket-docker-example

Now, add Rocket as a dependency in your Cargo.toml:

1
2
3
4
# Cargo.toml

[dependencies]
rocket = "0.5.0-rc.1"

Make main.rs file

1
2
3
4
5
6
7
8
9
10
11
12
13
// src/main.rs

#[macro_use] extern crate rocket;

#[get("/")]
fn index() -> &'static str {
"Hello, world!"
}

#[launch]
fn rocket() -> _ {
rocket::build().mount("/", routes![index])
}

It creates an index route, mounts the route at the / path, and launches the application.

See Getting Started - Rocket Programming Guide - https://rocket.rs/v0.5-rc/guide/getting-started/ to learn more.

Dockerfile

Base Image

Create or edit Dockerfile-base file to base image for the system and Rust packages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Dockerfile-base

ARG RUST_VERSION=1.56.1
FROM rust:1.56.1 AS Builder

RUN rustup target add x86_64-unknown-linux-musl

RUN apt-get update -qq && \
apt-get install -y \
musl-tools \
musl-dev

RUN update-ca-certificates

ARG WORD_DIR=/app
WORKDIR ${WORD_DIR}

COPY ./ .

RUN cargo build --target x86_64-unknown-linux-musl --release

Build base image.

1
$ docker build . -f Dockerfile-base -t cloudolife/col-rust-docker-example-base

Final Image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# FROM scratch
FROM gcr.io/distroless/cc

FROM cloudolife/col-rust-docker-example-base AS Builder

ARG WORD_DIR=/app
WORKDIR ${WORD_DIR}

ARG APP=col-rust-docker-example

# Copy our build
COPY --from=Builder ${WORD_DIR}/target/x86_64-unknown-linux-musl/release/${APP} ${WORD_DIR}

COPY Rocket.toml ${WORD_DIR}

EXPOSE 8000

CMD ["./col-rust-docker-example"]

Build final image.

1
$ docker build . -f Dockerfile-base -t cloudolife/col-rust-docker-example

Run

1
2
3
4
$ docker run --rm --name col-rust-docker-example -p 8000:8000 cloudolife/col-rust-docker-example

# Mount current dir
# $ docker run --rm --name col-rust-docker-example -p 8000:8000 -v ${PWD}:/app cloudolife/col-rust-docker-example

Image Size

Compare images size:

1
2
3
$ docker images | grep col-rust-docker-example
cloudolife/col-rust-docker-example latest 93e6a17091d8 11 hours ago 37.6MB
cloudolife/col-rust-docker-example-base latest 8de13e91834c 18 hours ago 3.13GB

FAQS

Make sure you also have the development packages of openssl installed.

1
2
3
4
5
6
#12 790.6   run pkg_config fail: "pkg-config has not been configured to support cross-compilation.\n\nInstall a sysroot for the target platform and configure it via\nPKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a\ncross-compiling wrapper for pkg-config and set it via\nPKG_CONFIG environment variable."

#12 790.5 error: failed to run custom build command for `openssl-sys v0.9.72`

#12 550.3 Make sure you also have the development packages of openssl installed.
#12 550.3 For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.

Add openssl dependency to fix that issue.

1
2
3
4
# Cargo.toml

[dependencies]
openssl = { version = "0.10", features = ["vendored"] }

See Ubuntu 18: failed to run custom build command for openssl-sys v0.9.39 · Issue #1021 · sfackler/rust-openssl - https://github.com/sfackler/rust-openssl/issues/1021 to learn more.

References

[1] [Getting Started - Rocket Programming Guide - https://rocket.rs/v0.5-rc/guide/getting-started/])(https://rocket.rs/v0.5-rc/guide/getting-started/)

[2] Get Docker | Docker Documentation - https://docs.docker.com/get-docker/

[3] rustup.rs - The Rust toolchain installer - https://rustup.rs/

[4] GoogleContainerTools/distroless: 🥑 Language focused docker images, minus the operating system. - https://github.com/GoogleContainerTools/distroless

[5] Use multi-stage builds | Docker Documentation - https://docs.docker.com/develop/develop-images/multistage-build/

[6] Dockerfile reference | Docker Documentation - https://docs.docker.com/engine/reference/builder/

[7] Rust - Official Image | Docker Hub - https://hub.docker.com/_/rust

[8] johnthagen/min-sized-rust: 🦀 How to minimize Rust binary size 📦 - https://github.com/johnthagen/min-sized-rust

[9] How to create small Docker images for Rust - https://kerkour.com/rust-small-docker-image/