Memilih Container Image: Alpine, Debian, Ubuntu atau Distroless?
Panduan memilih container image untuk Docker dan Podman. Bandingkan Alpine, Debian Slim, Ubuntu, Fedora, Rocky, UBI, Distroless, BusyBox, dan scratch lengkap dengan matrix dan contoh Dockerfile.
Memilih base image bukan sekadar memilih image yang paling kecil. Untuk Docker maupun Podman, keputusan ini memengaruhi ukuran image, waktu build dan pull, kompatibilitas library, kemudahan debugging, security surface, sampai kenyamanan tim ketika aplikasi masuk production.
Kesalahan yang sering terjadi adalah langsung memilih Alpine karena terkenal kecil. Padahal untuk sebagian workload, Debian Slim atau Ubuntu justru membuat hidup developer dan operator lebih sederhana. Sebaliknya, untuk runtime production tertentu, Distroless atau bahkan scratch dapat mengurangi komponen yang tidak diperlukan.
Artikel ini membandingkan beberapa keluarga container image dari yang sangat minimal sampai yang lebih lengkap, lalu memberikan matrix praktis untuk membantu memilih.
Catatan penting: kolom Ukuran relatif di bawah ini adalah kategori praktis, bukan angka MB yang absolut. Ukuran aktual berubah berdasarkan tag, arsitektur CPU, package yang ditambahkan, dan layer image.
Matrix utama: diurutkan berdasarkan ukuran relatif
Urutan matrix ini sengaja dibuat dari image yang secara umum paling minimal menuju image yang relatif lebih lengkap. Ini bukan berarti semua tag dari satu keluarga selalu lebih kecil daripada semua tag keluarga berikutnya.
| Urutan | Image / Family | Ukuran relatif | libc | Package ecosystem | Debugging | Security surface | Compatibility | Cocok untuk |
|---|---|---|---|---|---|---|---|---|
| 1 | Scratch | Ekstrem kecil | Tidak ada | Tidak ada | Sangat sulit | Sangat kecil | Tergantung aplikasi | Static binary, runtime sangat minimal |
| 2 | Distroless | Sangat kecil | Umumnya glibc | Minimal/tanpa package manager | Sulit | Sangat kecil | Tergantung aplikasi | Production runtime |
| 3 | BusyBox | Sangat kecil | Bervariasi | Sangat minimal | Terbatas | Sangat kecil | Terbatas | Utility, troubleshooting, image minimal |
| 4 | Alpine | Sangat kecil | musl | apk | Mudah–sedang | Kecil | Sedang | Utility, microservice, workload kompatibel |
| 5 | Debian Slim | Kecil–sedang | glibc | apt | Mudah | Relatif kecil | Tinggi | Production general-purpose |
| 6 | Fedora | Sedang | glibc | dnf | Sangat mudah | Sedang | Tinggi | Linux modern, development |
| 7 | Ubuntu | Sedang–besar | glibc | apt | Sangat mudah | Lebih besar | Sangat tinggi | Development, aplikasi kompleks |
| 8 | Rocky Linux | Sedang–besar | glibc | dnf | Sangat mudah | Sedang | Tinggi | Enterprise/RHEL-compatible |
| 9 | AlmaLinux | Sedang–besar | glibc | dnf | Sangat mudah | Sedang | Tinggi | Enterprise/RHEL-compatible |
| 10 | UBI | Bervariasi | glibc | microdnf/dnf | Mudah | Terkontrol | Tinggi | Enterprise production |
Kenapa Scratch ada di posisi pertama?
scratch bukan Linux distribution lengkap. Ia pada dasarnya adalah titik awal kosong untuk image.
Contoh sederhana:
FROM scratch
COPY myapp /myapp
ENTRYPOINT ["/myapp"]
Ini sangat menarik untuk static binary seperti aplikasi Go yang benar-benar tidak membutuhkan userland Linux tambahan.
Namun konsekuensinya besar: tidak ada shell, package manager, CA certificates, timezone database, atau utility umum secara default.
Jadi:
Image paling kecil belum tentu image paling mudah dioperasikan.
1. Scratch
Scratch cocok ketika aplikasi sudah membawa hampir semua yang dibutuhkan saat runtime.
Contoh umum adalah aplikasi Go yang dibuat sebagai static binary.
FROM golang:alpine AS build
WORKDIR /src
COPY . .
RUN CGO_ENABLED=0 go build -o app .
FROM scratch
COPY --from=build /src/app /app
ENTRYPOINT ["/app"]
Kelebihan:
- Image sangat minimal.
- Attack surface sangat kecil.
- Tidak ada package manager yang perlu dipatch.
- Cocok untuk immutable runtime.
Kekurangan:
- Tidak ada shell.
- Debugging jauh lebih sulit.
- CA certificates dan timezone data harus disediakan bila diperlukan.
- Tidak semua aplikasi dapat berjalan dengan baik.
Scratch lebih cocok untuk runtime yang benar-benar terkontrol daripada sebagai default semua aplikasi.
2. Distroless
Distroless dirancang untuk menjalankan aplikasi tanpa membawa userland lengkap seperti shell dan package manager.
Contoh konsepnya:
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM gcr.io/distroless/nodejs22-debian12
WORKDIR /app
COPY --from=build /app .
CMD ["server.js"]
Keuntungannya:
- Runtime sangat minimal.
- Tidak membawa tool development yang tidak diperlukan.
- Attack surface lebih kecil dibanding image general-purpose.
- Cocok untuk pola build once, run many.
Kekurangannya:
- Debugging lebih sulit.
- Tidak ada shell pada image runtime standar.
- Troubleshooting harus mengandalkan observability, ephemeral debug container, atau proses debug dari image builder.
Untuk production, ini menarik ketika pipeline dan observability sudah matang.
3. BusyBox
BusyBox menggabungkan banyak Unix utility dalam footprint yang sangat kecil.
Contoh:
podman run --rm busybox sh
BusyBox sangat berguna untuk:
- troubleshooting container,
- utility image,
- init/helper sederhana,
- eksperimen Linux minimal.
Namun BusyBox bukan pilihan universal untuk application runtime karena compatibility dan library environment-nya lebih terbatas.
4. Alpine Linux
Alpine populer karena ukurannya kecil dan memiliki package manager apk.
FROM alpine:latest
RUN apk add --no-cache curl ca-certificates
CMD ["sh"]
Kelebihan:
- Kecil.
- Cepat untuk pull dalam banyak skenario.
- Package manager tersedia.
- Cocok untuk utility dan banyak microservice.
- Ekosistem container sangat luas.
Hal pentingnya adalah Alpine menggunakan musl libc, bukan glibc.
Perbedaan libc dapat memengaruhi:
- binary native,
- Python package tertentu,
- Node.js native addon,
- Java/native library,
- aplikasi yang bergantung pada behavior glibc,
- tooling pihak ketiga.
Jadi jangan memilih Alpine hanya karena ukurannya kecil.
5. Debian Slim
Debian Slim sering menjadi kompromi yang sangat praktis.
FROM debian:bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates curl \
&& rm -rf /var/lib/apt/lists/*
Kelebihan:
- Menggunakan glibc.
- Compatibility luas.
- apt tersedia.
- Familiar bagi banyak developer Linux.
- Cocok untuk production general-purpose.
Jika aplikasi bermasalah di Alpine karena dependency native atau compatibility, Debian Slim sering menjadi titik tengah yang masuk akal.
6. Fedora
Fedora menggunakan glibc dan ekosistem RPM dengan dnf.
podman run --rm -it fedora:latest bash
Fedora menarik untuk:
- development environment modern,
- eksperimen teknologi Linux terbaru,
- tooling yang dekat dengan ekosistem Red Hat.
Untuk runtime production, pilihan sebaiknya mengikuti requirement aplikasi dan standardisasi organisasi, bukan sekadar popularitas distribution.
7. Ubuntu
Ubuntu adalah salah satu pilihan paling familiar bagi developer.
FROM ubuntu:24.04
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
Kelebihan:
- Compatibility sangat luas.
- Dokumentasi dan komunitas besar.
- apt tersedia.
- Nyaman untuk development dan aplikasi dengan dependency kompleks.
Kekurangannya adalah image general-purpose biasanya membawa lebih banyak komponen dibanding image minimal.
Untuk development, ini sering justru menjadi keuntungan karena debugging lebih nyaman.
8. Rocky Linux dan AlmaLinux
Rocky Linux dan AlmaLinux berada di keluarga enterprise Linux yang kompatibel dengan ekosistem RHEL.
Keduanya cocok ketika aplikasi atau organisasi membutuhkan:
- glibc,
- RPM/dnf,
- pola enterprise Linux,
- kompatibilitas dengan software yang ditujukan untuk ekosistem RHEL.
Contoh:
podman run --rm -it rockylinux:9 bash
atau:
podman run --rm -it almalinux:9 bash
Untuk workload enterprise, compatibility dengan platform target biasanya lebih penting daripada mengejar image sekecil mungkin.
9. Red Hat UBI
Red Hat Universal Base Image atau UBI ditujukan untuk application container yang membutuhkan base image dari ekosistem Red Hat.
UBI memiliki beberapa varian sehingga ukurannya tidak bisa dipukul rata.
Pertimbangannya biasanya meliputi:
- standardisasi enterprise,
- lifecycle dan support model,
- compatibility dengan ekosistem Red Hat,
- security dan compliance requirements.
Jika organisasi sudah menggunakan Red Hat ecosystem, UBI dapat menjadi bagian penting dari standardisasi container base image.
Matrix berdasarkan kebutuhan
| Kebutuhan | Pilihan yang relevan | Alasan utama |
|---|---|---|
| Static Go binary | Scratch | Runtime sangat minimal |
| Production runtime minimal | Distroless | Minim komponen runtime |
| Utility kecil | BusyBox / Alpine | Tool dasar dengan footprint kecil |
| Microservice umum | Alpine / Debian Slim | Balance ukuran dan usability |
| Dependency native kompleks | Debian Slim / Ubuntu | glibc dan compatibility luas |
| Development container | Ubuntu / Fedora | Tooling dan debugging nyaman |
| RHEL-compatible workload | Rocky / Alma / UBI | Enterprise Linux ecosystem |
| Troubleshooting container | BusyBox / Alpine | Shell dan utility tersedia |
| Image untuk tim yang belum matang observability-nya | Debian Slim / Ubuntu | Debugging lebih mudah |
Alpine vs Debian Slim: keputusan yang paling sering muncul
Banyak tim akhirnya membandingkan dua pilihan ini.
Pilih Alpine jika
- dependency sudah terbukti kompatibel dengan musl;
- image kecil menjadi requirement nyata;
- aplikasi sederhana;
- runtime tidak membutuhkan banyak native dependency;
- tim sudah memiliki testing dan observability yang baik.
Pilih Debian Slim jika
- aplikasi menggunakan banyak native library;
- compatibility glibc penting;
- debugging production perlu lebih mudah;
- tim ingin mengurangi kejutan compatibility;
- penghematan ukuran Alpine tidak memberikan manfaat signifikan.
Perbedaan puluhan atau ratusan MB tidak selalu penting jika aplikasi hanya di-deploy beberapa container. Tetapi jika ada ribuan image pull, registry traffic, cold start, atau bandwidth terbatas, ukuran image dapat menjadi faktor operasional yang lebih berarti.
Jangan mengukur image hanya dari compressed size
Ada beberapa ukuran yang perlu dibedakan:
- Compressed image size — ukuran yang ditransfer registry.
- Uncompressed size — ukuran layer setelah diekstrak.
- Runtime memory — RAM yang digunakan aplikasi.
- Disk usage — storage yang digunakan node.
- Build cache — storage tambahan pada builder.
Image 100 MB tidak otomatis membuat aplikasi menggunakan RAM 100 MB.
Begitu juga image 20 MB tidak otomatis membuat aplikasi lebih cepat.
Multi-stage build: cara mendapatkan image kecil tanpa mengorbankan build tooling
Salah satu teknik paling penting adalah memisahkan build image dan runtime image.
Contoh Node.js:
FROM node:22 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-bookworm-slim
WORKDIR /app
COPY --from=build /app/package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
CMD ["node", "dist/server.js"]
Build stage boleh besar karena berisi compiler dan development tools. Runtime stage hanya membawa yang dibutuhkan aplikasi.
Pola ini biasanya lebih aman daripada memaksakan satu image super-minimal yang sekaligus menjadi build environment.
Cara memilih secara praktis
Gunakan decision tree sederhana berikut:
Apakah aplikasi bisa berjalan sebagai static binary?
|
Ya
|
Apakah debugging runtime sangat minimal
dapat diterima?
|
Ya --> Scratch
|
Tidak --> Distroless / image minimal lain
Tidak
|
Apakah dependency native sangat sensitif?
|
Ya --> Debian Slim / Ubuntu
|
Tidak
|
Apakah image sangat kecil merupakan requirement?
|
Ya --> Alpine, setelah compatibility test
|
Tidak
|
Apakah environment enterprise RHEL-compatible?
|
Ya --> UBI / Rocky / AlmaLinux
|
Tidak --> Debian Slim / Ubuntu / Fedora
Tips memilih base image
1. Pin major/minor version
Hindari bergantung sepenuhnya pada latest untuk production.
Gunakan tag yang sesuai dengan lifecycle aplikasi dan lakukan update secara terkontrol.
2. Scan image secara rutin
Base image tetap memiliki dependency yang perlu diperbarui. Gunakan scanner yang sesuai dengan pipeline Anda dan tetapkan kebijakan severity yang jelas.
3. Gunakan multi-stage build
Jangan membawa compiler, git, package manager cache, dan development dependency ke production runtime bila tidak diperlukan.
4. Jangan menghapus shell secara membabi buta
Runtime tanpa shell memang mengurangi komponen, tetapi debugging menjadi berbeda. Pastikan observability dan incident workflow sudah siap.
5. Test native dependency
Untuk Alpine, test aplikasi yang menggunakan:
- database driver native,
- image processing,
- cryptography,
- Node native addon,
- Python wheel dengan native extension,
- library C/C++.
6. Jangan mengejar ukuran dengan mengorbankan reliability
Menghemat 50 MB tetapi menghabiskan berjam-jam troubleshooting compatibility bukan optimasi yang bagus.
Rekomendasi cepat
Jika harus memilih tanpa analisis panjang:
- Paling minimal: Scratch
- Minimal untuk production runtime: Distroless
- Minimal + shell/package manager: Alpine
- Balance compatibility dan ukuran: Debian Slim
- Development nyaman: Ubuntu atau Fedora
- RHEL-compatible: Rocky Linux / AlmaLinux
- Enterprise Red Hat: UBI
- Utility/troubleshooting: BusyBox atau Alpine
Tetapi rekomendasi ini tetap harus divalidasi terhadap aplikasi, dependency, security policy, dan operational workflow.
Kesimpulan
Tidak ada satu base image yang paling benar untuk semua aplikasi.
Cara berpikir yang lebih sehat adalah:
Ukuran → Compatibility → Debugging → Security → Operational requirement.
Jika aplikasi bisa berjalan sebagai static binary, scratch sangat menarik. Jika ingin production runtime minimal dengan dependency yang lebih terstruktur, Distroless layak dipertimbangkan. Jika membutuhkan shell dan package manager tetapi tetap ingin image kecil, Alpine merupakan pilihan populer. Untuk compatibility yang lebih luas, Debian Slim atau Ubuntu sering lebih praktis. Sementara Rocky Linux, AlmaLinux, dan UBI masuk akal ketika kebutuhan enterprise Linux menjadi faktor utama.
Pada akhirnya, base image adalah keputusan engineering, bukan lomba mencari image dengan jumlah MB paling kecil.
Referensi resmi
Post Terkait
Pengalaman Publish Aplikasi ke Google Play: Personal vs Organization, D-U-N-S, Tester dan Biaya
Membedah proses publikasi aplikasi ke Google Play: akun personal vs organization, D-U-N-S, 12 tester selama 14 hari, bia...
Tutorial Podman Praktis: Untuk Programmer & DevOps
Tutorial Podman praktis untuk pekerjaan sehari-hari programmer dan DevOps: container, database, volume, network, debuggi...
AWS ALB Tidak Selalu Diperlukan: Solusi Ingress Single-AZ yang Scalable
Jika workload sengaja berada di satu Availability Zone, apakah ALB masih diperlukan? Pelajari alternatif ingress single-...