wayanjimmy
ENID

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 #

dockerfile
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:

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

Menjalankan Container #

Setelah build selesai, pastikan container berjalan tanpa masalah:

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

Extract Static Binary #

Jika ingin mendapatkan static binary-nya saja:

bash
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:

bash
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.

Berlangganan