LaravelのAPIとバッチをサーバレスに構築したく下記3つを使って
APIGatewayとLambda環境を簡単に構築してみます。
- PHPをLambdaで動かす為のサポートをしてくれるbref
- LaravelをLambda用に動作するようにしてくれるlaravel-bridge
- AWSにサーバレス環境を自動構築してくれるnpm serverless
Lambdaとは
- Lambdaとは
- インフラの構築・管理を気にしなくてよく、コードをアップすればLambdaが動かしてくれる
- 自動でスケーリングしてくれます
- 処理した時間だけ課金(個人レベルの利用であれば無料枠を超えることはほぼない
- httpリクエストをトリガーにLambdaを使うためにAPIGatewayを使います
- デメリット
- Lambdaに合わせた実装が必要になる
- 最大15分の処理時間に合わせる
- httpリクエストだと29秒
- 容量512MBまでなのでそれに合わせる
- リクエストとレスポンスのペイロードが6MBまでといった細かな制約も
- 関数インスタンスの起動が遅い
- 数百ミリ秒の遅延が発生する
- 設定によって起動したインスタンスを再利用することで改善できるようです
- 料金は別途かかる
- プロビジョニングされた同時実行
- Lambdaに合わせた実装が必要になる
- Lambda+RDS使うときの注意→RDSProxyを使う
- LambdaからRDSへの同時接続数に上限があるのでアクセス多いとエラーになる(db.t2.micro/メモリ1GBだと85)
- Lambdaは全てのプロセスが独立してしまうので、コネクションが使い回せず同時接続数がどんどん増えます
- RDSProxyで既存のコネクションを再利用することができるので、同時接続数をこれでセーブする
詳細
- リクエストを処理している関数のインスタンスは、リサイクルされるまで数時間アクティブのままになる
- 関数は、/tmpディレクトリ内のローカルストレージにアクセス可
Laravelでの構築の仕方
1.(npm)serverlessのインストール
awsの認証情報もインストール後設定します。
$ npm install -g serverless
$ serverless config credentials --provider aws --key <key> --secret <secret>
2.(php)brefとlaravel-bridgeインストール
PHPをLambdaで動かす為のサポートをしてくれるbrefと、LaravelをLambda用に動作するようにしてくれる
laravel-bridgeをインストールします。
$ composer require bref/bref bref/laravel-bridge
3.serverless.ymlを生成
下記コマンドでserverless.ymlを生成します。
serverless.ymlはどんなAPIGateway・Lambdaを作るかの設計図になります。
$ php artisan vendor:publish --tag=serverless-config
4.serverless.ymlを自分の環境に合わせる
ほぼ修正する必要なく利用できますが、下記自分の環境に合わせて修正します。
- regionの変更
- timeoutの設定(デフォルト120秒。最大15分(900秒))
- cronの設定(events > schedules)
- artisanコマンドの場合、inputで「"」で括る('"video:channel"')
functions:
# This function runs the Laravel website/API
web:
handler: public/index.php
timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
layers:
- ${bref:layer.php-74-fpm}
events:
- httpApi: '*'
# This function lets us run artisan commands in Lambda
artisan:
handler: artisan
timeout: 120 # in seconds
layers:
- ${bref:layer.php-74} # PHP
- ${bref:layer.console} # The "console" layer
events:
- schedule:
rate: cron(0 0 * * ? *) # GMT
input: '"video:channel"'
- schedule:
rate: cron(15 0 * * ? *) # GMT
input: '"video:videolist"'
5.AWSデプロイ
下記コマンド実行するとLambda+APIGatewayが自動構築されます。
$ php artisan config:clear
$ serverless deploy
ファンクション単位でのデプロイ
$ serverless deploy function -f <yourfunction>
6.自動デプロイ
ローカルでコマンドを打つのも手間なのでgit pushしたら自動で「serverless deploy」が走るようにします。
github actionを用います。
- 1.S3のバケットに.envをアップロードする
- .envはgit管理対象外にしたい
- S3に.envアップロードしデプロイ時に利用する
- 1.GithubのActions secretsを設定します。
- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- S3_DOWNLOAD_BUCKET(.envファイル用
- 2.workflowを作成
https://github.com/serverless/github-action
https://github.com/aws-actions/configure-aws-credentials
name: Deploy master branch
on:
push:
branches:
- develop
defaults:
run:
working-directory: ./src
jobs:
deploy:
name: deploy
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
steps:
- uses: actions/checkout@v2
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
- name: Download file from S3
env:
S3_DOWNLOAD_BUCKET: ${{ secrets.S3_DOWNLOAD_BUCKET }}
run: |
aws s3 cp s3://$S3_DOWNLOAD_BUCKET/.env ./ --quiet
- name: Output file contents
run: |
cat .env
- name: Install Dependencies
run: composer install --prefer-dist --optimize-autoloader --no-dev
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- name: serverless deploy
run: |
npm i -g serverless@2.x
serverless deploy
env:
AWS_REGION: ap-northeast-1
AWS_VERSION: latest
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
あとはgit pushすればデプロイされます。
ローカル
開発環境
下記参考に実装しました。
/tmp以外ではコマンドからファイル生成できないので、やりづらい。(readonlyになる為)
https://bref.sh/docs/web-apps/local-development.html
version: "3"
services:
db:
image: mysql:5.7
volumes:
- ./db:/var/lib/mysql
- ./initdb.d:/docker-entrypoint-initdb.d
- ./mysql/my.cnf:/etc/mysql/conf.d/my.cnf
restart: always
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: vtuber
TZ: "Asia/Tokyo"
ports: ["3306:3306"]
web:
image: bref/fpm-dev-gateway
ports:
- '8000:80'
volumes:
- ../src:/var/task
depends_on:
- php
environment:
HANDLER: public/index.php
DOCUMENT_ROOT: public
php:
image: bref/php-74-fpm-dev
volumes:
- ../src:/var/task:ro
- ./tmp:/tmp
バッチ
ローカルからLambdaのバッチを実行する
# AWS_DEFAULT_REGION=ap-northeast-1 AWS_ACCESS_KEY_ID=[access_key_id] AWS_SECRET_ACCESS_KEY=[secret_access_key] vendor/bin/bref cli laravel-dev-artisan video:channel
php artisan migrateしたいときは下記です。
「--force」つけないと本番環境で「本当に実行しますか?」と入力待ち状態になってしまう為です。
https://mrkmyki.com/%E9%80%86%E5%BC%95%E3%81%8Dlaravel/laravel%E3%81%A7%E5%BC%B7%E5%88%B6%E7%9A%84%E3%81%ABmigration%E3%82%92%E5%AE%9F%E8%A1%8C%E3%81%99%E3%82%8B
vendor/bin/bref cli laravel-dev-artisan -- migrate --force
AWS CloudWatchLogsの見方
REPORT RequestId: 3595eefc-ec9c-4021-a826-28453c0f5afd Duration: 654.51 ms Billed Duration: 980 ms Memory Size: 1024 MB Max Memory Used: 102 MB Init Duration: 325.39 ms
- Duration: 654.51 ms / 関数のハンドラーメソッドがイベントの処理に費やした時間
- Billed Duration: 980 ms / 呼び出しの課金対象の時間
- Init Duration: 325.39 ms / 最初に処理されたリクエスト(コールドスタート時)についてハンドラーメソッド外で関数をロードしてコードを実行するためにランタイムにかかった時間