FrankenPHPでLaravelを動かしてみよう
この記事は下記スライドの補足資料的な立ち位置です(環境構築の説明に振り切っています)
1.モチベーション
試してみたいよね、FrankenPHP。
みんなが好きな?Laravelを動かしたいよね。
2.注意事項
今回は最小構成です。
既存Laravelプロジェクトが全部FrankenPHPで動くとは限りません。ご了承ください。
3.環境紹介
PC
- Apple M4
- Seqoia 15.5
- メモリ16GB
開発ツール、プログラミング言語
- Docker version 28.1.1
- Docker Compose version v2.35.1-desktop.1
- PHP 8.4.8
- Composer 2.8.9
- Laravel 12.0
4.FrankenPHPとは
5.まずは試してみる
とにかくインストール
curl https://frankenphp.dev/install.sh | sh
mv frankenphp /usr/local/bin/
sudo mv /Users/{ユーザー名}/frankenphp /usr/local/bin/
frankenphp --version
homebrewを使ってインストールも可能ですが、自分は既存のPHPとバッティングして面倒だったのでしませんでした。※何回か試していたらhomebrewでも上手くいきました。
brew install dunglas/frankenphp/frankenphp
Hello World
ひとまず簡単に動かしてみましょう
franenphp-hello-world
└── public
└── index.php
webサーバー起動
frankenphp php-server -r public
# Caddyが動いてlocalhostで確認できます
command line App起動
frankenphp php-cli public/index.php
# Hello, FrankenPHP!が出力されます
6.今回作る構成
DockerでLaravelアプリが動く最小構成を作ってみよう
- Laravel(FrankenPHP)
- DB(SQLite, MySQL, PostreSQL)
@startuml
!define RECTANGLE class
actor Client as "Client\n(ブラウザ / API Client)"
rectangle "Laravel Application\n(FrankenPHP)" as Laravel
database "Database\n(SQLite / MySQL / PostgreSQL)" as DB
Client --> Laravel : HTTP Request
Laravel --> DB : DB Query
Laravel --> Client : HTTP Response
@enduml

仮想環境を使わずにLaravelプロジェクトをFrankenPHPで動かす
Laravelプロジェクト作成
今回は作ります
composer create-project laravel/laravel frankenphp-laravel-sample
Laravelプロジェクト起動
cd frankenphp-laravel-sample
php artisan serve

動いた。
FrankenPHPを導入していく
laravel/octaneを導入しましょう。
octaneのおかげでいろんな設定をよしなにやってくれます。
laravel/octaneをインストール
composer require laravel/octane
設定
php artisan octane:install --server=frankenphp
FrankenPHPでLaravelプロジェクトを起動
php artisan octane:frankenphp

同じ画面が表示されます。
frankenphpのバイナリーがないと言われるのでダウンロードしましょう


FrankenPHPで動かす(Laravel Sail編)
Sailでも使えます。
Sailを導入
laravel/octane導入
公式ドキュメントを参考にしてください。
docker-compose.ymlの変更を忘れずに
services:
laravel.test:
build:
context: './vendor/laravel/sail/runtimes/8.4'
dockerfile: Dockerfile
args:
WWWGROUP: '${WWWGROUP}'
image: 'sail-8.4/app'
extra_hosts:
- 'host.docker.internal:host-gateway'
ports:
- '${APP_PORT:-80}:80'
- '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
environment:
# 環境変数を変えて起動し直すと切り替わります
# cli-server
# WWWUSER: '${WWWUSER}'
# LARAVEL_SAIL: 1
# XDEBUG_MODE: '${SAIL_XDEBUG_MODE:-off}'
# XDEBUG_CONFIG: '${SAIL_XDEBUG_CONFIG:-client_host=host.docker.internal}'
# IGNITION_LOCAL_SITES_PATH: '${PWD}'
# frankenphp
SUPERVISOR_PHP_COMMAND: "/usr/bin/php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=frankenphp --host=0.0.0.0 --admin-port=2019 --port='${APP_PORT:-80}'"
XDG_CONFIG_HOME: /var/www/html/config
XDG_DATA_HOME: /var/www/html/data
volumes:
- '.:/var/www/html'
networks:
- sail
depends_on:
- mysql
mysql:
image: 'mysql/mysql-server:8.0'
ports:
- '${FORWARD_DB_PORT:-3306}:3306'
environment:
MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}'
MYSQL_ROOT_HOST: '%'
MYSQL_DATABASE: '${DB_DATABASE}'
MYSQL_USER: '${DB_USERNAME}'
MYSQL_PASSWORD: '${DB_PASSWORD}'
MYSQL_ALLOW_EMPTY_PASSWORD: 1
volumes:
- 'sail-mysql:/var/lib/mysql'
- './vendor/laravel/sail/database/mysql/create-testing-database.sh:/docker-entrypoint-initdb.d/10-create-testing-database.sh'
networks:
- sail
healthcheck:
test:
- CMD
- mysqladmin
- ping
- '-p${DB_PASSWORD}'
retries: 3
timeout: 5s
networks:
sail:
driver: bridge
volumes:
sail-mysql:
driver: local
FrankenPHPで動かす(Docker編)
Laravel Sailを使わずにコンテナを立てます。公式Docにある情報を元に構築します。
今回はホストのディレクトりをバインドマウントします。これで開発環境としてcomposerでパッケージをinstallしてもvendor配下が確認できます。
プロジェクトにdocker-compose.yml作成
services:
app:
build:
context: .
dockerfile: ./docker/php/Dockerfile
ports:
- "8000:8000"
db:
image: mysql:8.0
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: develop
volumes:
- frankenphp-laravel-sample-db:/var/lib/mysql
volumes:
frankenphp-laravel-sample-db:
プロジェクトにdocker/Dockerfileとdocker/entrypoint.shを作成
今回は時間がなかったのでシェルスクリプトを駆使して無理やりマウントしました。もっと良い書き方があったかもしれません。
FROM dunglas/frankenphp
# composer を追加
COPY /usr/bin/composer /usr/bin/composer
# 必要な PHP 拡張をインストール
RUN install-php-extensions \
pcntl \
pdo_mysql \
pdo_pgsql \
pgsql \
gd \
intl \
zip \
opcache
WORKDIR /app
# Laravel プロジェクトをコピー
COPY . /app
# entrypoint.sh をコンテナ実行パスにコピー
COPY docker/php/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
# composer 環境変数を設定
ENV COMPOSER_ALLOW_SUPERUSER=1
# CMD でシェルスクリプトを実行
CMD ["entrypoint.sh"]
#!/bin/sh
# vendor が存在しない場合のみ composer install
if [ ! -d "vendor" ]; then
echo "Running composer install..."
composer install
fi
# APP_KEY が設定されていない場合のみ key:generate を実行
if ! grep -q '^APP_KEY=base64:' .env; then
echo "Generating app key..."
php artisan key:generate
fi
# FrankenPHP起動
exec php artisan octane:frankenphp
7.デプロイしてみよう
fly.ioを使ってデプロイします。
事前準備
fly.ioのアカウント作成とflyctlの準備をしておきましょう。
自分の環境
fly v0.3.144
Dockerfile作成
プロジェクトルートにDockerfileを用意します。
シェルスクリプトを使わずCMDでFrankenPHPを起動するようなDockerfileを書きます。
今回はLaravel Sailを使わないDocker環境を使います。
FROM dunglas/frankenphp
# composer を追加
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
# 必要な PHP 拡張をインストール
RUN install-php-extensions \
pcntl \
pdo_pgsql \
pgsql \
gd \
intl \
zip \
opcache
WORKDIR /app
# Laravel プロジェクトをコピー
COPY . /app
# composer 環境変数を設定
ENV COMPOSER_ALLOW_SUPERUSER=1
RUN composer install --no-dev --optimize-autoloader
ENTRYPOINT ["php", "artisan", "octane:frankenphp"]
最終的なディレクトリ構成
frankenphp-laravel-sample
├── app
├── artisan
├── bootstrap
├── composer.json
├── composer.lock
├── config
├── database
├── docker
├── docker-compose.yml
├── Dockerfile ///// このDockerfileが必要です
├── fly.toml
├── Makefile
├── package.json
├── phpunit.xml
├── public
├── README.md
├── resources
├── routes
├── storage
├── tests
├── vendor
└── vite.config.js
flyctlでプロジェクト初期化
CLIで実行
fly launch (Do you want to tweak these settings before proceeding? Yesで回答)
Fly.io側の設定
自動で画面遷移をしてインフラの詳細設定を求められたので下記を入力しました。
◯Basics
App name : frankenphp-laravel-sample
Organization : Personal
◯Region
Tokyo
◯Postgres
Provider : Fly Unmanaged Postgres
Name : frankenphp-laravel-sample-db
Configuration : Development
◯Redis
none
◯Sentry
Disables
自動生成されたものを少し手直しします。
app = '自分が作ったApp名'
primary_region = 'nrt'
console_command = 'php /var/www/html/artisan tinker'
[build]
[build.args]
NODE_VERSION = '18'
PHP_VERSION = '8.2'
[env]
APP_ENV = 'production'
LOG_CHANNEL = 'stderr'
LOG_LEVEL = 'info'
LOG_STDERR_FORMATTER = 'Monolog\Formatter\JsonFormatter'
SESSION_DRIVER = 'cookie'
SESSION_SECURE_COOKIE = 'true'
DB_CONNECTION = 'pgsql'
DB_HOST = 'postgresql://自分が作ったdb名.flycast'
DB_DATABASE= '自分が作ったApp名'
DB_PORT = 5432
[http_service]
internal_port = 8000
force_https = true
auto_stop_machines = 'stop'
auto_start_machines = true
min_machines_running = 0
processes = ['app']
[[vm]]
memory = '1gb'
cpu_kind = 'shared'
cpus = 1
デプロイ実施
fly deploy
cli側がプロジェクトを検知し勝手にデプロイを行ってくれます(これすごい)。
マイグレーション
DBのマイグレーションを忘れずに
※「デプロイ時に自動でマイグレーションできる」という記事を見つけたのですが上手くいきませんでした。自分の勘違いかも知れないので何か知ってる方がいたら教えてください。
コマンドで仮想マシン内に入りartisanコマンドをいつも通り動かしましょう
fly ssh console
---- fly.ioのコンソール内 ---
php artisan migrate:status
php artisan migrate
exit
8.まだまだ試したいことがたくさんある
Caddyfileのカスタムもできてない。キューを利用した機能も組んでない。
FrankenPHP、おもちゃとしてのポテンシャルが高い。
9.今回のコード
10.参考文献
FrankenPHPやLaravel関連は丁寧にドキュメントが用意されています。いつくか紹介しておきます。Fly.ioについても紹介します。
深掘りたい場合は作者が出してる記事や動画がおすすめです
Discussion