Dipublikasikan 11 Juli 2026
Salah satu masalah klasik saat containerizing aplikasi Go adalah ukuran image Docker yang membengkak. Image berbasis distro penuh seperti Ubuntu atau Debian bisa mencapai 1GB, padahal binary Go yang sudah di-compile biasanya hanya beberapa puluh MB. Multi-stage build adalah solusi standar industri untuk mengoptimasi ukuran image tanpa mengorbankan reproducibility build.
Teknik ini memanfaatkan fitur Dockerfile yang memungkinkan kamu menggunakan multiple FROM statements dalam satu file. Stage pertama digunakan untuk compiling kode dengan semua dependency build tools, sementara stage kedua hanya menyalin binary hasil compile ke image runtime yang minimal. Hasil akhirnya adalah image production yang aman, ringan, dan cepat di-deploy.
Pastikan kamu sudah menginstal Docker versi 17.05 atau lebih baru, karena multi-stage build baru didukung sejak versi tersebut. Selain itu, siapkan project Go sederhana dengan struktur seperti ini:
myapp/
├── main.go
├── go.mod
└── Dockerfile
Isi main.go bisa berupa HTTP server sederhana yang menggunakan library net/http. Berikut contoh minimal yang bisa digunakan:
package main
import (
"fmt"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello from Go!")
})
http.ListenAndServe(":8080", nil)
}
Jalankan go mod init myapp untuk membuat file go.mod. Project ini akan menjadi bahan percobaan kita untuk membandingkan ukuran image sebelum dan sesudah multi-stage build.
Untuk memahami seberapa besar penghematan yang bisa didapat, mari kita mulai dengan Dockerfile konvensional. Buat file Dockerfile dengan isi berikut:
FROM golang:1.23
WORKDIR /app
COPY go.mod .
COPY main.go .
RUN go build -o myapp .
EXPOSE 8080
CMD ["./myapp"]
Build image tersebut dan perhatikan ukurannya:
docker build -t myapp:single-stage .
docker images myapp:single-stage
Image myapp:single-stage kemungkinan besar akan berukuran sekitar 800MB hingga 1GB. Hal ini karena base image golang:1.23 membawa compiler, toolchain, dan package Debian yang tidak diperlukan saat runtime. Di production, ukuran semacam ini memperlambat deployment, pull, dan scaling.
Sekarang ubah Dockerfile untuk menggunakan multi-stage build. Stage pertama tetap menggunakan golang:1.23 sebagai builder, namun stage kedua menggunakan gcr.io/distroless/static atau alpine:latest sebagai runtime:
# Stage 1: Build
FROM golang:1.23 AS builder
WORKDIR /app
COPY go.mod .
COPY main.go .
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o myapp .
# Stage 2: Runtime
FROM gcr.io/distroless/static:latest
WORKDIR /root/
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]
Flag CGO_ENABLED=0 sangat penting di sini. Tanpa flag ini, binary Go akan ter-link secara dinamis ke library C sistem, yang menyebabkan binary tidak bisa berjalan di image distroless. Dengan CGO_ENABLED=0, binary menjadi fully static dan bisa dieksekusi di environment minimal mana pun.
Build image baru dan bandingkan ukurannya:
docker build -t myapp:multi-stage .
docker images myapp:multi-stage
Kamu akan melihat ukuran image turun drastis dari sekitar 1GB menjadi kurang dari 20MB. Distroless image hanya berisi binary yang diperlukan untuk menjalankan aplikasi, tanpa shell, package manager, atau utilitas sistem lainnya.
Jika kamu memerlukan shell untuk debugging, alpine:latest adalah alternatif yang masih sangat ringan. Alpine Linux berbasis musl libc dan busybox, menghasilkan image sekitar 5-7MB. Ubah stage runtime seperti ini:
FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/myapp .
EXPOSE 8080
CMD ["./myapp"]
Tambahan package ca-certificates diperlukan jika aplikasi kamu melakukan HTTPS request ke API eksternal. Tanpa certificate store, TLS handshake akan gagal. Image hasil build dengan Alpine biasanya sedikit lebih besar dibanding distroless, namun tetap di bawah 25MB untuk aplikasi Go yang sederhana.
Di lingkungan production, gunakan non-root user untuk menjalankan container. Ini adalah praktik keamanan fundamental yang mencegah privilege escalation jika aplikasi terkena exploit. Modifikasi Dockerfile untuk menambahkan user baru:
FROM alpine:latest
RUN apk --no-cache add ca-certificates && addgroup -S appgroup && adduser -S appuser -G appgroup
WORKDIR /home/appuser
COPY --from=builder /app/myapp .
RUN chown appuser:appgroup myapp
USER appuser
EXPOSE 8080
CMD ["./myapp"]
Perhatikan penggunaan && untuk menggabungkan perintah RUN. Ini mengurangi jumlah layer Docker dan memperkecil ukuran image akhir. Selain itu, pastikan kamu selalu menggunakan tag spesifik untuk base image, seperti golang:1.23.4-alpine, untuk menghindari perubahan tak terduga saat image di-rebuild di masa depan.
Multi-stage build juga sangat powerful saat diintegrasikan ke pipeline CI/CD. Salah satu triknya adalah memanfaatkan Docker layer caching untuk mempercepat build berulang. Pisahkan dependency download dari kode aplikasi:
FROM golang:1.23 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o myapp .
Dengan menyalin go.mod dan go.sum terlebih dahulu, Docker akan meng-cache layer go mod download selama file dependency tidak berubah. Build berikutnya akan jauh lebih cepat k Docker hanya perlu meng-compile kode aplikasi, bukan mendownload ulang semua modul.
Untuk pipeline GitHub Actions, gunakan docker/build-push-action dengan cache-from dan cache-to untuk memanfaatkan registry sebagai remote cache. Ini sangat berguna untuk project dengan tim besar yang melakukan banyak build setiap hari.
Docker multi-stage build adalah teknik wajib bagi setiap developer Go yang mengadopsi containerization. Dengan memisahkan environment build dan runtime, kamu bisa mengurangi ukuran image hingga lebih dari 90% sambil menjaga keamanan dan reproducibility. Pilihan antara distroless dan Alpine bergantung pada kebutuhan debugging dan ukuran yang bisa kamu toleransi.
Dokumentasi resmi Docker mengenai multi-stage build tersedia di Docker Docs: Multi-stage builds. Untuk project open source yang ingin melihat implementasi nyata, cek repository Google Distroless di GitHub.
Dapatkan feedback, users, dan eksposur dari komunitas kreator, developer, dan entrepreneur digital Indonesia.
Submit Produk → Pelajari Dulu