Single-Stage vs Multi-Stage Docker Builds: Panduan Lengkap untuk Meningkatkan Efisiensi Docker Anda

Apa itu Docker Build?
Docker adalah alat yang memungkinkan pengembang untuk mengemas aplikasi dan semua dependensinya ke dalam container yang dapat dijalankan di mana saja. Proses pembuatan container ini dimulai dengan menggunakan Dockerfile, yang berisi instruksi untuk membangun image Docker.
Namun, tidak semua Dockerfile sama. Ada dua jenis utama dalam Docker build: Single-Stage Build dan Multi-Stage Build. Masing-masing memiliki keuntungan dan kelemahan, tergantung pada kebutuhan proyek Anda.
Dalam artikel ini, kita akan membahas perbedaan utama antara Single-Stage Docker Builds dan Multi-Stage Docker Builds, serta bagaimana memilih yang terbaik untuk aplikasi Anda.
Apa Itu Single-Stage Docker Build? 🟦
Definisi:
Single-Stage Build adalah pendekatan sederhana untuk membangun image Docker. Semua instruksi—mulai dari menginstal dependencies hingga menyalin aplikasi—dilakukan dalam satu tahap. Proses ini tidak memisahkan antara tahap build dan runtime.
Keuntungan:
- Simplicity: Mudah untuk memahami dan diterapkan, cocok untuk aplikasi kecil atau proyek prototipe.
- Kecepatan: Lebih cepat dalam membangun image, karena hanya ada satu tahap.
Contoh Dockerfile Single-Stage:
# Menggunakan image dasar
FROM node:14
# Install dependencies dan copy aplikasi
RUN npm install
COPY . /app
# Tentukan direktori kerja
WORKDIR /app
# Expose port untuk akses
EXPOSE 80
# Jalankan aplikasi
CMD ["npm", "start"]
Catatan: pada single‑stage, tool build & cache ikut terbawa ke image final, sehingga ukuran image cenderung lebih besar.
Pada contoh di atas, kita:
- Menggunakan image dasar Node.js.
- Menginstal dependencies menggunakan
npm install
. - Menyalin aplikasi ke container dan menjalankan server.
Namun, masalah utama dengan pendekatan ini adalah ukuran image. Image yang dihasilkan akan mencakup semua tool dan dependensi yang digunakan dalam build, bahkan yang tidak dibutuhkan saat aplikasi dijalankan.
Apa Itu Multi-Stage Docker Build? 🐳
Definisi:
Multi-Stage Build adalah pendekatan yang lebih kompleks dan efisien. Pada pendekatan ini, proses build dibagi menjadi beberapa tahap. Biasanya, tahap pertama digunakan untuk membangun aplikasi, sedangkan tahap terakhir hanya berisi file yang diperlukan untuk menjalankan aplikasi.
Keuntungan:
- Ukuran Image yang Lebih Kecil: Dengan hanya menyalin file yang diperlukan untuk runtime, Anda menghindari membawa build dependencies ke dalam image final.
- Keamanan: Tools dan dependensi build yang tidak diperlukan tidak ada dalam image final, yang membuat image lebih aman.
- Optimalisasi: Menghasilkan image yang lebih efisien untuk produksi, karena hanya mengandung file yang benar-benar dibutuhkan.
Contoh Dockerfile Multi-Stage:
# Stage 1: Build Stage
FROM node:14 AS builder
# Install dependencies
RUN npm install
COPY . /app
WORKDIR /app
# Build aplikasi
RUN npm run build
# Stage 2: Final Image
FROM node:14
# Salin hasil build dari Stage 1
COPY --from=builder /app/build /app
# Expose port
EXPOSE 80
# Jalankan aplikasi
CMD ["npm", "start"]
Pada contoh ini:
- Stage 1 menginstal dependencies dan membangun aplikasi.
- Stage 2 hanya menyalin hasil build dan menjalankan aplikasi, menghasilkan image yang lebih kecil.
Dengan menggunakan multi-stage builds, kita mengurangi ukuran final image dan menghindari membawa dependensi build yang tidak diperlukan.
Perbandingan: Single-Stage vs. Multi-Stage Docker Build 🧐
Fitur | Single-Stage Build | Multi-Stage Build |
---|---|---|
Kompleksitas | Sederhana dan mudah dipahami | Lebih kompleks, memerlukan beberapa tahap |
Ukuran Image | Lebih besar karena membawa tools build | Lebih kecil, hanya membawa file runtime |
Keamanan | Tools build ada di image akhir | Tools build tidak ada di image akhir |
Kecepatan | Lebih cepat dalam build | Lebih lambat karena beberapa tahap build |
Penggunaan | Cocok untuk aplikasi kecil dan prototipe | Ideal untuk aplikasi besar dan produksi |
Kapan Menggunakan Single-Stage Build? ⚡
- Prototipe: Jika Anda sedang membuat prototipe atau aplikasi kecil yang tidak akan digunakan di lingkungan produksi.
- Aplikasi Sederhana: Jika Anda tidak memerlukan optimasi image atau memiliki kebutuhan khusus untuk keamanan dan ukuran image.
Kapan Menggunakan Multi-Stage Build? 🚀
- Lingkungan Produksi: Jika Anda perlu mengoptimalkan ukuran image untuk kecepatan pengiriman dan penyimpanan di cloud.
- Aplikasi Besar: Jika aplikasi Anda kompleks, memerlukan banyak dependensi, dan Anda ingin memastikan image akhir tetap bersih dan aman.
Mengapa Multi-Stage Builds Lebih Disarankan? 🔥
Dengan multi-stage builds, Anda bisa memastikan bahwa image akhir Anda hanya berisi file yang benar-benar dibutuhkan untuk menjalankan aplikasi. Ini membuatnya lebih kecil, lebih cepat, dan lebih aman. Di dunia DevOps yang semakin mengutamakan efisiensi dan kecepatan, menggunakan pendekatan ini adalah langkah cerdas, terutama untuk aplikasi berat dan produksi.
Optimalkan Docker Builds Anda untuk Produksi 🏁
Jika Anda masih menggunakan single-stage build untuk aplikasi besar atau aplikasi yang membutuhkan optimasi, sangat disarankan untuk beralih ke multi-stage build. Dengan begitu, Anda akan:
- Mempercepat proses build.
- Mengurangi ukuran dan biaya penyimpanan image.
- Meningkatkan keamanan dengan menghindari pembawaan dependencies yang tidak diperlukan.
Di bawah ini adalah Dockerfile multi‑stage final yang dipakai masdika sudah termasuk tuning PHP penuh (4096M, JIT 512M, file cache), ImageMagick/convert, serta runtime libs agar ekstensi gd/imagick/zip
selalu terbaca. Ini membuat image rapi, build cepat, dan optimasi gambar WebP aman. 👇
# =========================
# Stage 1: BUILD (compile PHP extensions, pecl, tuning)
# =========================
FROM dunglas/frankenphp:latest AS builder
# Build deps + ImageMagick dev untuk compile imagick
RUN apt-get update && apt-get install -y --no-install-recommends \
libjpeg-dev libpng-dev libwebp-dev libxpm-dev libfreetype6-dev libzip-dev \
libicu-dev libmagickwand-dev imagemagick curl git unzip \
&& pecl install redis imagick \
&& docker-php-ext-enable redis imagick \
&& docker-php-ext-configure gd --with-freetype --with-jpeg --with-webp --with-xpm \
&& docker-php-ext-install -j"$(nproc)" gd mysqli opcache zip intl exif \
&& docker-php-ext-enable gd mysqli opcache zip intl exif \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# >>> TUNING PHP.INI
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini" && \
mkdir -p /app/opcache && chown www-data:www-data /app/opcache && \
echo "memory_limit = 4096M" >> "$PHP_INI_DIR/php.ini" && \
echo "upload_max_filesize = 1024M" >> "$PHP_INI_DIR/php.ini" && \
echo "post_max_size = 1024M" >> "$PHP_INI_DIR/php.ini" && \
echo "max_execution_time = 300" >> "$PHP_INI_DIR/php.ini" && \
echo "max_input_time = 300" >> "$PHP_INI_DIR/php.ini" && \
echo "realpath_cache_size = 4096k" >> "$PHP_INI_DIR/php.ini" && \
echo "realpath_cache_ttl = 600" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.enable=1" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.enable_cli=1" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.memory_consumption=1024" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.interned_strings_buffer=128" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.max_accelerated_files=60000" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.revalidate_freq=0" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.validate_timestamps=0" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.jit=tracing" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.jit_buffer_size=512M" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.file_cache=/app/opcache" >> "$PHP_INI_DIR/php.ini" && \
echo "opcache.file_cache_only=0" >> "$PHP_INI_DIR/php.ini"
# =========================
# Stage 2: FINAL (runtime only + ImageMagick)
# =========================
FROM dunglas/frankenphp:latest
ENV SERVER_NAME="masdika.biz.id www.masdika.id" \
FRANKENPHP_MAX_CONCURRENCY=10000 \
FRANKENPHP_WORKER_TIMEOUT=120 \
FRANKENPHP_MAX_REQUESTS=50000
# Runtime libs + ImageMagick (convert)
RUN apt-get update && apt-get install -y --no-install-recommends \
imagemagick \
libpng16-16 libjpeg62-turbo libwebp7 libxpm4 libfreetype6 \
libzip4 libicu72 libmagickwand-6.q16-6 \
&& rm -rf /var/lib/apt/lists/*
# Copy extensions, core PHP, dan config dari builder
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/lib/php/ /usr/local/lib/php/
COPY --from=builder /usr/local/etc/php/ /usr/local/etc/php/
# App & Caddy
COPY --chown=www-data:www-data ./wordpress /app/public
COPY ./Caddyfile /etc/caddy/Caddyfile
# Healthcheck
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s \
CMD curl -fsS http://localhost/wp-login.php || exit 1
RUN chown -R 33:33 /app
USER www-data
Bagaimana Dockerfile Ini Bekerja (2 Tahap) 🔧
Stage 1 — Builder
- Memasang paket dev (termasuk komponen pengembangan untuk ImageMagick) agar bisa mengompilasi ekstensi.
- Mengompilasi & mengaktifkan ekstensi PHP yang dibutuhkan WordPress:
gd
(dengan freetype, jpeg, webp),mysqli
,opcache
,zip
,intl
,exif
,redis
(PECL), danimagick
(PECL). - Menerapkan tuning
php.ini
penuh:
memory_limit=4096M, upload_max_filesize=1024M, post_max_size=1024M
max_execution_time=300, max_input_time=300, realpath cache (realpath_cache_size=4096k, realpath_cache_ttl=600)
OPcache: enable=1, enable_cli=1, memory_consumption=1024, interned_strings_buffer=128, max_accelerated_files=60000, revalidate_freq=0, validate_timestamps=0
JIT: opcache.jit=tracing, opcache.jit_buffer_size=512M
File cache: opcache.file_cache=/app/opcache, opcache.file_cache_only=0 (folder /app/opcache dimiliki www-data).
Stage 2 — Final/Runtime
- Memakai image FrankenPHP yang bersih lalu menambahkan runtime libraries (tanpa header dev) + ImageMagick sehingga CLI
convert
tersedia. - Shared libraries yang memastikan ekstensi
gd/imagick/zip
bisa diload:libpng16
,libjpeg-turbo
,libwebp
,libfreetype6
,libzip4
,libicu72
,libMagickWand-6.q16-6
. - Menyalin ekstensi & konfigurasi PHP hasil build dari Stage 1; menjalankan aplikasi sebagai user non‑root (
www-data
). - Menambahkan healthcheck ke
http://localhost/wp-login.php
agar orkestrator tahu status aplikasi.
Dampaknya
- Optimasi & konversi WebP berjalan mulus—misalnya melalui plugin WP‑Optimize dengan converter Imagick (ImageMagick)—serta pembuatan thumbnail/responsive image WordPress tanpa error.
- Image final lebih kecil & rapi (alat build tidak ikut terbawa ke produksi).
- Menghilangkan error umum seperti:
convert: not found
,libpng16.so.16 not found
,libzip.so.4 not found
, ataulibMagickWand-6.Q16.so.6 not found
.
Kenapa setup ini dipilih?
- ✅ Lebih ramping dari single‑stage: dev headers hanya ada di builder; final cuma bawa runtime.
- ✅ Stabil untuk WordPress:
gd
,imagick
,zip
selalu kebaca karena runtime libs tersedia di stage final. - ✅ Gambar/WebP lancar:
convert
(ImageMagick) tersedia, sehingga plugin optimasi gambar misalnya WP‑Optimize dengan converter Imagick (ImageMagick) dapat melakukan konversi WebP serta thumbnail/responsive image tanpa error.
Tip: Mengaktifkan Imagick di WP‑Optimize
- Buka WP‑Optimize → Images → WebP.
- Pada Converter, pilih Imagick (ImageMagick). Opsi Generate WebP on upload bisa diaktifkan bila perlu.
- Klik Save settings, lalu Run conversion untuk memproses gambar yang sudah ada.

Kesimpulan 🏆
Pilihlah multi-stage build jika Anda ingin:
- Ukuran image yang lebih kecil.
- Memisahkan tahap build dan runtime.
- Mengurangi potensi masalah keamanan dengan tidak menyertakan tools build dalam image produksi.
Single-stage build tetap berguna untuk aplikasi kecil dan saat Anda membutuhkan solusi cepat tanpa terlalu mengkhawatirkan ukuran atau efisiensi.
Jika Anda ingin membuat image Docker yang lebih efisien dan optimal, multi-stage builds adalah pilihan terbaik untuk aplikasi produksi Anda. Dengan mengikuti panduan ini, Anda akan dapat menulis Dockerfile yang lebih bersih dan lebih efisien.
Dengan penjelasan di atas, Anda bisa mengoptimalkan Docker build untuk aplikasi apa pun, baik itu untuk proyek kecil atau aplikasi produksi besar.

Buat kamu yang lagi Deploy aplikasi dengan Next.js dan pengen jalan di Kubernetes dengan domain custom + SSL otomatis, artikel…

🌟 Apa itu Next.js ? Next.js adalah framework React yang populer untuk membangun aplikasi web modern. Dengan fitur SSR (Server…
Sangat bermanfaat
Oke