Build Container Aplikasi Laravel dengan FrankenPHP

Apa itu FrankenPHP?

FrankenPHP adalah PHP server yang sebenarnya adalah sebuah modul dari Caddy web server. Karena Caddy ditulis dengan Go memungkinkan FrankenPHP menghadirkan fitur self-contained executable, yang mana aplikasi Laravel akan dibungkus dalam single binary untuk memuluskan proses Deployment.

Persiapan

Pastikan project Laravel sudah siap, ditulisan ini saya menggunakan blog ini yang memang ditulis dengan Laravel, dengan catatan frontend asset di project blog ini di build dengan Bun.

Membuat Multi-Stage Container file

FROM docker.io/oven/bun:1 AS asset-builder
COPY package.json bun.lockb /app/
WORKDIR /app
RUN bun install
COPY . .
RUN bun run build
FROM docker.io/serversideup/php:8.4-cli as vendor
COPY --chown=www-data:www-data . /var/www/html
RUN composer install --no-interaction --optimize-autoloader --ignore-platform-reqs --no-dev
FROM docker.io/dunglas/frankenphp:static-builder-musl-1.7.0 AS builder
ENV NO_COMPRESS=1
# Copy your app
WORKDIR /go/src/app/dist/app
COPY . .
# Remove the tests and other unneeded files to save space
# Alternatively, add these files to a .dockerignore file
RUN rm -Rf tests/
COPY --from=vendor /var/www/html /go/src/app/dist/app
COPY --from=asset-builder /app/public/build /go/src/app/dist/app/public/build
# Build the static binary, be sure to select only the PHP extensions you want
WORKDIR /go/src/app/
RUN EMBED=dist/app/ ./build-static.sh
FROM gcr.io/distroless/static-debian12
ARG build=dev
ENV BUILD $build
WORKDIR /app
COPY --from=builder /go/src/app/dist/frankenphp-linux-x86_64 blog
ENTRYPOINT ["/app/blog", "php-server"]

Penjelasan Multi-Stage build

Stage 1: Asset Builder

Stage ini menggunakan Bun untuk build frontend assets (CSS, Javascript):

Stage 2: PHP Dependencies

Stage ini berisi instalasi Composer dependencies, menggunakan base image dari serversideup:

Stage 3: Static Binary Build

Membuat static binary dengan FrankenPHP:

Stage 4: Final Runtime

Stage terakhir yang menghasilkan image production

Build Docker Image

Jalankan perintah berikut untuk build image:

podman build --format=docker \
-t wayanjimmy/blog-10:latest .

Menjalankan Container

Setelah build selesai, pastikan container berjalan tanpa masalah:

podman container run -p 8080:80 \
--env-file=./.env --rm wayanjimmy/blog-10:latest

Extract Static Binary

Jika ingin mendapatkan static binary-nya saja:

podman create --name temp-container wayanjimmy/blog-10:latest
podman cp temp-container:/app/blog ./blog-binary
podman rm temp-container

Sekarang file blog-binary bisa dijalankan langsung:

chmod +x blog-binary
./blog-binary php-server

Kesimpulan

Dengan menggunakan FrankenPHP dan multi-stage Container build, kita bisa mengubah aplikasi Laravel menjadi self-contained single binary. Ini akan memuluskan proses deployment, karena menghilangkan beberapa component yang harus dijalankan seperti nginx/apache dan php-fpm.

Mesti ukuran binary cukup besar (sekitar 199MB), namun kemudahan deployment yang didapat menurut saya cukup worth it. Approach ini sangat cocok untuk menyederhanakan komponen yang di deploy, dan seperti blog ini saya deploy ke server Fly.io.