LambdaでLaravelを動作させようと思ったけど、少しコケたのでメモしとく

私はPHPerなのですが、最近、仕事関係でLambdaの話がちょくちょく出てきたので、ちょっと勉強がてら調査することに。

今更なのですが Lambda でPHPを動かせるようになっていたということに驚いた。

で、調べてみるとどうやらbrefというライブラリを使えば、簡単にLambda上でLaravelも動かせるらしい。
<a target="_blank" href="https://bref.sh/">Bref - Serverless PHP made simple</a>


わざわざ Lambda で PHPを使う必要があるのかと思うかもだけど、一緒にお仕事しているチームの構成を考えるとメンテナンスも含めてLaravelが使えるというのはとても助かるのです。

で、さくっと試してみようと思ったところデプロイで躓いちゃったので、メモ残しておきます。

## 環境

- Windows 10 Home
- <a target="_blank" href="https://docs.docker.com/toolbox/overview/">Docker Toolbox</a>
- PHP7.4
- Laravel 8

## IAM ユーザーを作成する

Lambda を利用するにあたり必要な IAM ユーザーを作成。

<a target="_blank" href="https://bref.sh/docs/installation/aws-keys.html">Creating AWS access keys - Bref</a>

とりあえず試したいだけだから、まんまガイドに従って作成。
簡単、簡単。

## serverless framwork のインストール

後述しますが、本当は docker で serverless が動作する環境を作ろうと思っていたのですが、なぜかメモリ不足というエラーのため動作せず。。。

なので、Windows に直接 serverless をインストール。

<a target="_blank" href="https://www.serverless.com/framework/docs/getting-started/">Serverless Getting Started Guide</a>

docker で環境作りに悩んでいたのが馬鹿みたいに、サクッと環境ができた。
credential の設定もガイドに従って設定。

私、この環境を作るまで<a target="_blank" href="https://chocolatey.org/">Chocolatey</a>というソフトを存じ上げませんでした。
いや～、ダサいというイメージの Windows ですが、少しずつクールになってきていると思っているのは私だけ？ｗ

## Laravel 環境を docker で作る

毎回 docker 自分で作るの面倒だなぁと思っていたら、多くのLGTMがついてた下記で環境作り。

<a target="_blank" href="https://qiita.com/ucan-lab/items/5fc1281cd8076c8ac9f4">最強のLaravel開発環境をDockerを使って構築する【新編集版】 - Qiita</a>

いや～、ありがたい。

## bref をインストール

公式ドキュメント通り。

<a target="_blank" href="https://bref.sh/docs/frameworks/laravel.html#setup">Serverless Laravel applications - Bref</a>

ガイドに従って、`.env` の設定も行いましたよ。

```tex:.env
#LOG_CHANNEL=stack
LOG_CHANNEL=stderr

#SESSION_DRIVER=file
SESSION_DRIVER=array

VIEW_COMPILED_PATH=/tmp/storage/framework/views
```

楽ですね～

## いざ deploy したら、動かなかった。。。

ここまで、ガイドに従うだけなので、超簡単に環境構築できていました。
`serverless deploy` でデプロイもすんなり成功！

が、、、エンドポイントにアクセスしたらエラー発生。。。

```
Exception
The /var/task/bootstrap/cache directory must be present and writable.

----
/var/task/vendor/laravel/framework/src/Illuminate/Foundation/PackageManifest.php
----
            return [];
        }
        return json_decode(file_get_contents(
            $this->basePath.'/composer.json'
        ), true)['extra']['laravel']['dont-discover'] ?? [];
    }
    /**
     * Write the given manifest array to disk.
     *
     * @param  array  $manifest
     * @return void
     *
     * @throws \Exception
     */
    protected function write(array $manifest)
    {
        if (! is_writable($dirname = dirname($this->manifestPath))) {
            throw new Exception("The {$dirname} directory must be present and writable.");
        }
        $this->files->replace(
            $this->manifestPath, '<?php return '.var_export($manifest, true).';'
        );
    }
}
----
Arguments
"The /var/task/bootstrap/cache directory must be present and writable."
```

で結論からいうと、エラーの通り `/var/task/bootstrap/cache` に書き込もうとしてエラーが発生しているので、これを直す。
Lambda で書き込み権限あるのは、`/tmp` 配下だけらしいので、以下を `.env` に追加。

```tex:.env
APP_SERVICES_CACHE=/tmp/services.php
APP_PACKAGES_CACHE=/tmp/packages.php
APP_CONFIG_CACHE=/tmp/config.php
APP_ROUTES_CACHE=/tmp/routes.php
APP_EVENTS_CACHE=/tmp/events.php
```

で、再度デプロイして、アクセスすると200が返ってきましたよ～
上記の設定をする前にググってたら、 `$app->useStoragePath()` を設定すると良いよとか書いてあったので、試したりしたのですがうまくいかず、上記の記述を追加するまでにまぁまぁな時間がかかりました。。

というわけで、どなたか同じ状況になったときの参考にしてもらえれば幸いです。

## (番外)dockerにserverless環境を作ったけど、deploy できなかった。。

前述の docker 環境に以下のような serverless 用のコンポーネントを作った。

```docker:docker-compose.yml
  serverless:
    build:
      context: .
      dockerfile: ./infra/docker/serverless/Dockerfile
      args:
        - AWS_ACCESS_KEY_ID=<key>
        - AWS_SECRET_ACCESS_KEY=<secret>
    tty: true
    stdin_open: true
    image: serverless
    working_dir: /app
    volumes:
      - ./backend:/app
    container_name: serverless
```

```dockerfile:./infra/docker/serverless/Dockerfile
FROM python:3.7-alpine
ARG AWS_ACCESS_KEY_ID
ARG AWS_SECRET_ACCESS_KEY

ENV NODE_PATH /usr/lib/node_modules/
# install nodejs
RUN apk update \
  && apk add --no-cache nodejs npm

# install aws-cli
RUN pip install awscli

# install serverless framework
RUN npm install -g serverless serverless-plugin-existing-s3

# set aws key
RUN sls config credentials --provider aws --key $AWS_ACCESS_KEY_ID --secret $AWS_SECRET_ACCESS_KEY

# change work directory
RUN mkdir -p /app
WORKDIR /app
```

ほんでもって、docker内で `serverless deploy` を実行したところ、なぜか以下のエラー。

```console:console
Serverless: Setting up AWS...
root@02e9b3d52dbe:/work/backend# serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...

  Error --------------------------------------------------

  Error: ENOMEM: not enough memory, open '/work/backend/vendor/mockery/mockery/library/Mockery/Matcher/NoArgs.php'

     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          linux
     Node Version:              12.19.0
     Framework Version:         2.5.0
     Plugin Version:            4.0.4
     SDK Version:               2.3.2
     Components Version:        3.2.1
```



メモリは十分にあると思うのに理由がわからない。
散々悩んだあげく、諦めたのさ～