Build Container Aplikasi Laravel dengan FrankenPHP
- Apa itu FrankenPHP?
- Persiapan
- Membuat Multi-Stage Container file
- Penjelasan Multi-Stage build
- Build Docker Image
- Menjalankan Container
- Extract Static Binary
- Kesimpulan
#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
1FROM docker.io/oven/bun:1 AS asset-builder 2 3COPY package.json bun.lockb /app/ 4 5WORKDIR /app 6 7RUN bun install 8 9COPY . .10 11RUN bun run build12 13FROM docker.io/serversideup/php:8.4-cli as vendor14 15COPY --chown=www-data:www-data . /var/www/html16 17RUN composer install --no-interaction --optimize-autoloader --ignore-platform-reqs --no-dev18 19FROM docker.io/dunglas/frankenphp:static-builder-musl-1.7.0 AS builder20 21ENV NO_COMPRESS=122 23# Copy your app24WORKDIR /go/src/app/dist/app25 26COPY . .27 28# Remove the tests and other unneeded files to save space29# Alternatively, add these files to a .dockerignore file30RUN rm -Rf tests/31COPY --from=vendor /var/www/html /go/src/app/dist/app32COPY --from=asset-builder /app/public/build /go/src/app/dist/app/public/build33 34# Build the static binary, be sure to select only the PHP extensions you want35WORKDIR /go/src/app/36 37RUN EMBED=dist/app/ ./build-static.sh38 39FROM gcr.io/distroless/static-debian1240 41ARG build=dev42 43ENV BUILD $build44 45WORKDIR /app46 47COPY --from=builder /go/src/app/dist/frankenphp-linux-x86_64 blog48 49ENTRYPOINT ["/app/blog", "php-server"]
#Penjelasan Multi-Stage build
#Stage 1: Asset Builder
Stage ini menggunakan Bun untuk build frontend assets (CSS, Javascript):
- Install dependencies dengan
bun install
- Build assets dengan
bun run build
- Hasil build akan di-copy ke stage selanjutnya
#Stage 2: PHP Dependencies
Stage ini berisi instalasi Composer dependencies, menggunakan base image dari serversideup:
- Install Composer dependencies dengan optimasi production
- Flag
--no-dev
untuk skip development dependencies - Flag
--optimize-autoloader
untuk performa lebih baik
#Stage 3: Static Binary Build
Membuat static binary dengan FrankenPHP:
- Menggunakan base image
dunglas/frankenphp:static-builder-musl-1.7.0
- Menggabungkan source code, Composer dependencies, dan frontend build assets
- Aktivasi variable
NO_COMPRESS
untuk menghindari proses kompression binary karena ini akan menambah waktu build container image - Menjalankan script
build-static.sh
dari Frankenphp untuk compile menjadi single executable
#Stage 4: Final Runtime
Stage terakhir yang menghasilkan image production
- Menggunakan base image
distroless/static-debian12
- Hanya berisi static binary hasil compile
#Build Docker Image
Jalankan perintah berikut untuk build image:
1podman build --format=docker \2 -t wayanjimmy/blog-10:latest .
#Menjalankan Container
Setelah build selesai, pastikan container berjalan tanpa masalah:
1podman container run -p 8080:80 \2 --env-file=./.env --rm wayanjimmy/blog-10:latest
#Extract Static Binary
Jika ingin mendapatkan static binary-nya saja:
1podman create --name temp-container wayanjimmy/blog-10:latest2podman cp temp-container:/app/blog ./blog-binary3podman rm temp-container
Sekarang file blog-binary
bisa dijalankan langsung:
1chmod +x blog-binary2./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.