Apa itu Docker Multistage Build
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
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.