先日Laravel12が発表されたので、Laravelのスターターキットで作成したSPAをBrefを使ってAWS Lambdaにデプロイする流れをまとめてみます。
1. Brefとは
Brefは、AWS Lambda上でPHPアプリケーションを実行するためのオープンソースツールです。Lambdaはサーバーレス環境であり、従来のサーバー管理を不要にしますが、PHPはそのままではLambda上で動作しません。そこでBrefは、カスタムランタイムを提供し、LaravelのようなフルスタックフレームワークもLambda上で動かせるように工夫されています。
Brefを使用したLambdaのリクエスト ~ レスポンス生成までの流れ
引用:PHP-FPM runtime for AWS Lambda
1. クライアントからのHTTPリクエスト
ユーザーが アプリケーション にアクセスすると、そのリクエストは Amazon API Gateway へ送られます。
2. API Gatewayによるルーティング
API Gatewayは、設定されたエンドポイント(URLパスやメソッドなど)に基づいて、AWS Lambda 関数(Brefを用いたPHPランタイム)を呼び出します。
3. Lambdaの起動とBrefの処理
Lambda関数が呼び出されると、event
(API Gatewayから渡されるリクエストデータ)とcontext
(Lambdaの実行コンテキスト情報)がLambdaランタイムに渡されます。
Bref はカスタムランタイムとして、Lambdaのライフサイクルに合わせて起動します。具体的には、bootstrap と呼ばれるバイナリがイベントを受け取り、FastCGI プロトコルを通じて PHP-FPM に処理を委ねます。
4. PHP-FPMでのリクエスト処理
PHP-FPMがFastCGIリクエストを受け取り、index.php(Laravelの場合は public/index.php)をエントリーポイントとしてアプリケーションを実行します。
ここでLaravelやその他のWebフレームワークの処理が行われ、最終的にレスポンスが生成されます。
5. レスポンスの返却
PHP-FPMが生成したレスポンスをFastCGIレスポンスとしてBref に返却します。
BrefはそのレスポンスをLambdaのフォーマット(JSON形式など)に変換し、LambdaがAPI Gatewayに応答します。
API GatewayはレスポンスをHTTPレスポンスに変換し、クライアントへ返却します。
なぜBrefを使うのか
- コスト削減: まずなんと言っても安いです。EC2やホスティングサービスを使うよりも圧倒的にコストを削減できます。
- スケーラビリティ: 自動でスケールアウト・スケールインするため、アクセス増加時にも柔軟に対応可能です。
- 運用の簡素化: サーバー管理の負荷が大幅に軽減され、開発に専念できます。
2. 開発環境の構築
必要なツール・前提条件
- PHP 8.3
- Laravel 12
- AWS CLI
- Serverless Framework v3
- Bref
AWS CLIのインストール
AWS CLIをインストールし、以下のコマンドで認証情報を設定します。
aws configure
Serverless Frameworkのインストール
npmを利用してServerless Frameworkをグローバルにインストールします。
※Serverless Frameworkはv4まで出ていますが、動作が非常に不安定ということでBref公式から非推奨とされています。そのため、今回はv3を使用します。
npm install -g serverless@3
Laravelプロジェクトの作成
今回はLaravel12のスターターキットを利用してプロジェクトを作成します。
- まず、Composer経由でLaravelインストーラをインストールします。
composer global require laravel/installer
- 次に、LaravelインストーラCLIを使用して、新しいLaravelアプリケーションを作成します。
laravel new my-app
この時、使用するフロントエンドの種類を聞かれますが、今回はReactを選択します。
- 後はJSパッケージをインストール&ビルドして、開発環境を立ち上げれば完了です。
cd my-app
npm install && npm run build
composer run dev
Brefのセットアップ
LaravelプロジェクトにBrefを導入し、インフラストラクチャの設定を行います。
Laravelプロジェクトのルートディレクトリで、Composerを使ってBrefをインストールします。
composer require bref/bref
次に、プロジェクトのルートディレクトリにserverless.yml
ファイルを作成し、Lambda用の設定を記述します。
service: laravel-react
provider:
name: aws
region: ap-northeast-1 # 東京リージョンを指定
package:
patterns:
- '!node_modules/**'
- '!public/storage'
- '!storage/**'
- '!tests/**'
- '!database/*.sqlite'
functions:
web:
handler: public/index.php
runtime: php-83-fpm
timeout: 28
events:
- httpApi:
path: /{proxy+}
method: ANY
artisan:
handler: artisan
runtime: php-83-console
timeout: 720
plugins:
- ./vendor/bref/bref
- serverless-lift
constructs:
website:
type: server-side-website
assets:
'/build/assets/*': public/build/assets/
'/favicon.ico': public/favicon.ico
'/robots.txt': public/robots.txt
各セグメントの解説
service
service: laravel-react
Serverless Frameworkにおけるプロジェクト名を定義します。ここでは「laravel-react」という名前のサービスとしてデプロイされます。この名前はCloudFormationスタックやS3バケットのプレフィックスなどにも使われます。
provider
provider:
name: aws
region: ap-northeast-1 # 東京リージョンを指定
デプロイ先のクラウドプロバイダーとリージョンを指定します。awsを使い、東京リージョン(ap-northeast-1)で各リソースが作成されます。
package
package:
patterns:
- '!node_modules/**'
- '!public/storage'
- '!storage/**'
- '!tests/**'
- '!database/*.sqlite'
デプロイに含めないファイルやフォルダを定義しています。不要なファイルを除外することで、デプロイパッケージのサイズを削減します。
node_modules/**
:Laravelでは不要
public/storage
:アップロードファイル(S3などで管理する想定)
storage/**
:ログやキャッシュなど実行時のみ必要なもの
tests/**
:テストコード
database/*.sqlite
:ローカル環境で使うSQLiteファイル
functions
functions:
web:
handler: public/index.php
runtime: php-83-fpm
timeout: 28
events:
- httpApi:
path: /{proxy+}
method: ANY
web関数は、HTTPリクエストを処理するLaravelのメインエントリポイントです。
handler
: public/index.php をLambdaのエントリポイントに指定
runtime
: php-83-fpm(BrefによるPHP 8.3 + FPM環境)
timeout
: 最大28秒
events
: HTTP API Gatewayで全パス・全メソッドに対応
artisan:
handler: artisan
runtime: php-83-console
timeout: 720
artisan関数は、LaravelのCLIコマンド(バッチ処理やマイグレーションなど)用です。
handler
: artisan コマンドをエントリポイントに
runtime
: php-83-console(CLI用のBrefランタイム)
timeout
: 長時間処理に備えて最大値の720秒を指定
plugins
plugins:
- ./vendor/bref/bref
- serverless-lift
使用するServerless Frameworkのプラグインを指定します。
bref
: PHP用のLambdaランタイムを提供
serverless-lift
: サーバーサイドWebアプリや静的ファイル配信のための簡潔な構成を可能にするプラグイン
constructs
constructs:
website:
type: server-side-website
assets:
'/build/assets/*': public/build/assets/
'/favicon.ico': public/favicon.ico
'/robots.txt': public/robots.txt
serverless-liftを使った、S3 + CloudFront構成での静的アセットの配信設定です。
-
type
: server-side-website:サーバーサイドアプリ(Laravelなど)に最適化された構成 -
assets
: 指定したファイル群をS3にアップロードしてCDN経由で配信
3. アプリケーションのデプロイ
最後に、ローカルでの動作確認から、AWS Lambdaへのデプロイ、そしてデプロイ後の動作確認までの手順を見ていきます。
ローカルでの動作確認
まず、開発環境でLaravelアプリケーションが正しく動作するかを確認します。
composer run dev
ブラウザで http://localhost:8000 にアクセスし、初期画面が表示されるかチェックしてください。
デプロイ
Serverless Frameworkを用いてデプロイします。プロジェクトルートで以下のコマンドを実行してください。
serverless deploy
デプロイが成功すると、出力にAPIエンドポイントのURLが表示されます。
デプロイ後の動作確認
デプロイ後に表示されたAPIエンドポイントにアクセスし、アプリケーションが正しく動作するか確認します。
終わりに
AWSのコンソールをほぼ一切触らずに、CLIからサーバーレスアプリケーションがコマンドを数回打つだけで完成できました。