Por que Rust e Docker são a combinação perfeita?
\n\nImagine: você criou uma aplicação super rápida em Rust que processa milhões de requisições por segundo. Ela compila para um binário estático, não precisa de máquina virtual e, em alguns cenários, é mais rápida que C++. Mas como levar essa obra-prima da engenharia para o servidor? Como garantir que ela funcione exatamente igual na máquina do desenvolvedor, no CI/CD e em produção?
\n\nA resposta é simples — containerizar aplicações Rust com Docker. O Docker permite empacotar sua aplicação com todas as dependências em um contêiner leve. E o Rust, por sua natureza, torna esse processo incrivelmente eficiente. Neste artigo, não vamos apenas escrever um Dockerfile — vamos transformar seu binário em uma obra-prima de containerização.
\n\nSe você já conhece desenvolvimento em Rust, mas quer dominar DevOps para projetos Rust, está no lugar certo. Vamos nessa!
\n\nO problema do Dockerfile "ingênuo" para Rust
\n\nIniciantes geralmente escrevem algo assim:
\n\nFROM rust:latest\nWORKDIR /app\nCOPY . .\nRUN cargo build --release\nCMD ["./target/release/my_app"]\n\nIsso funciona. Mas vamos ser sinceros: essa abordagem é como dirigir uma Ferrari em uma estrada de terra. Por quê?
\n\n- \n
- Imagem gigantesca — ~1.5 GB por causa do compilador e ferramentas de build \n
- Rebuild lento — o cache de dependências não é aproveitado \n
- Vulnerabilidades — a imagem contém pacotes desnecessários \n
- Violando boas práticas — o runtime não deve conter o compilador \n
A verdadeira containerização de aplicações Rust exige uma abordagem mais inteligente. E o nome dela é build multi-estágio (multi-stage build).
\n\nContainerização correta do Rust: build multi-estágio
\n\nA ideia é simples: o primeiro estágio é o "andaime de construção", onde o compilador vive. O segundo é o "runtime" limpo, que recebe apenas o binário pronto. Vamos colocar isso em prática.
\n\nPasso 1: Dockerfile básico
\n\nCrie um arquivo Dockerfile na raiz do seu projeto Rust (ao lado do Cargo.toml):
# ====================\n# Estágio 1: Build\n# ====================\nFROM rust:1.77-slim-bookworm AS builder\n\n# Cria um projeto vazio para cachear dependências\nRUN USER=root cargo new /app\nWORKDIR /app\n\n# Copia apenas os manifestos (para cachear camadas)\nCOPY Cargo.toml Cargo.lock ./\n\n# Compila as dependências (esta camada é cacheada se Cargo.toml não mudar)\nRUN cargo build --release 2>/dev/null || true\n\n# Agora copia o código-fonte\nCOPY src ./src\n\n# Compila a aplicação (apenas arquivos modificados)\nRUN cargo build --release\n\n# ====================\n# Estágio 2: Imagem mínima\n# ====================\nFROM debian:bookworm-slim AS runtime\n\n# Instala dependências mínimas (se necessário)\n# RUN apt-get update && apt-get install -y ca-certificates tzdata && rm -rf /var/lib/apt/lists/*\n\n# Copia o binário do builder\nCOPY --from=builder /app/target/release/my_app /usr/local/bin/my_app\n\n# Configurações para produção\nENV RUST_LOG=info\nENV APP_ENV=production\n\n# Executa como usuário não privilegiado\nRUN useradd -m -u 1000 appuser\nUSER appuser\n\nEXPOSE 8080\nCMD ["my_app"]\n\nRepare na mágica com COPY Cargo.toml Cargo.lock ./ e cargo build antes de copiar o código-fonte. Esse é o truque essencial para otimizar o build Docker do Rust: o Docker cacheia as camadas e, enquanto você não mudar as dependências, esse estágio não será recompilado. Economia de tempo — de 5 a 15 minutos por build!
Passo 2: Usando Alpine (emagrecimento extremo)
\n\nSe você quer uma imagem com menos de 10 MB, use alpine:
# O estágio de build permanece o mesmo\n\n# Estágio 2: Alpine\nF