Perkecil Docker Image: Multi-stage Build dari 2GB ke 80MB

Perkecil Docker Image: Multi-stage Build dari 2GB ke 80MB

Build pertama berjalan mulus, image sukses di-push, lalu pipeline deploy gagal: no space left on device. Registry mulai komplain, pull lambat, dan CI yang dulu 2 menit jadi 8 menit. Penyebab paling umum bukan kode aplikasi — melainkan image yang membawa jauh lebih banyak dari yang seharusnya: compiler toolchain, dependency build-time, file sampah, dan base image raksasa yang tidak pernah dirapikan.

Panduan ini membedah cara mengecilkan image Docker dari skala GB ke skala puluhan MB memakai multi-stage build, tanpa mengorbankan keamanan.

1. Ukur Dulu: Apa yang Memakan Tempat

docker images                            # lihat ukuran image
docker history myapp:latest --no-trunc   # lihat kontribusi tiap layer
dive myapp:latest                        # inspeksi per layer (tool interaktif)

Temuan paling sering:

  • Build toolchain (gcc, make, JDK) ikut terbawa karena hanya ada satu RUN stage
  • apt-get install tanpa --no-install-recommends dan tanpa membersihkan /var/lib/apt/lists
  • Dependency dev (node_modules penuh source test) di-copy ke runtime
  • .env, .git, dan cache build ikut masuk karena .dockerignore tidak ada

2. Multi-stage Build: Prinsipnya

Satu Dockerfile, dua (atau lebih) stage. Stage pertama dipakai untuk build — boleh gemuk. Stage terakhir adalah runtime — hanya berisi hasil jadi. Builder stage tidak pernah masuk ke image final.

Contoh aplikasi Node.js:

# ---- Stage 1: build ----
FROM node:20 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build          # hasil: dist/

# ---- Stage 2: runtime ----
FROM node:20-slim
ENV NODE_ENV=production
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev      # hanya production deps
COPY --from=builder /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]

Hasil ukuran (kasus nyata, Express + TypeScript):

Pendekatan Ukuran
node:20 penuh, 1 stage ±1.4 GB
node:20-slim, 1 stage (deps + src) ±480 MB
Multi-stage + npm ci –omit=dev ±120 MB
Distroless / alpine runtime final ±80 MB

3. Pilih Base Image yang Tepat

Base Ukuran Cocok untuk
ubuntu:24.04 / debian:12 ~70–120 MB Butuh banyak binary sistem
alpine:3.20 ~7 MB (di atas scratch) Budget ketat; berhati-hatilah: musl libc kadang beda perilaku
*-slim (node:20-slim, python:3.12-slim) ~40–80 MB Rasio aman/kecil — pilihan default
gcr.io/distroless/*-debian12 terkecil, tanpa shell Runtime final saat build di stage lain; attack surface paling kecil

Catatan: distroless tidak punya shell — debugging pakai docker exec tidak bisa. Untuk produksi yang sudah stabil, ini justru kelebihan.

4. Contoh Python (FastAPI): dari 1.1GB ke 95MB

FROM python:3.12 AS builder
WORKDIR /app
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

FROM python:3.12-slim
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
WORKDIR /app
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Trik serupa untuk Go: build statik RUN CGO_ENABLED=0 go build -o /app, lalu stage final cuma FROM scratch + binary — image bisa di bawah 10 MB.

5. Aturan Penghematan yang Selalu Berlaku

  1. Layer order — copy file yang jarang berubah dulu (requirements.txt, package.json), source code belakangan. Build cache tidak bakal invalidasi install dependency tiap kali commit.
  2. Bersihkan dalam satu RUN — RUN apt-get update && apt-get install -y --no-install-recommends gcc && apt-get purge -y gcc && rm -rf /var/lib/apt/lists/*. Terpisah-pisah = tiap layer tetap membawa sisa.
  3. .dockerignore wajib — .git, node_modules, __pycache__, .env, dist/, berkas lokal.
  4. Jangan COPY “.” yang kotor — salin spesifik: hanya folder src/ + artefak build.
  5. Audit security — setelah optimasi jalankan trivy image myapp:latest; image kecil biasanya juga lebih sedikit CVE-nya.

6. Verifikasi Hasil

docker build -t myapp:slim .
dive myapp:slim                 # periksa layer terbuang
docker run --rm myapp:slim      # tes jalan normal
trivy image myapp:slim          # scan kerentanan
docker push registry/myapp:slim

Bandingkan docker images sebelum/sesudah, lalu pantau waktu pull di environment staging — biasanya turun drastis.

Kesimpulan

Multi-stage build adalah perbaikan dengan rasio usaha-hasil terbaik di ekosistem Docker: satu file Dockerfile, ukuran image turun 5–10x, waktu deploy membaik, dan attack surface berkurang. Ukur dulu dengan dive, pahami layer mana yang gemuk, lalu pisahkan fase build dari runtime. Mulai dari base image -slim, tambahkan distroless kalau butuh lebih ringan lagi.

Perkecil Docker Image: Multi-stage Build dari 2GB ke 80MB
Categories: Sains
Oentoro:
X

Headline

You can control the ways in which we improve and personalize your experience. Please choose whether you wish to allow the following:

Privacy Settings