---
title: "Rust e Docker: Builds Otimizados para Produção — 2026"
url: "https://rustlang.com.br/blog/rust-docker-builds-otimizados-producao-2026/"
markdown_url: "https://rustlang.com.br/blog/rust-docker-builds-otimizados-producao-2026.MD"
description: "Aprenda a criar imagens Docker otimizadas para aplicações Rust com multi-stage builds, cargo-chef, cache de dependências e boas práticas de segurança."
date: "2026-04-23"
author: "Equipe Rust Brasil"
---

# Rust e Docker: Builds Otimizados para Produção — 2026

Aprenda a criar imagens Docker otimizadas para aplicações Rust com multi-stage builds, cargo-chef, cache de dependências e boas práticas de segurança.


## Introdução

Compilar Rust dentro de um container Docker pode ser frustrante: builds de 15 minutos, imagens de 2 GB e cache que nunca funciona direito. Se você já passou por isso, este guia é para você. Vamos construir um pipeline Docker que gera imagens de **menos de 10 MB**, com builds incrementais rápidos e seguros para produção.

O segredo está em combinar **multi-stage builds**, **cache inteligente de dependências** e **targets estáticos** com musl. Essas técnicas são usadas por empresas como Cloudflare e Discord nos seus serviços Rust em produção.

---

## O Problema: Build Ingênuo

O Dockerfile mais básico para Rust compila tudo em uma única imagem:

```dockerfile
FROM rust:1.88
WORKDIR /app
COPY . .
RUN cargo build --release
CMD ["./target/release/meu-app"]
```

Esse approach tem três problemas graves:

1. **Imagem gigante** (~1.4 GB): inclui o compilador Rust, todas as ferramentas de build e código-fonte
2. **Sem cache de dependências**: qualquer mudança no código recompila todas as crates
3. **Superfície de ataque**: ferramentas de desenvolvimento disponíveis em produção

---

## Multi-Stage Build: A Base

A primeira otimização é separar o build da imagem final:

```dockerfile
# Stage 1: Build
FROM rust:1.88-slim AS builder
WORKDIR /app
COPY . .
RUN cargo build --release

# Stage 2: Runtime
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/meu-app /usr/local/bin/
USER 1000
CMD ["meu-app"]
```

A imagem final cai de 1.4 GB para ~80 MB. Mas ainda recompilamos tudo a cada mudança no código. Vamos resolver isso.

---

## Cache de Dependências com cargo-chef

O [cargo-chef](https://github.com/LukeMathWalker/cargo-chef) é a ferramenta padrão da comunidade para cache de dependências em Docker. Ele funciona em três etapas:

1. **Planner**: analisa seu projeto e gera um "recipe" — um plano de build das dependências
2. **Cacher**: compila apenas as dependências a partir do recipe
3. **Builder**: compila seu código-fonte usando o cache das dependências

```dockerfile
# Stage 1: Planner
FROM rust:1.88-slim AS planner
WORKDIR /app
RUN cargo install cargo-chef
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

# Stage 2: Cache de dependências
FROM rust:1.88-slim AS cacher
WORKDIR /app
RUN cargo install cargo-chef
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json

# Stage 3: Build
FROM rust:1.88-slim AS builder
WORKDIR /app
COPY --from=cacher /app/target target
COPY --from=cacher /usr/local/cargo /usr/local/cargo
COPY . .
RUN cargo build --release

# Stage 4: Runtime
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y ca-certificates && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/meu-app /usr/local/bin/
USER 1000
CMD ["meu-app"]
```

Agora, quando você altera apenas código-fonte, o Docker reutiliza o cache do stage 2. O tempo de rebuild cai de 10+ minutos para **segundos** em muitos casos.

### Usando com Cargo Workspaces

Se seu projeto usa [Cargo workspaces](/blog/cargo-workspaces-monorepos-rust-2026/), o cargo-chef funciona sem alterações. Ele detecta automaticamente a estrutura do workspace e gera o recipe correto para todos os crates.

---

## Binários Estáticos com musl: Imagens Mínimas

Para imagens realmente pequenas, compile com o target `x86_64-unknown-linux-musl` e use `scratch` ou `alpine` como base:

```dockerfile
# Stage 1: Build estático
FROM rust:1.88-slim AS builder
RUN apt-get update && apt-get install -y musl-tools && rm -rf /var/lib/apt/lists/*
RUN rustup target add x86_64-unknown-linux-musl

WORKDIR /app
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl

# Stage 2: Imagem mínima
FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/meu-app /
USER 1000
ENTRYPOINT ["/meu-app"]
```

O resultado? Uma imagem Docker de **5-10 MB** contendo apenas seu binário e certificados SSL. Sem shell, sem package manager, sem nada que um atacante possa explorar.

### Quando Não Usar musl

Nem toda crate compila limpo com musl. Projetos que dependem de linkagem dinâmica com bibliotecas C (como OpenSSL direto) podem ter problemas. Alternativas:

- Use `rustls` em vez de `openssl` para TLS — funciona perfeitamente com musl
- Para crates que usam [SQLx](/ecossistema/sqlx/) com PostgreSQL, considere `debian:bookworm-slim` em vez de `scratch`
- Se usar [Diesel](/ecossistema/diesel/), compile com as features corretas para linkagem estática

---

## Otimizações Avançadas de Build

### Perfil de Release Otimizado

Configure seu `Cargo.toml` para gerar binários menores:

```toml
[profile.release]
opt-level = "z"      # Otimizar para tamanho
lto = true           # Link-Time Optimization
codegen-units = 1    # Compilação mais lenta, binário menor
panic = "abort"      # Remove overhead de unwinding
strip = true         # Remove símbolos de debug
```

Essas opções podem reduzir o binário de 20 MB para 3-5 MB. O trade-off é um tempo de compilação maior — perfeito para builds de [CI/CD](/artigos/ci-cd-rust/) onde o tamanho da imagem importa.

### Cache com BuildKit

O Docker BuildKit oferece cache de montagem que persiste entre builds:

```dockerfile
FROM rust:1.88-slim AS builder
WORKDIR /app
COPY . .
RUN --mount=type=cache,target=/usr/local/cargo/registry \
    --mount=type=cache,target=/app/target \
    cargo build --release && \
    cp target/release/meu-app /usr/local/bin/meu-app
```

O diretório `target/` e o registry do [Cargo](/ecossistema/cargo/) são preservados entre builds, proporcionando compilação verdadeiramente incremental.

---

## Segurança em Produção

### Usuário Não-Root

Nunca rode seu aplicativo como root. Use um usuário sem privilégios:

```dockerfile
FROM debian:bookworm-slim
RUN groupadd -r appuser && useradd -r -g appuser appuser
COPY --from=builder --chown=appuser:appuser /app/target/release/meu-app /usr/local/bin/
USER appuser
CMD ["meu-app"]
```

### Scanning de Vulnerabilidades

Integre scanning de vulnerabilidades no pipeline:

```bash
# Scan da imagem Docker
docker scout cve meu-app:latest

# Scan das dependências Rust
cargo audit
cargo deny check
```

O `cargo audit` verifica suas dependências contra o banco de dados [RustSec](https://rustsec.org/). Combinado com [tratamento de erros robusto](/blog/tratamento-erros-rust-thiserror-anyhow/) e [testes abrangentes](/blog/testes-rust-estrategias-boas-praticas-2026/), você tem uma aplicação sólida para produção.

### Health Checks

Adicione health checks ao seu Dockerfile:

```dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
    CMD ["/usr/local/bin/meu-app", "--health-check"]
```

Se sua aplicação usa [Axum](/blog/axum-web-framework-rust-2026/), implemente um endpoint `/health`:

```rust
use axum::{Router, routing::get};

async fn health_check() -> &'static str {
    "OK"
}

let app = Router::new()
    .route("/health", get(health_check));
```

---

## Exemplo Completo: API Web com Axum

Juntando tudo — cargo-chef, musl, segurança — em um Dockerfile de produção:

```dockerfile
FROM rust:1.88-slim AS planner
WORKDIR /app
RUN cargo install cargo-chef
COPY . .
RUN cargo chef prepare --recipe-path recipe.json

FROM rust:1.88-slim AS cacher
WORKDIR /app
RUN apt-get update && apt-get install -y musl-tools && rm -rf /var/lib/apt/lists/*
RUN rustup target add x86_64-unknown-linux-musl
RUN cargo install cargo-chef
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --target x86_64-unknown-linux-musl --recipe-path recipe.json

FROM rust:1.88-slim AS builder
WORKDIR /app
RUN apt-get update && apt-get install -y musl-tools && rm -rf /var/lib/apt/lists/*
RUN rustup target add x86_64-unknown-linux-musl
COPY --from=cacher /app/target target
COPY --from=cacher /usr/local/cargo /usr/local/cargo
COPY . .
RUN cargo build --release --target x86_64-unknown-linux-musl

FROM scratch
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/minha-api /
USER 1000
EXPOSE 3000
ENTRYPOINT ["/minha-api"]
```

Resultado: imagem de ~8 MB com build incremental rápido e superfície de ataque mínima.

---

## Comparativo de Tamanho de Imagens

| Estratégia | Tamanho da Imagem | Tempo de Rebuild |
|---|---|---|
| Build simples (`rust:1.88`) | ~1.4 GB | 10-15 min |
| Multi-stage + Debian slim | ~80 MB | 10-15 min |
| Multi-stage + cargo-chef | ~80 MB | ~30 seg |
| musl + scratch | ~5-10 MB | 10-15 min |
| cargo-chef + musl + scratch | ~5-10 MB | ~30 seg |

---

## Perguntas Frequentes

### Qual a melhor imagem base para Rust em produção?

Para tamanho mínimo e segurança máxima, use `scratch` com binários compilados para musl. Se sua aplicação precisa de ferramentas do sistema ou bibliotecas C dinâmicas, use `debian:bookworm-slim`.

### O que é cargo-chef e por que usar?

cargo-chef é uma ferramenta que separa o build de dependências do build do seu código. Ele gera um "recipe" que permite ao Docker cachear a camada de dependências, evitando recompilações desnecessárias.

### Posso usar Alpine Linux em vez de scratch?

Sim. Alpine usa musl por padrão, então binários compilados com o target musl rodam nativamente. A imagem final fica em torno de 10-15 MB — um pouco maior que scratch, mas com shell e package manager disponíveis para debugging.

### Como debugar uma imagem scratch em produção?

Use `docker debug` (Docker Desktop) ou crie uma imagem de debug separada baseada em `debian:bookworm-slim` com ferramentas de diagnóstico. Mantenha a imagem de produção limpa e use [logging com tracing](/ecossistema/tracing/) para observabilidade.

---

## Conclusão

Docker e Rust são uma combinação poderosa quando feitos direito. Com multi-stage builds, cargo-chef e targets estáticos, você consegue imagens de produção minúsculas e seguras, sem sacrificar a velocidade de desenvolvimento.

As técnicas deste artigo se aplicam igualmente a projetos simples e a [monorepos com Cargo workspaces](/blog/cargo-workspaces-monorepos-rust-2026/). Se você está montando um pipeline de [CI/CD para Rust](/artigos/ci-cd-rust/), combine essas práticas com [testes automatizados](/blog/testes-rust-estrategias-boas-praticas-2026/) para um fluxo de deploy confiável.

Para quem está explorando outras linguagens com Docker, compare as estratégias de containerização com <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go</a> (que também gera binários estáticos nativamente) e <a href="https://python.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'python.dev.br' })">Python</a> (onde o tamanho de imagem é um desafio maior).

### Leia Também

- [Rust 1.88: Let Chains, Naked Functions e Novidades](/blog/rust-1-88-let-chains-naked-functions-2026/)
- [Axum: Construindo APIs Web de Alta Performance](/blog/axum-web-framework-rust-2026/)
- [Cargo Workspaces: Organizando Projetos Grandes](/blog/cargo-workspaces-monorepos-rust-2026/)
- [CI/CD para Projetos Rust](/artigos/ci-cd-rust/)
- [Testes em Rust: Estratégias e Boas Práticas](/blog/testes-rust-estrategias-boas-praticas-2026/)
