Fusic Tech Blog

Fusicエンジニアによる技術ブログ

始めよう!PHP AWS Lambda with Laravel!
2024/03/29

始めよう!PHP AWS Lambda with Laravel!

こんにちは!
Fusicの清家です。

この記事は「AWS LambdaとServerless Advent Calendar 2022」1日目の記事です.

今回はAWS Lambdaを使いたいけどどうして良いかわからない、
そんな方に少しでも身近に感じて頂ける記事を書きたいと思います。

PHPerでもAWS Lambdaしたい!

オフィシャルサポートされているランタイムを利用する方にはAWS Lambdaは身近になってきていますが、
PHPerがAWS Lambdaを実行する場合は、必然的にCustom Runtimeを利用することになります。

その場合、簡単に利用できる一つの案として、「AWS Lambda Web Adapter」を利用できます。
AWS Lambda で Web アプリケーションを実行するためのツールです。

以下examplesの様にDockerfile内で1行追加するのみで利用できます。

FROM public.ecr.aws/amazonlinux/amazonlinux:2.0.20220121.0

COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.5.0 /lambda-adapter /opt/extensions/lambda-adapter

RUN amazon-linux-extras install -y nginx1 php7.4 && yum clean all && rm -rf /var/cache/yum

# Nginx config
COPY nginx/ /etc/nginx/

# PHP config
COPY php/ /etc/

# Expose ports
EXPOSE 8080

# Define default command.
COPY run.sh /run.sh
CMD ["/run.sh"]

Lambda 関数実装は出来る限りシンプルに作成するべきなので、原則に従うとここからAPIを作成していく事が
一つの手段として考えられると思います。

ただここから実際のデプロイまで実行するのは、一定の知識ハードルがあるように思えます。

イージーにPHP AWS Lambdaしたい!

そこで利用したいのが、最近よく話に聞くようになったbrefです。
「Simple and scalable PHP applications with serverless」 と書かれている通り、
簡単にAWS Lambdaを利用することが出来ます。

以下のように簡単に環境を作成することが出来ます。


# serverless frameworkのインストール
$ npm install -g serverless

# composer で brefのインストール
$ composer require bref/bref

 composer output

# serverless.ymlのインストール
$ 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`) [Web application]:
  [0] Web application
  [1] Event-driven function
 > 0

Creating index.php


 [OK] index.php successfully created.


Creating serverless.yml


 [OK] serverless.yml successfully created.



 [OK] Project initialized and ready to test or deploy.

# デフォルトのAWS Profileを使う場合
$ serverless deploy
or 
# 指定のAWS Profileを使う場合
$ AWS_PROFILE=phper_demo_serverless serverless deploy

Deploying app to stage dev (us-east-1)

 Service deployed to stack app-dev (131s)

endpoint: ANY - https://XxxxxxxxxX.execute-api.us-east-1.amazonaws.com
functions:
  api: app-dev-api (988 kB)

Need a better logging experience than CloudWatch? Try our Dev Mode in console: run "serverless --console"

$ curl https://XxxxxxxxxX.execute-api.us-east-1.amazonaws.com/

<!DOCTYPE html>
<html lang="en">
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>Welcome!</title>
    <link href="https://fonts.googleapis.com/css?family=Dosis:300&display=swap" rel="stylesheet">
    <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="flex h-screen">
    <div class="rounded-full mx-auto self-center relative" style="height: 400px; width: 400px; background: linear-gradient(123.19deg, #266488 3.98%, #258ECB 94.36%)">
        <h1 class="font-light absolute w-full text-center text-blue-200" style="font-family: Dosis; font-size: 45px; top: 35%">Hello there,</h1>
        <div class="w-full relative absolute" style="top: 60%; height: 50%">
            <div class="absolute inset-x-0 bg-white" style="bottom: 0; height: 55%"></div>
            <svg viewBox="0 0 1280 311" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M1214 177L1110.5 215.5L943.295 108.5L807.5 168.5L666 66.5L581 116L517 49.5L288.5 184L163.5 148L-34.5 264.5V311H1317V258.5L1214 177Z" fill="white"/><path d="M1214 177L1110.5 215.5L943.295 108.5L807.5 168.5L666 66.5L581 116L517 49.5L288.5 184L163.5 148L-34.5 264.5L163.5 161L275 194L230.5 281.5L311 189L517 61L628 215.5L600 132.5L666 77L943.295 295L833 184L943.295 116L1172 275L1121 227L1214 189L1298 248L1317 258.5L1214 177Z" fill="#DCEFFA"/></g><defs><clipPath id="clip0"><rect width="1280" height="311" fill="white"/></clipPath></defs></svg>
        </div>
    </div>
</body>
</html>

このようにとてもシンプルに環境を作成する事が出来ます。
※作成された環境は公開されるAPIですのでご注意ください。

PHPでやるならLaravelしたい!

一方でPHPerだったら御用達のWeb Framework、Laravelを利用したい!って方は多いのではないでしょうか。
Bref公式サイトでも紹介されている通り、簡単に導入することが可能です

# Laravelのプロジェクトを作成
$ composer create-project laravel/laravel bref-laravel-project
$ cd bref-laravel-project
# bref Install
$ composer require bref/bref bref/laravel-bridge --update-with-dependencies
# serverless.yml 生成
$ php artisan vendor:publish --tag=serverless-config
php artisan vendor:publish --tag=serverless-config

   INFO  Publishing [serverless-config] assets.

  Copying file [vendor/bref/laravel-bridge/config/serverless.yml] to [serverless.yml] ......................................................... DONE

実行するPHPのバージョンに合わせる

serverless.yml内に利用するlayersの記述があるので、phpのバージョンをcomposer実行したものと合わせます

$ vim serverless.yml

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-81-fpm} <- ※※※ 80 or 81

        events:
            - httpApi: '*'
    # This function lets us run artisan commands in Lambda
    artisan:
        handler: artisan
        timeout: 120 # in seconds
        layers:
            - ${bref:layer.php-81} # PHP <- ※※※ 80 or 81
            - ${bref:layer.console} # The "console" layer

その後、同じ様にデプロイすればOKです。

$ serverless deploy

Deploying laravel to stage dev (us-east-1)

 Service deployed to stack laravel-dev (113s)

endpoint: ANY - https://YyyyyyyyyY.execute-api.us-east-1.amazonaws.com
functions:
  web: laravel-dev-web (30 MB)
  artisan: laravel-dev-artisan (30 MB)

1 deprecation found: run 'serverless doctor' for more details

Improve API performance monitor it with the Serverless Console: run "serverless --console"

$ curl https://YyyyyyyyyY.execute-api.us-east-1.amazonaws.com

                    <div class="ml-4 text-center text-sm text-gray-500 sm:text-right sm:ml-0">
                        Laravel v9.42.2 (PHP v8.1.12)
                    </div>
                </div>
            </div>
        </div>
    </body>
</html>

開発時

開発時はBrefのDocker Imageが提供されているので、こちらでスムーズに開発を行うことが出来ます。
※ 公式の docker-compose.ymlの指定は volumesがRead onlyになっているので、
ログを吐き出したい場合等は適宜変更しましょう

version: "3.5"

services:
    console:
        image: bref/php-81
        volumes:
            - .:/var/task:ro # Read only, like a lambda function
        entrypoint: php
        command: demo/console.php

    web:
        image: bref/fpm-dev-gateway
        ports:
            - '8000:80'
        volumes:
            - .:/var/task:ro # Read only, like a lambda function
        depends_on:
            - php
        environment:
            HANDLER: demo/http.php
    php:
        image: bref/php-81-fpm-dev
        volumes:
            - .:/var/task:ro # Read only, like a lambda function

AWS Lambda で Laravelする必要はあるの?

出来るだけシンプルなAPIを作成する事が求められるAWS Lambdaにおいて、
本当にWeb Frameworkを利用するメリットはあるのか?
という疑問をお持ちになる方もいらっしゃると思います。

ここは主観が入ってしまいますが、パフォーマンス要件が非常に厳しいなどの
厳しい要件が入ってない場合、利用するメリットはあるように思えています

スピード感を持って構築が出来て、なおかつWebAPIとしての速度も最低限の速度はあるように思えます。

その上で、Laravelのエコシステムに乗っかることが出来るメリットは大きいです。
小さなプロダクトなどのスモールスタートや、短期案件等において優位性を持たす事が出来るのは大きいです。

LaravelとAWSの親和性は非常に高く、構築速度を高める事が出来ます。

一方で、この選択は直行性を自ら注入しており、Laravelのバージョンアップも意識しなければなりません。
シンプルに構築するべきLambdaのベストプラクティス原則を忘れないようにしましょう

パフォーマンスは?

以下の発表内にて触れていますが、超高レイテンシーが求められない限りは
スループットとしては十分な結果になっているのではないかと考えています。

Amazon S3 Selectで実現するサーバーレス高負荷対応サイト

PHP以外でもWeb Framework AWS Lambdaしたい!

例えばRubyの Ruby on Rails を利用したい場合は、Jetsというツールがあったり
Pythonの Flask を利用したい場合は、serverless-wsgi、serverless-python-requirementsを利用する方法が
Serverless Frameworkのブログにて紹介されてます。
Goの場合は awslabsにて aws-lambda-go-api-proxyが存在するなど、
やはりWeb Framework をAWS Lambdaにて利用する需要はあるのかと思います

シンプルに構築出来る様に意識しながら、 Web Framework を利用して AWS Lambdaしましょう!

明日は このアドベントカレンダーを作成してくれた @_kenshさんの記事です!
お楽しみに!

shiro seike / せいけ しろう / 清家 史郎

shiro seike / せいけ しろう / 清家 史郎

Company:Fusic CO., LTD. Slides:slide.seike460.com blog:blog.seike460.com Program Language:PHP , Go Interest:Full Serverless Architecture