Containerize Laravel Framework with Docker Multi-Stage to Optimized Container Image Size

Andri Muhyidin
Andri #DevOps
Published in
6 min readFeb 27, 2021

Background

Melakukan containerization pada suatu aplikasi merupakan salah satu hal yang dapat menunjang produktivitas developer, container dapat membantu mempercepat proses development, deployment, hingga delivery berbagai jenis aplikasi. Namun terdapat beberapa kasus bahwa aplikasi yang di container-kan memiliki ukuran images yang cukup besar, dikarenakan banyak package yang tidak digunakan atau pemilihan base image yang tidak ideal. Khususnya pada Laravel yang merupakan salah satu php framework populer, ia membutuhkan berbagai dependencies dan modules seperti composer, node, dan sebagainya.

Objective

Pada artikel ini penulis akan memberikan solusi bagaimana meminimalisir ukuran image container laravel dengan menggunakan metode multi-stage. Namun, penulis juga membatasi bahwa aplikasi yang akan dijalankan hanya contoh dan sederhana. Penulis juga berharap bahwa anda sudah mengenal sedikit tentang docker maupun laravel, sehingga anda dapat lebih memahami artikel ini. Penulis juga memberikan sedikit istilah terkait sebelum membahas artikel inti.

Terms

Dockerfile

Menyediakan file yang dibutuhkan untuk membangun docker image, setiap line merepresentasikan aksi seperti install software, konfigurasi, dan sebagainya. Source code Dockerfile dapat didistribusikan menggunakan git repository dan proses containerzation dapat diotomatisasi menggunakan tools CI/CD.

Docker Images

Adalah image file yang tidak dapat diubah dan persisten berdasarkan layer instruksi yang diberikan saat membangunnya. Setiap image merepresentasikan perintah, perubahan, instalasi, konfigurasi, dan sebagainya. Sehingga memungkinkan image sangat kompleks seperti berjalan diatas sistem operasi pada umumnya. Images dapat didistribusikan pada registries baik publik seperti docker hub maupun private registries seperti nexus, jfrog, dan sebagainya.

Docker Containers

Container mengisolasi aplikasi dan seluruh dependencies yang berjalan diatas sistem operasi. Semua hal yang anda butuhkan saat menjalankan vm atau bare metal dapat diinstall pada container yang lebih fleksibel dan cepat.

Container Orchestration

Orchestration berarti kemampuan untuk melakukan manajemen dan maintenance containers. Selain itu ia dapat lebih mudah digunakan untuk melakukan provisioning dan scale up resource. Tools populer yang dapat digunakan untuk orchestration seperti Kubernetes, Docker Swarm, dan sebagainya.

Laravel

Laravel adalah satu framework php yang digunakan untuk membantu pengembangan website. Dengan menggunakan framework, developer dapat terbantu dalam penyederhanaan proses pengembangan, performa website, keamanan, dan lebih dinamis.

Prerequisites

Operating System

Untuk sistem operasi, sesuaikan dengan kebutuhan anda. Pada artikel ini penulis menggunakan Linux Ubuntu 20.04. Jadi, anda perlu menyesuaikan untuk perintah dasar, path, atau hal lainnya yang dirasa berbeda. Namun untuk obyektif tutorial ini (Dockerfile) dapat digunakan secara general berbagai macam sistem operasi.

Docker

Multi-stage build tersedia mulai dari docker versi 17.05. Sebaiknya anda melakukan instalasi docker terbaru. Jika laptop anda belum terinstall docker, lakukan instalasi docker terlebih dahulu dengan mengikuti official guide docker berikut.

https://docs.docker.com/engine/install/ubuntu/

Composer

Composer pada laravel merupakan komponen penting yang digunakan untuk melakukan generate library package laravel. Berikut perintah instalasi composer.

$ sudo apt install composer

Atau anda dapat mengikuti official guide berikut untuk instalasi pada platform lainnya

https://getcomposer.org/doc/00-intro.md

Yarn

Pastikan anda sudah menginstal yarn sebagai manajemen dependencies laravel.

Installing Yarn

$ curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
$ echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
$ sudo apt update && sudo apt install yarn

Install Verification

$ yarn — version

Reference

https://classic.yarnpkg.com/en/docs/install/#debian-stable

NPM

Pada ubuntu, perintah yang digunakan cukup sederhana. Karena umumnya sudah ada dalam package manager apt.

$ sudo apt install npm

Laravel

Penulis menggunakan Laravel versi 5.0. Berikut adalah beberapa dependencies yang perlu dipersiapkan seperti node, composer, yarn, dan sebagainya.

Installing Composer

$ composer global require laravel/installer

Alias Laravel Binary

$ alias -p laravel=~/.config/composer/vendor/bin/laravel

Laravel Project Initiate

$ laravel new <project-name>

Reference

https://laravel.com/docs/5.0/installation

Implementation

Traditional Method

Objective

Pada konsep dockerize image tradisional (single stage) dalam satu image docker, anda harus memiliki setiap dependencies yang dibutuhkan seperti harus menginstall node js, composer, yarn, dan sebagainya. Sehingga docker image yang dihasilkan akan sangat berantakan, sulit dipelihara, dan bisa saja ukuran image menjadi lebih besar dari multi-stage untuk objective yang sama.

Script

Contoh dari pendekatan tradisional ini ada pada cuplikan Dockerfile berikut. Create Dockerfile, pastikan file berada di root directory laravel project.

$ vi Dockerfile

Isi dengan script berikut

# Base Image
FROM php:8.0-apache

# Install NPM
RUN apt-get update && apt-get install -y npm zip unzip

# Install Composer
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer

# Copy Laravel app to Container
COPY . .

# Composer Install
RUN composer install \
--ignore-platform-reqs \
--no-interaction \
--no-plugins \
--no-scripts \
--prefer-dist

# NPM Install and Compile
RUN npm install \
&& npm run production

Lalu, anda dapat melakukan build image dengan contoh perintah berikut.

$ docker build -t <image-name>:<image-tag> .

Result

Ukuran image yang dihasilkan kurang lebih 588 MB untuk metode tradisional ini, anda dapat mengecek hasil-nya dengan perintah berikut:

$ docker images

Jalankan container untuk melihat hasil dari laravel container, misalkan berjalan diatas port 80. Maka perintah yang dapat digunakan adalah sebagai berikut:

$ docker run -it — expose 80 -p 80:80 <image-name:<image-tag>

Multi-Stage Build Method

Objective

Dengan menggunakan metode multi-stage build setiap stage akan menggunakan container image tertentu sesuai fungsinya. Hasil dari stage tersebut akan dialihkan ke stage berikutnya untuk di eksekusi menggunakan container images lainnya. Meminimalisir proses instalasi manual dengan perintah secara langsung pada satu docker images.

Preparation

Buat file .dockerignore, untuk mencegah penyalinan jalur yang ditentukan selama proses build. List berikut artinya file tidak akan diabaikan saat ada instruksi COPY atau ADD pada dockerfile.

.git/
vendor/
node_modules/
public/js/
public/css/
yarn-error.log

Misalkan ada perintah berikut COPY . /var/www/html. Artinya perintah tersebut akan melakukan copy seluruh file yang ada pada workdir, kecuali yang sudah di list pada .dockerignore.

Stage 1

Sesuai dengan tahapan instalasi laravel pada prerequisite. Tahap 1 adalah menyiapkan composer dengan menggunakan official image composer secara langsung. Berikut cuplikan Dockerfile tahap pertama.

# Stage 1 - PHP Dependencies
FROM composer:2 as vendor

COPY database/ database/
COPY composer.json composer.json
COPY composer.lock composer.lock

RUN composer install \
--ignore-platform-reqs \
--no-interaction \
--no-plugins \
--no-scripts \
--prefer-dist

Pada bagian “as vendor” akan digunakan sebagai referensi untuk menyalin seluruh hasil pada tahap 1 ke tahap berikutnya.

Stage 2

Pada tahap kedua ini bertujuan untuk menginstall dependencies frontend dengan menggunakan yarn atau npm. Tambahkan script berikut setelah script tahap pertama. Anda dapat mengidentifikasi directory public laravel dengan melakukan exec ke container. Tahap ini akan menghasilkan artefak frontend yang siap disalin ke tahap berikutnya.

# Stage 2 - Frontend Dependencies
FROM node:15.10-alpine as frontend

RUN mkdir -p /app/public

COPY package.json webpack.mix.js yarn.lock /app/
COPY resources/ /app/resources/

WORKDIR /app

RUN yarn install && yarn production

Stage 3

Tahap terakhir adalah menjalankan aplikasi menggunakan apache. Pada bagian ini juga terdapat aktifitas untuk merestore artefak tahap 1 (vendor), dan tahap 2 (frontend) ke directory /var/www/html yang sudah didefinisikan secara default oleh apache sebagai workdir. Anda dapat mengubahnya dengan memberikan konfigurasi tambahan pada file yang siap di copy dalam container.

# Stage 3 - Run Application
FROM php:8.0-apache
COPY . /var/www/html
COPY --from=vendor /app/vendor/ /var/www/html/vendor/
COPY --from=frontend /app/public/js/ /var/www/html/public/js/
COPY --from=frontend /app/public/css/ /var/www/html/public/css/
COPY --from=frontend /app/mix-manifest.json /var/www/html/mix-manifest.json
RUN chown -R www-data:www-data /var/www/html

Selain itu, jangan lupa untuk mengubah owner /var/www/html dan seluruh isinya pada UG www-data. Hal ini menghindari isu terkait file permissions.

Stage Summary

Setelah anda memahami konsep stage tersebut, berikut penulis sajikan hasil penggabungan dari seluruh stage yang ada pada Dockerfile.

Summary Multistage Docker Build Image

Result

Lakukan docker build didalam root directory laravel project seperti perintah berikut.

$ docker build -t <image-name>:<image-tag> .

Ukuran image yang dihasilkan kurang lebih 488 MB untuk metode multistage, maka kurang lebih kita mengurangi sekitar 100 MB untuk melakukan membuat docker image laravel. Hal ini mungkin dapat di optimize kembali dengan memilih image yang lebih ringan. Anda dapat mengecek hasil docker build image dengan perintah berikut:

$ docker images

Jalankan container untuk melihat hasil dari laravel container, misalkan berjalan diatas port 80. Maka perintah yang dapat digunakan adalah sebagai berikut:

$ docker run -it — expose 80 -p 80:80 <image-name:<image-tag>

Kunjungi http://localhost pada browser anda untuk mengetahui hasilnya.

Artifactory

Dockerfile Repository

Source code sample app laravel dapat anda clone atau unduh pada repository berikut

https://github.com/divistant/container-php-laravel

Container Registry

https://hub.docker.com/r/divistant/php-laravel

Atau anda dapat langsung pull image dengan perintah berikut

$ docker pull divistant/php-laravel

DevOps Consultant

Jika anda memiliki kebutuhan containerize berbagai macam aplikasi, anda dapat menghubungi saya melalui email andrimuhyidin55@gmail.com. Semoga bisa membantu.

--

--