Rust #

Rust sering diposisikan sebagai “bahasa paling ideal” untuk container karena mampu menghasilkan single static binary. Akibatnya, banyak engineer mengira Docker untuk Rust itu trivial: build → copy binary → selesai.

Realitanya, Rust di production tetap punya jebakan:

  • image membengkak karena glibc
  • build time lama
  • TLS & libc dependency tidak disadari
  • debug & observability sering diabaikan

Artikel ini membahas strategi Docker image Rust yang kecil, aman, dan benar-benar production-grade, bukan sekadar demo FROM scratch.

Realita Ukuran Docker Image Rust #

Tanpa Strategi #

SetupUkuran Image
rust:latest (single stage)1.2–1.6 GB
rust + slim runtime150–250 MB

Dengan Strategi yang Benar #

SetupUkuran Image
Multi-stage + slim40–80 MB
Distroless15–40 MB
Scratch (static)5–15 MB

Masalah Utama Rust di Docker #

1. Build Toolchain Sangat Besar #

  • rustc
  • cargo
  • LLVM

Semua ini harus 100% berhenti di build stage.

2. Static Binary Itu Opsional, Bukan Default #

Secara default:

  • Rust link ke glibc
  • butuh runtime OS

Static binary harus disengaja.

3. TLS & libc adalah Silent Dependency #

Crate seperti:

  • reqwest
  • openssl
  • native-tls

Bisa menarik dependency runtime tanpa disadari.


Prinsip Utama Image Rust Production #

Runtime image Rust idealnya hanya berisi binary + cert (opsional).

Tidak ada:

  • shell
  • package manager
  • OS tool

Strategi 1: Multi-stage Build (Wajib) #

Dockerfile Dasar #

FROM rust:1.76 AS builder
WORKDIR /app

# Cache dependency
COPY Cargo.toml Cargo.lock ./
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN cargo build --release

# Build real app
COPY src ./src
RUN cargo build --release

FROM debian:12-slim
WORKDIR /app
COPY --from=builder /app/target/release/app ./app
CMD ["./app"]

Ukuran: 40–80 MB.


Strategi 2: Distroless Rust #

FROM rust:1.76 AS builder
WORKDIR /app
COPY . .
RUN cargo build --release

FROM gcr.io/distroless/cc-debian12
WORKDIR /app
COPY --from=builder /app/target/release/app ./app
CMD ["./app"]

Ukuran: 15–40 MB.

Catatan:

  • cocok untuk glibc binary
  • debugging minimal

Strategi 3: Static Binary + Scratch (Paling Kecil) #

Build Static #

FROM rust:1.76 AS builder
WORKDIR /app

RUN rustup target add x86_64-unknown-linux-musl

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

FROM scratch
COPY --from=builder /app/target/x86_64-unknown-linux-musl/release/app /app
CMD ["/app"]

Ukuran: 5–15 MB.


TLS & Certificate #

Static binary tidak membawa CA cert.

Solusi:

  • embed cert
  • atau copy dari builder
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/

Optimasi Binary Size #

Gunakan:

RUSTFLAGS="-C strip=symbols" \
  cargo build --release

Atau:

strip target/release/app

Tambahan:

  • LTO
  • panic = "abort"

Observability & Production Concerns #

Logging #

  • structured logging
  • STDOUT

Metrics #

  • expose /metrics

Healthcheck #

  • HTTP based

Security & Runtime Safety #

AspekRust
Memory safety
Non-rootDefault
Attack surfaceSangat kecil

Perbandingan Strategi #

StrategiUkuranKompleksitasRekomendasi
debian-slimSedangRendahDefault
distrolessKecilMenengahProduction
scratchSangat kecilTinggiHigh performance

Kapan Strategi Mana Digunakan? #

KondisiPilihan
Microservicedistroless
High securityscratch
Banyak native TLSdistroless

Penutup #

Rust adalah bahasa paling dekat dengan ideal container runtime, tapi tetap bisa gagal di production jika:

  • dependency tidak dipahami
  • TLS & libc diabaikan
  • observability dilupakan

Docker image kecil di Rust bukan prestasi, tapi baseline. Yang membedakan engineer matang adalah stabilitas, security, dan operasionalnya.

Rust membuat image kecil itu mudah. Engineering membuatnya layak production.

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact