Python #

Di ekosistem Java kita mengenal fat JAR, di Node.js ada node_modules, sementara di Python—terutama Django—biang masalah ukuran Docker image hampir selalu adalah dependency Python + OS package.

Tidak sedikit aplikasi Django sederhana yang berakhir dengan image 500–800 MB, padahal logikanya hanya CRUD API. Artikel ini membahas secara mendetail, praktis, dan engineering-driven bagaimana membuat Docker image Django yang ramping, aman, dan production-grade, setara filosofi distroless di Java.

Realita Ukuran Docker Image Django #

Tanpa Optimasi #

SetupUkuran Image
python:latest + pip install600–900 MB
python:slim (tanpa cleanup)350–500 MB

Dengan Optimasi #

SetupUkuran Image
python:slim + multi-stage180–250 MB
distroless python90–140 MB
bundling + distroless50–80 MB

⚠️ Jika image Django kamu >300 MB, hampir pasti ada dependency atau OS package yang bocor ke runtime.


Kenapa Image Django Mudah Membengkak? #

Python Tidak Memisahkan Build vs Runtime #

Banyak package Python:

  • Perlu compiler (gcc, make)
  • Perlu header OS (libpq-dev, openssl-dev)

Jika tidak dipisahkan, semua ini ikut masuk image final.

Dependency C Extension #

Contoh umum:

  • psycopg2
  • Pillow
  • cryptography

Mereka membutuhkan library native saat build.

pip Tidak Prune Secara Otomatis #

Berbeda dengan npm atau Maven, pip tidak punya konsep dev vs prod dependency bawaan.


Prinsip Utama Mengecilkan Image Python #

Semua tool build harus mati di runtime image.

Runtime Django idealnya hanya berisi:

  • Python runtime
  • Virtual environment
  • Dependency runtime
  • Source code

Pendekatan 1: Multi-stage Build (Fondasi Wajib) #

Dockerfile Dasar (Belum Optimal) #

# =====================
# Build stage
# =====================
FROM python:3.12-slim AS builder

WORKDIR /app

RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
 && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN python -m venv /venv \
 && /venv/bin/pip install --upgrade pip \
 && /venv/bin/pip install -r requirements.txt

# =====================
# Runtime stage
# =====================
FROM python:3.12-slim

WORKDIR /app

COPY --from=builder /venv /venv
COPY . .

ENV PATH="/venv/bin:$PATH"
EXPOSE 8000
CMD ["gunicorn", "config.wsgi:application"]

Ukuran: 180–250 MB (sudah jauh lebih baik).


Pendekatan 2: Pisahkan Dependency Build vs Runtime #

Gunakan Binary Wheel #

Contoh:

  • psycopg2-binary
  • uvicorn[standard]

Ini menghindari kebutuhan compiler di runtime.

Hindari *-dev Package di Runtime #

Runtime tidak perlu:

  • gcc
  • make
  • header library

Pendekatan 3: Distroless untuk Python #

Dockerfile Django + Distroless #

FROM python:3.12-slim AS builder
WORKDIR /app

RUN apt-get update && apt-get install -y \
    build-essential \
 && rm -rf /var/lib/apt/lists/*

COPY requirements.txt .
RUN python -m venv /venv \
 && /venv/bin/pip install --no-cache-dir -r requirements.txt

FROM gcr.io/distroless/python3-debian12
WORKDIR /app

COPY --from=builder /venv /venv
COPY . .

ENV PATH="/venv/bin:$PATH"
EXPOSE 8000
CMD ["/venv/bin/gunicorn", "config.wsgi:application"]

Ukuran Realistis #

Tipe AppUkuran
Django API sederhana90–110 MB
Django + ORM + auth110–140 MB

Pendekatan 4: Dependency Audit (Sering Diabaikan) #

Banyak proyek Django membawa:

  • django-debug-toolbar
  • testing libs (pytest, factory-boy)
  • migration helper

Pisahkan:

  • requirements.txt (prod)
  • requirements-dev.txt

Pendekatan 5: Bundling Python (Advanced) #

Gunakan:

  • PyInstaller
  • Nuitka

Contoh: PyInstaller #

pyinstaller manage.py --onefile

Runtime:

FROM gcr.io/distroless/base-debian12
WORKDIR /app
COPY manage .
CMD ["./manage"]

Ukuran Akhir #

👉 50–80 MB

Namun:

  • build lebih kompleks
  • debugging lebih sulit

Perbandingan Pendekatan #

PendekatanVirtualenvDistrolessUkuranKompleksitas
Slim onlyYaTidakBesarRendah
Multi-stageYaTidakSedangMenengah
DistrolessYaYaKecilMenengah
BundlingTidakYaSangat kecilTinggi

Trade-off yang Wajib Dipahami #

Debugging #

  • Distroless: tidak ada shell
  • Bundling: stack trace minimal

Native Dependency #

  • Lebih sensitif dibanding Node/Java

Observability #

  • Logging harus STDOUT
  • Error harus eksplisit

Kapan Pendekatan Mana Paling Tepat? #

KondisiRekomendasi
Django monolithslim + multi-stage
API productiondistroless
Serverlessbundling
Banyak native libslim + audit

Penutup #

Python bukan ekosistem yang “container-friendly” secara default. Image besar bukan karena Django buruk, tapi karena:

  • build dan runtime sering dicampur
  • dependency native tidak diaudit
  • base image dipilih sembarangan

Dengan disiplin yang sama seperti Java distroless, Django bisa berjalan di image <150 MB, bahkan <100 MB.

Masalahnya bukan di Python—tapi di kebiasaan engineering yang terlalu memanjakan runtime.

“Container kecil bukan hasil trik Docker, tapi hasil kejelasan batas antara build dan runtime.”

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