LaravelをコンテナにしてLambdaでデプロイするのが超簡単になった2021年

2021/05/26追記
Nuxtバージョン作成しました。
[NuxtをコンテナにしてLambdaでデプロイするのが超簡単になった2021年](https://qiita.com/umihico/items/fb8733c6cba1e195181d)
Djangoバージョンもあります。
[DjangoをLambdaを使ってサーバレスにデプロイする](https://qiita.com/umihico/items/4534e1f84e8de5a62db5)

[昨年同じ記事](https://qiita.com/umihico/items/64fcf159f68ebd866170)を書きましたが、完全に過去の遺物と化しており、現在の手順はまるで違います。LaravelをコンテナにしてLambdaにデプロイする記事は見つからないので、書きました。

デモサイトとgithubは以下です。
https://w0qw04g8sj.execute-api.ap-northeast-1.amazonaws.com/
https://github.com/umihico/laravel-lambda-docker-bref

### curlでプロジェクトが作成できる

パスが動的に設定可能で、そのままアプリ名となります。この場合`larademo`というフォルダが作成され、配下に展開されます。

```bash
curl -s https://laravel.build/larademo | bash
```

### docker-composeがデフォルトでパッケージされている。

即座にコンテナ内でcomposer, phpコマンドを使わせてくれます。プロジェクト自体もcurlで作ってますので、ローカルマシンの環境を気にする必要がなくなるということですね:tada:

```bash
cd larademo
./vendor/bin/sail up -d # docker-compose upに相当。立ち上げている間にコマンドを流す
./vendor/bin/sail composer require bref/bref bref/laravel-bridge # サーバーレス用ライブラリ
```

### brefがserverless.ymlを生成してくれる

Serverless Frameworkを使いますが、今やbref側でセッティング済みのテンプレを作ってくれます。

```bash
./vendor/bin/sail php artisan vendor:publish --tag=serverless-config
./vendor/bin/sail down # 本稿ではもう使わないのでdocker-composeを終了します。
```

### Lambdaがコンテナイメージに対応している

こちらは有名ですね。以前はbrefはLambdaレイヤーとして使ってましたが、今回はベースイメージになりました。おかげでたったの３行です。`Dockerfile`を作成し、`serverless.yml`はイメージをビルドしてそのイメージを参照するよう編集します。ECR管理はなんとServerless Frameworkがやってくれます。

```Dockerfile:Dockerfile
FROM bref/php-80-fpm
COPY . /var/task
CMD [ "public/index.php" ]
```

```diff:serverless.yml
service: laravel

provider:
    name: aws
    # The AWS region in which to deploy (us-east-1 is the default)
-    region: us-east-1
+    region: {opt:region, us-east-1}
    # The stage of the application, e.g. dev, production, staging… ('dev' is the default)
    stage: dev
    runtime: provided.al2
+    ecr:
+        images:
+            laravel:
+                path: ./
package:
    # Directories to exclude from deployment
    exclude:
        - node_modules/**
        - public/storage
        - resources/assets/**
        - storage/**
        - tests/**
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}
+        image:
+             name: laravel
        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
-
-
- plugins:
-    # We need to include the Bref plugin
-    - ./vendor/bref/bref
```


作成したらslsコマンドでデプロイを行います。

```bash
sls deploy --region ap-northeast-1
```

### API GatewayのURLからステージ名が消えた

REST APIではなく、HTTP APIを選択できるようになったおかげです。以前はAPI Gatewayはステージ名が末尾パスに付与されることが不可避で、フレームワークによっては都合が悪かったので、カスタムドメインを付与して対応する必要があったのですが、いつの間にか消えています。

### 所感

サーバーレスの課金形態であればデモ、試作、やってみた系のウェブサイトを何個も立ち上げっぱなしにできますね。何か決定的に変わったというわけではありませんが、ローカルマシンの環境をデフォルトで切り離せるようになったり、コマンドラインで大半を用意できるようになったり、リリースした時系列がECRでタグ管理できるのはやはり良いと思いました。

### 追記

デプロイ初回のアクセスで正常なレスポンスの代わりに`{"message":"Service Unavailable"} `というメッセージが表示される現象を確認しました。ログ見てもエラー等なく、3秒近い課金となっています。（以降は10msくらいで正常表示）。イメージの取得、コールドスタートから起因する悪影響でしょうか。。

### 参考

- https://aws.amazon.com/jp/blogs/compute/building-php-lambda-functions-with-docker-container-images/
- https://bref.sh/docs/frameworks/laravel.html
- https://laravel.com/docs/8.x/installation
- https://laravel.com/docs/8.x/sail#introduction
- https://please-sleep.cou929.nu/bash-strict-mode.html