Apa itu Docker Multistage Build

Ardhan Dikri Achmad Fahrudin
5 min readSep 8, 2023

--

docker

Apa itu Multistage Build

Docker multistage build adalah fitur yang ada pada pada Dockerfile yang memungkinkan anda untuk dapat menggunakan banyak FROM dalam membuat beberapa tahapan pembangunan, setiap tahap dapat memiliki image yang berbeda-beda.

Fitur ini sangat berguna untuk mengoptimalkan dan mengoptimasi ukuran image yang kita buat dan meningkatkan keamanan dari container saat dijalankan.

Penerapan Multistage Build

Disini saya memiliki sebuah app nodejs yang akan saya coba deploy menggunakan multistage dan tanpa multi stage supaya kita bisa melihat perbedaannya

Tanpa Multistage

Buat file Dockerfile dengan nama single.dockerfile dengan perintah seperti dibawah ini

ardhan@forwarddestiny:~/nuxtapp$ vi single.dockerfile

Selanjutnya copy dibawah ini dan pastekan kedalam file single.dockerfile

# Menggunakan image node versi 18 alpine
FROM node:18-alpine

# Menetapkan working direktori container di /usr/app
WORKDIR /usr/app

# Mengcopy package*.json ke working directory container
COPY package*.json ./

# Melakukan install dependensi
RUN npm install

# Menyalin semua file yang berada pada host directory ke wokdir container
COPY . .

# Menentapkan Variabel HOST untuk konfigurasi aplikasi
ENV HOST=0.0.0.0
ENV PORT=3000

# Perintah default yang akan dijalankan saat container berjalan
CMD ["npm","run","dev"]

# Membuka port 3000 dari container saat dijalankan
EXPOSE 3000

Build single.dockerfile tersebut dengan perintah docker build, karena disini kita tidak menggunakan Dockerfile jadi tambahkan opsi -f atau — file dan jangan lupa untuk memberi nama dari image yang kita build dengan nuxtsingle.

ardhan@forwarddestiny:~/nuxt-app$ docker build -t nuxtsingle -f single.dockerfile .
[+] Building 10.0s (11/11) FINISHED
=> [internal] load build definition from single.dockerfile
=> => transferring dockerfile: 185B
=> [internal] load .dockerignore
=> => transferring context: 2B
=> [internal] load metadata for docker.io/library/node:18-alpine
=> [auth] library/node:pull token for registry-1.docker.io
=> [1/5] FROM docker.io/library/node:18-alpine@sha256:3482a20c97e401b56ac50ba8920cc7b5b2022bfc6aa7d4e4c231755770cf892f
=> [internal] load build context
=> => transferring context: 1.33MB
=> CACHED [2/5] WORKDIR /usr/app
=> CACHED [3/5] COPY package*.json ./
=> CACHED [4/5] RUN npm install
=> [5/5] COPY . .
=> exporting to image
=> => exporting layers
=> => writing image sha256:6f76ee9349b5b64c3f21c90cb49793150209c81dab6f6c5be35b7d0be22ace31
=> => naming to docker.io/library/nuxtsingle

Jalankan perintah docker images untuk melihat image yang baru saja dibuat

ardhan@forwarddestiny:~/nuxt-app$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nuxtsingle latest 6f76ee9349b5 17 seconds ago 594MB

Dapat dilihat bahwa image yang dibuild dengan single build menghasilkan image dengan size 594MB.

Selanjutnya mari kita coba build image menggunkaan multistage build, apakah dapat mengoptimasi size dari project kita atau tidak.

Dengan Multistage

Buat file Dockerfile dengan nama multi.dockerfile, file ini nantinya akan kita gunakan untuk membuild image kita.

ardhan@forwarddestiny:~/nuxt-app$ vi multi.dockerfile

Copy dan pastekan dockerfile dibawah ini ke file multi.dockerfile

# Menggunakan image node versi 18 alpine sebagai builder
FROM node:18-alpine AS builder

# Menetapkan working direktori dari container ke /usr/app
WORKDIR /usr/app

# Mengcopy package*.json ke working directory container
COPY package*.json ./

# Melakukan install dependensi
RUN npm install

# Menyalin semua file yang berada pada host directory ke wokdir container
COPY . .

# Menjalankan perintah untuk generate static website
RUN npm run generate


# Menggunakan image nginx sebagai web server
FROM nginx

# Menyalin hasil dari proses generate dari tahap pertama ke working direktory nginx
COPY --from=builder /usr/app/dist /usr/share/nginx/html

# Membuka port 80 saat container dijalankan
EXPOSE 80

Catatan:

AS: Intruksi yang digunakan sebagai alias dari tahap di dockerfile

Selain kitadapat menggunakan AS untuk mengidentifikasi tahapan-tahapannya, kita juga bisa menggunakan angka untuk mengidentifikasi tahapan-tahapan tersebut sebagai contoh.

# Menggunakan image node versi 18 aline
FROM node:18-alpine

# Menetapkan working direktori dari container ke /usr/app
WORKDIR /usr/app

# Mengcopy package*.json ke working directory container
COPY package*.json ./

# Melakukan install dependensi
RUN npm install

# Menyalin semua file yang berada pada host directory ke wokdir container
COPY . .

# Menjalankan perintah untuk generate static website
RUN npm run generate

# Menggunakan image nginx sebagai web server
FROM nginx

# Menyalin hasil dari proses generate dari tahap pertama ke working direktory nginx
COPY --from=0 /usr/app/dist /usr/share/nginx/html

# Membuka port 80 saat container dijalankan
EXPOSE 80

Penggunaan 0 di atas berfungsi untuk mengidentifikasi tahap-tahap dalam Dockerfile dengan pendekatan yang lebih sederhana dan berurutan dalam multi-stage builds. Keduanya memiliki fungsi yang sama, tergantung kita ingin menggunakan yang mana.

Selanjutnya build image multistage dengan perintah docker build, jangan lupa berikan opsi -f untuk menenetukan nama dari dockerfile dan -t untuk memeberikan nama kepada image hasil build dengan nama nuxtmulti.

ardhan@forwarddestiny:~/nuxt-app$ docker build -t nuxtmulti -f multi.dockerfile .
[+] Building 9.0s (16/16) FINISHED
=> [internal] load build definition from multi.dockerfile
=> => transferring dockerfile: 247B
=> [internal] load .dockerignore
=> => transferring context: 2B
=> [internal] load metadata for docker.io/library/nginx:latest
=> [internal] load metadata for docker.io/library/node:18-alpine
=> [auth] library/nginx:pull token for registry-1.docker.io
=> [auth] library/node:pull token for registry-1.docker.io
=> [builder 1/6] FROM docker.io/library/node:18-alpine@sha256:3482a20c97e401b56ac50ba8920cc7b5b2022bfc6aa7d4e4c231755770cf892f
=> CACHED [stage-1 1/2] FROM docker.io/library/nginx@sha256:6926dd802f40e5e7257fded83e0d8030039642e4e10c4a98a6478e9c6fe06153
=> [internal] load build context
=> => transferring context: 1.33MB
=> CACHED [builder 2/6] WORKDIR /usr/app
=> CACHED [builder 3/6] COPY package*.json ./
=> CACHED [builder 4/6] RUN npm install
=> CACHED [builder 5/6] COPY . .
=> [builder 6/6] RUN npm run generate
=> [stage-1 2/2] COPY --from=builder /usr/app/dist /usr/share/nginx/html
=> exporting to image
=> => exporting layers
=> => writing image sha256:21456e144079fad122da9544dbb2182c7ef5a20315eb7271efd1bfb0142c7aab
=> => naming to docker.io/library/nuxtmulti

Lihat image yang baru dibuat, dan bandingkan dengan image yang dibuat tanpa menggunakan multistage build.

ardhan@forwarddestiny:~/nuxt-app$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
multinuxt latest 19a049073e11 2 minutes ago 187MB
nuxtsingle latest 6f76ee9349b5 15 minutes ago 594MB

Seperti yang kita lihat, bahwa image yang dibuat dengan multistage build memiliki ukuran yang lebih kecil dibanding sengan image yang tidak menggunakan multistage.

Terakhir coba jalankan aplikasi yang sudah kita build menggunakan multistage build.

ardhan@forwarddestiny:~/nuxt-app$ docker run -dp 80:80 --name nuxtmultiweb nuxtmulti

Jika aplikasi berjalan coba cek di browser dengan menggunakan alamat http://localhost

preview nuxt apps

Kesimpulan

Dengan Docker multistage build. Kita dapat menghindari masalah seperti image docker yang terlalu besar karena menyertakan alat-alat build atau file-file sementara yang tidak diperlukan dalam produksi. Ini juga membantu dalam menjaga keamanan karena gambar produksi hanya akan berisi komponen esensial tanpa mengandung potensi kerentanan atau dependensi yang tidak perlu. Selain itu, ini mempercepat proses pembuatan gambar dengan menghindari pembangunan ulang dari awal setiap kali kita memperbarui kode sumber aplikasi kita.

--

--