🦖

Bref でマイクロサービスを爆速で構築する - 調査・準備編

2023/12/22に公開

はじめに

本記事は、「Fusic Advent Calendar 2023」の23日目の記事です。
https://qiita.com/advent-calendar/2023/fusic

Bref はサーバレスに AWS 上に PHP を動作させることのできるランタイムを提供してくれるツールです。今回はこの Bref を用いて、API エンドポイントを爆速で作成するための準備手順をまとめました。

なお、本記事で解説する Bref や Serverless Framework の内容については、これから開発を進めるための調査内容をまとめたものになります。ほぼ公式ドキュメントに記載されている内容に尽きるので、開発段階における Tips など、深い内容までは言及できておりません。ご了承ください。

また、文字数が多くなりすぎたため、本記事は「調査・準備編」とすることにしました。
AWS構成(マイクロサービスとしてのつなぎ込みを行う部分)に関する内容については、後日別の記事として作成します。

調査の目的/背景

ある外部 SDK を利用するための認証情報を作成する機能を追加する事になったのですが、この処理の実行箇所を Fargate で動作している既存の API コンテナとは切り分けたい、という事情がありました。

DB については共同で利用したいので同一の AWS アカウント上に構築することが必要でしたが、用途も限定的で、利用頻度も少ないと見込まれているため、あらたにコンテナを稼働させるのは運用的に過剰で、費用的にも無駄がありそうということで Bref の採用を検討し始めました。

既存システム

既存のバックエンドでは、API と管理画面がそれぞれ別のコンテナ(サービス)で動いており、共通の DB を利用しています。ALB のホストベースルーティングで、api.****.jp にリクエストされた場合には API コンテナ、admin.****.jp にリクエストされた場合には管理画面コンテナにルーティングするように設定されています。


現状の構成(ざっくり)

今回は、auth.****.jp という様な URL で ALB にリクエストが送られたとき、ターゲットとして APIGateway にリダイレクトさせることで、既存の API コンテナとは別に処理を行うマイクロサービスとして機能追加を行いたいと思います。

Bref について

まずは Bref について、調査した内容をまとめます。また、Bref を利用するにあたり、改めて Serverless の概念についても整理しました。

なぜServerlessを使うのか

Serverless とは、サーバを管理してくれるクラウドサービスを利用することです。これにより、開発者はサーバの存在を特に意識することなく、サービスの開発に集中する事ができます。いわずもがなですが、サービスを動かすためにサーバが必要ない・存在しないということではありません。

通常、サーバー上で PHP を実行するには、以下のような運用が必要になります。

  • サーバーのセットアップ、設定、保守
  • サーバーの固定料金を支払う
  • トラフィックが増えたらサーバーをスケールさせる

PHPをサーバーレスで実行すると、

  • サーバーをセットアップする必要はなく、AWSが引き受けてくれる
  • 使用した分だけ(リクエストごとに)支払う
  • 自動的にスケールする

つまりサーバーレス構成により、少ない労力で・よりスケーラブルで・手頃な価格の・信頼性の高いアーキテクチャを提供することができます。

Bref

Bref はオープンソースの Composer パッケージとして提供されており、AWS に PHP アプリケーションをデプロイし、AWS Lambda 上で実行するのに役立ちます。

Bref は、PHP アプリケーションの実行を簡単かつシンプルにすることを目指していますが、今回調査するにあたって、すぐにその言葉の意味を体感することができました。Laravel の API バックエンド環境の構築だけでいうと、数十分で実現できるレベルに簡単です。

Bref の目指すべき方向性は以下のとおりです。この理念を実現するために、Serverless の仕組みを活用しています。

  1. simplify problems by removing choices
    → あらゆるニーズには対応しない
  2. provide simple and familiar solutions
    → 強力なカスタムソリューションを目指さない
  3. empower by sharing knowledge
    → 抽象化された知識の背後にたくさんの物事を隠蔽せず、しっかりと知識を共有する

Lambda の制約

現状、Lambda で PHP アプリケーションを実行する上で 「レガシーアプリケーションの移行」「リアルタイムアプリケーション」 には明確に制約があります。前者は既存のコードを書き換える手間が少なからず発生すること、後者ではコールドスタートの発生が避けられないため、常にレイテンシを100ms以下にしなければならないといった要件が満たせないといった制約です。

今回の目的である、SDK 用の認証情報を作成するサービスにおいては、両者の制約ともネックにはならないため採用する事ができそうでした。

実際にAPIを構築してみる

Serverless Framework

https://bref.sh/docs/setup

今回は、Serverless Framework のインストールの説明については省略します。公式ガイドの通り設定してもらえたら特につまる所もないかと思います。

Laravelの動作環境構築

https://bref.sh/docs/laravel/getting-started

Laravel は Sail で構築していきます。Sail は Laravel のデフォルトの Docker 開発環境を操作するための軽量コマンドラインインターフェイスです。公式でコマンドが提供されているので、これを利用します。

curl -s https://laravel.build/bref-laravel-setup | bash

cd bref-laravel-setup
./vendor/bin/sail up  # ローカルでコンテナを起動

ほんと簡単に環境構築できるようになりましたね...
Laravel をインストールできて、ローカルでウェルカムページの表示確認までできたら、次は AWS 上でLaravel を動作させるためのパッケージを導入していきます。

./vendor/bin/sail composer require bref/bref bref/laravel-bridge

composer上の設定は以上です。

serverless framework 用 config の設定

まずは、Serverless Framework の config (serverless.yml) を作成します。
コンテナが立ち上がった状況で、下記のコマンドを実行すればOKです。

./vendor/bin/sail artisan vendor:publish --tag=serverless-config

内容も基本的にはデフォルトのままでOKですが、必要に応じて変更を行います。

上記で使用した Laravel インストールのコマンドでは、現時点で laravelsail/php8.2-composer という Docker イメージを使用して PHP と composer をインストールしますので、config の FPM のバージョンもそれに合わせて修正しています。

また、リソースをデプロイするリージョンも 「ap-northeast-1(東京リージョン)」に変更しました。

service: laravel

provider:
    name: aws
    # The AWS region in which to deploy
    region: ap-northeast-1
    # Environment variables
    environment:
        APP_ENV: production # Or use ${sls:stage} if you want the environment to match the stage

package:
    # Files and directories to exclude from deployment
    patterns:
        - '!node_modules/**'
        - '!public/storage'
        - '!resources/assets/**'
        - '!storage/**'
        - '!tests/**'

functions:

    # This function runs the Laravel website/API
    web:
        handler: public/index.php
        runtime: php-82-fpm
        timeout: 28 # in seconds (API Gateway has a timeout of 29 seconds)
        events:
            - httpApi: '*'

    # This function lets us run artisan commands in Lambda
    artisan:
        handler: artisan
        runtime: php-82-console
        timeout: 720 # in seconds
        # Uncomment to also run the scheduler every minute
        #events:
        #    - schedule:
        #          rate: rate(1 minute)
        #          input: '"schedule:run"'

plugins:
    # We need to include the Bref plugin
    - ./vendor/bref/bref

config の用意ができたら、後は Serverless Framework でデプロイするだけです。CloudFormation のスタックが作成され、バッチでリソースの管理が行われます。

serverless deploy

デプロイに成功すると、API Gateway のエンドポイントが払い出されます。

Deploying laravel to stage dev (ap-northeast-1)

✔ Service deployed to stack laravel-dev (295s)

endpoint: ANY - https://********.execute-api.ap-northeast-1.amazonaws.com
functions:
  web: laravel-dev-web (33 MB)
  artisan: laravel-dev-artisan

上記のエンドポイントにアクセスすると、ローカルで動作確認したときのように、Welcomeページが表示されることが確認できます。Laravel の爆速デプロイの成功です。

今回の本来の目的は API の提供なので、ここからさらに修正を加えていきます。RouteServiceProvider.php から web.php のルートを削除し、api.php にルートを追加することで API Gateway のエンドポイントにアクセスしたときに JsonResponse が返ってくる様に変更しました。

ルーティングの微修正(動作確認)

<?php

namespace App\Providers;

use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Route;

class RouteServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->routes(function () {
            Route::middleware('api')
                ->group(base_path('routes/api.php'));
        });
    }
}
<?php

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route; 

// Hello World!!
Route::get('/', function() {
    return new JsonResponse('Hello World!');
});


できました!

あとは、実際の認証機能を Laravel で実装していくだけです!
すぐに実装に移れるの幸せ!

さいごに

Serverless は有望で、実際に数十分で Laravel API のデプロイまで行うことができたことからも、開発の速度をグンと上げてくれそうだなという期待感を持たせてくれます。と同時に、AWS上で扱う上では、構成として選択すべきこと、把握すべきベストプラクティスはたくさんありそうだなと感じていて、落とし穴もかなり多そうです。

今考えている構成に関して言うと、API Gateway は通常、クライアントから直接リクエストを受けるエンドポイントです。バックエンドにトラフィックをルーティングするための ALB から、リダイレクトする形で API Gateway にトラフィックを流していいものか、現時点で正直わかっていません。

引き続き、実際の実装・構築を行っていく上で、Tipsとして記事にまとめていきたいと思います。

Discussion