Docker and Rust: Containerizing Applications from A to Z

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: Why Docker and Rust Are the Perfect Pair



Modern software development requires not only writing efficient code but also creating a reliable environment for its execution. Rust — a systems programming language known for its performance and memory safety — is ideal for building high-load services. Docker, in turn, provides lightweight and isolated containers that allow you to package an application with all its dependencies.



Combining these two technologies gives developers a powerful tool: a compiled Rust binary placed in a minimal container runs quickly, securely, and predictably on any platform. In this article, we will go from a simple example to a production-ready solution, examine common mistakes, and learn how to optimize images.



Basics: Creating a Simple Rust Application in Docker



Step 1. Preparing a Rust Project



First, let's create a simple web application in Rust using the popular framework actix-web. This is not mandatory, but it provides a clear example of working with the network inside a container.



Create a new project:



cargo new rust-docker-appcd rust-docker-app


Add the dependency to Cargo.toml:



[dependencies]actix-web = "4"


Replace the contents of src/main.rs with:



use actix_web::{web, App, HttpServer, Responder};

async fn index() -> impl Responder { "Hello from Rust in Docker!"}

#[actix_web::main]async fn main() -> std::io::Result<()> { HttpServer::new(|| { App::new().route("/", web::get().to(index)) }) .bind("0.0.0.0:8080")? .run() .await}


Step 2. A Simple Dockerfile



A basic Dockerfile for a Rust application looks like this:



FROM rust:latest

WORKDIR /appCOPY . .

RUN cargo build --release

EXPOSE 8080

CMD ["./target/release/rust-docker-app"]


This approach works but has serious drawbacks: the image becomes very large (over 1 GB), and each rebuild re-downloads all dependencies.



Optimization: Multi-stage Build and Reducing Image Size



Multi-stage Build



A key technique for Rust developers is using a multi-stage build. The idea is simple: in the first stage, we use a full image with the compiler and tools, and in the second stage, we use a minimal image into which we copy only the finished binary.



# Stage 1: BuildFROM rust:latest AS builder

WORKDIR /appCOPY Cargo.toml Cargo.lock ./RUN mkdir src && echo "fn main() {}" > src/main.rsRUN cargo build --release 2>/dev/null || true

COPY src/ src/RUN cargo build --release

# Stage 2: Minimal imageFROM debian:bookworm-slim

WORKDIR /appCOPY --from=builder /app/target/release/rust-docker-app .

EXPOSE 8080CMD ["./rust-docker-app"]


Why does this work? The first RUN cargo build caches the dependencies. When you change only the source code, Docker does not rebuild the dependencies from scratch, which speeds up the build significantly.



Using Alpine for Maximum Compression



If you need a minimal image size, use alpine as the final stage. Rust binaries are statically linked, so no additional libraries are required.



# Final stage with AlpineFROM alpine:latest

WORKDIR /appCOPY --from=builder /app/target/release/rust-docker-app .

EXPOSE 8080CMD ["./rust-docker-app"]


The image size can then be as small as 5–15 MB instead of 1+ GB!



Advanced Techniques: Caching and Security



Caching Dependencies with sccache



For large projects, you can use

Blogs

Book Recommendations