はじめに
この記事は、PHP Advent Calendar 2019 の16日目の記事です。
PHPerKaigi 2019で『サーバーレスPHP』というお話をさせていただいたのですが、その際に紹介した『Bref』が進化してたので紹介したいと思います。
Brefとは
BrefとはAWS Lambda上でPHPを動作させるためのもろもろの設定を楽にしてくれるCLIです。Brefを利用するためには、AWSアカウント、aws-cli、serverless frameworkが必要となります。
いままでのBrefとの変更点
相性の良いサービス
PHPerKaigiでは『DBの絡むものには向いていない』と発表したのですが、現在の公式ドキュメントには
上記のように、DBの絡むサービスが相性が良いものに変わっていました。
以前はLambdaからVPCに接続する時のコールドスタートがネックとなるので、相性が悪いサービスとしてDBが絡むものが挙げられてましたが、Lambdaの機能改善により、かなり早くDBにアクセスできるようになりました。よって、RDSを使ったサービスであれば実用に耐えうるものになったようです。
インストール
春先のBrefはこうでした。
composer require mnapoli/bref
が、今のBrefはこう変わっています。
composer require bref/bref
プロジェクト名がわかりやすくなってますね。1点注意ですが、新しいBrefはPHP7.2以上必須です。PHP7.1以下の方はPHPのバージョンアップして再度インストールしてください。
設定ファイル
BrefはデプロイにCloud Fomationを利用するため、Cloud Fomation用の設定ファイルを用意する必要がありました。
例えばこんな感じ。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Environment:
Variables:
APP_ENV: prod
Resources:
Website:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'bref-symfony-website'
CodeUri: .
Handler: public/index.php
Timeout: 30 # in seconds (API Gateway has a timeout of 30 seconds)
MemorySize: 1024
Runtime: provided
Layers:
- 'arn:aws:lambda:ap-northeast-1:209497400698:layer:php-73-fpm:1'
Events:
HttpRoot:
Type: Api
Properties:
Path: /
Method: ANY
HttpSubPaths:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
Console:
Type: AWS::Serverless::Function
Properties:
FunctionName: 'bref-symfony-console'
CodeUri: .
Handler: bin/console
Timeout: 120 # in seconds
Runtime: provided
Layers:
- 'arn:aws:lambda:ap-northeast-1:209497400698:layer:php-73:1' # PHP
- 'arn:aws:lambda:ap-northeast-1:209497400698:layer:console:1' # The "console" layer
Outputs:
DemoApi:
Description: 'URL of our function in the *Prod* environment'
Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/'
これは、PHPerKaigiで紹介したBrefを利用して、サーバーレスなSymfony環境を用意するためのCloud Fomation用設定ファイルです。
これでもサンプルがドキュメントに用意してあたので、そんなに問題なく用意できましたが、ぱっと見わかりにくい印象です。
これが、新しいBrefだとこんな感じになります。
service: bref-symfony-website
provider:
name: aws
region: ap-northeast-1
runtime: provided
environment:
# Symfony environment variables
APP_ENV: prod
plugins:
- ./vendor/bref/bref
package:
exclude:
- node_modules/**
- tests/**
functions:
website:
handler: public/index.php
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-73-fpm}
events:
- http: 'ANY /'
- http: 'ANY /{proxy+}'
console:
handler: bin/console
timeout: 120 # in seconds
layers:
- ${bref:layer.php-73} # PHP
- ${bref:layer.console} # The "console" layer
まず、template.ymlというファイル名からserverless.ymlというファイル名に変わり、Cloud Fomation用の設定ファイルでなくserverlessの設定ファイルを用意する形に変更になりました。Cloud Fomationよりもシンプルになったので、かなり書きやすくなったと思います。また、前回同様、公式サイトのドキュメントにサンプルがあるので、それを利用すれば、さくっと設定ファイルが用意できます。
デプロイ
春先では、デプロイは以下のコマンドを入力する必要がありました。
sam package --output-template-file .stack.yaml --s3-bucket [S3バケット名]
sam deploy --template-file .stack.yaml --capabilities CAPABILITY_IAM --stack-name [スタック名]
sam package
で、プロジェクトをS3にアップロードし、sam deploy
でLambdaにデプロイ、API Gatewayに設定していました。
これが新しいBrefでは
serverless deploy
serverlessのコマンド1つでデプロイできるようになりました。書いてて薄々きづいてきましたが、Brefの進化は、Serverless Frameworkの進化が大きく影響を与えているようです。
Laravel環境をつくってみる。
では、Laravelの環境をセットアップしてみましょう。上記の通りですが、作業をまとめてみると非常にシンプルなのがよくわかります。
インストール
コマンドでインストールしていきます。
composer create-project laravel/laravel serverless-laravel --prefer-dist
cd serverless-laravel
composer require bref/bref
vendor/bin/bref init
What kind of lambda do you want to create? (you will be able to add more functions later by editing `serverless.yml`) [PHP function]:
[0] PHP function
[1] HTTP application
[2] Console application
> 1 # どれを選んでもあとで設定を変えるので特に問題ないですが、HTTP applicationを選びました。
Creating serverless.yml
Creating index.php
[OK] Project initialized and ready to test or deploy.
自動生成されたプロジェクト直下のindex.phpは削除しても問題ありません。
serverless設定
そして、serverlessの設定を行います。
service: serverless-laravel
provider:
name: aws
region: ap-northeast-1
runtime: provided
environment:
# Laravel environment variables
APP_STORAGE: '/tmp'
plugins:
- ./vendor/bref/bref
functions:
website:
handler: public/index.php
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-73-fpm}
events:
- http: 'ANY /'
- http: 'ANY /{proxy+}'
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-73} # PHP
- ${bref:layer.console} # The "console" layer
regionですが、us-east-1からap-northeast-1に変更しています。この設定はwebsiteとartisanを用意しています。websiteはHTTPアクセス用の設定、artisanはコンソール(後述)の設定です。
Laravel微調整
Lambdaのカスタムランタイム上で動作しますが、/tmpディレクトリをのぞきファイルを保存することができません。そこで、少しLaravelを調整します。
以下のとおり、ファイルを修正します。
$app = new Illuminate\Foundation\Application(
$_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
);
+ $app->useStoragePath($_ENV['APP_STORAGE'] ?? $app->storagePath());
+ VIEW_COMPILED_PATH=/tmp/storage/framework/views
+ SESSION_DRIVER=array
- SESSION_DRIVER=file
+ LOG_CHANNEL=stderr
- LOG_CHANNEL=stack
public function boot()
{
+ if (! is_dir(config('view.compiled'))) {
+ mkdir(config('view.compiled'), 0755, true);
}
}
デプロイ
ここまで設定したら、デプロイするだけです。
serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
.... 中略 ....
Serverless: Stack update finished...
Service Information
service: serverless-laravel
stage: dev
region: ap-northeast-1
stack: serverless-laravel-dev
resources: 15
api keys:
None
endpoints:
ANY - https://**********.execute-api.ap-northeast-1.amazonaws.com/dev
ANY - https://**********.execute-api.ap-northeast-1.amazonaws.com/dev/{proxy+}
functions:
website: serverless-laravel-dev-website
artisan: serverless-laravel-dev-artisan
layers:
None
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
endpointsに記載されてるURLにアクセスしてみましょう。
無事、表示されました。
コンソールも実行できるか確認してみましょう。
vendor/bin/bref cli --region ap-northeast-1 serverless-laravel-dev-artisan -- inspire
Simplicity is the essence of happiness. - Cedric Bledsoe
こちらも動きました。コンソールの設定をすることで、ローカル環境からLambda上のLaravel(artisan)を実行します。serverless.ymlの設定でregionをap-northeast-1に変更したので、bref cliの実行オプションに --region ap-northeast-1
を付与します。付与しないとエラーとなるので注意しましょう。
まとめ
PHPerKaigiから約半年ですが、春先よりも随分と設定がシンプルになった印象がしました。前よりも環境が準備しやすいので試しやすく、いろいろなサーバーレスPHPの実例が出てくるような気がします。
来年もPHPerKaigiに参加する予定なので、なにか実例ありましたら是非当日おしえてくださいー!