📝

Lambda で PHP を実行しようとしたらハマった

2022/07/11に公開

Lambda で PHP を実行しようと思い、AWS 公式ブログや複数の記事を見たのですが、現時点では手順通りに動かなかったのでハマりました。

解決策として、2 つの方法を見つけたので紹介します。

結論

  1. Serverless Framework を使用する
  2. AWS Serverless Application Model (AWS SAM) を使用する

経緯

Lambda で PHP を実行する方法について検索すると、AWS 公式ブログの内容をもとにした記事がいくつかヒットします。

https://aws.amazon.com/jp/blogs/news/building-php-lambda-functions-with-docker-container-images/

https://aws.amazon.com/jp/builders-flash/202106/new-lambda-container-development-3/

https://github.com/aws-samples/php-examples-for-aws-lambda/tree/master/0.7-PHP-Lambda-functions-with-Docker-container-images

AWS 公式の内容だから手順通りに実行すればできると思っていたのですが、GitHub の手順通りに実行したところ、デプロイ後に以下のエラーが発生しました。

{
  "errorMessage": "RequestId: 0d280a9a-152b-4876-998f-193e24f2d143 Error: Runtime exited with error: exit status 126",
  "errorType": "Runtime.ExitError"
}
START RequestId: 0d280a9a-152b-4876-998f-193e24f2d143 Version: $LATEST
/lambda-entrypoint.sh: /var/runtime/bootstrap: /var/lang/bin/php^M: bad interpreter: No such file or directory
/lambda-entrypoint.sh: line 14: /var/runtime/bootstrap: Success
END RequestId: 0d280a9a-152b-4876-998f-193e24f2d143
REPORT RequestId: 0d280a9a-152b-4876-998f-193e24f2d143	Duration: 25.73 ms	Billed Duration: 26 ms	Memory Size: 128 MB	Max Memory Used: 3 MB	
RequestId: 0d280a9a-152b-4876-998f-193e24f2d143 Error: Runtime exited with error: exit status 126
Runtime.ExitError

上記のエラーの解決策が分からなかったので、AWS 公式ブログや GitHub の手順では実行がうまくいきませんでした。

参考になった記事

以下の 2 つの記事が参考になりました。

https://atuweb.net/202007a_aws-lambda-on-bref-php/

https://www.fenet.jp/aws/column/tool/997/

Serverless Framework を使用する方法と、SAM を使用する方法に分かれていたので、それぞれを検証し、自分なりに少し変更してみました。

1. Serverless Framework を使用する方法

https://atuweb.net/202007a_aws-lambda-on-bref-php/

こちらの方法では以下のツールを使用します。

AWS CLI
npm
Serverless framework
Composer
PHP

  1. Administrator ポリシーを付与した IAM ユーザーを作成

  2. Serverless framework のインストール

npm install -g serverless
  1. Serverless framework の認証情報を設定
serverless config credentials --provider aws --key <Access key ID> --secret <Secret access key> --profile php-user
  1. bref のインストール
composer require bref/bref
  1. 関数の作成
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

[1] Event-driven function を選択します。

  1. デプロイ
serverless deploy --aws-profile php-user

デプロイ後、バージニア北部リージョン (us-east-1) に app-dev-hello という Lambda 関数が作成されます。
Lambda コンソールからテスト実行すると、以下の結果が返ってきます。

"Hello world"

以上が Serverless Framework を使用する方法です。
基本的には参考サイトと同様の手順ですが、profile は適宜変更してください。

Serverless Framework で気になった点

Serverless Framework では .aws/config に記載されている認証情報を利用することができないようです。

https://stackoverflow.com/questions/66560150/aws-profile-doesnt-seem-to-be-configured-serverless-framework-error

This is a known issue with Serverless, Serverless only checks ~/.aws/credentials for the profile and not ~/.aws/config.
これはサーバーレスの既知の問題です。サーバーレスは~/.aws/credentialsはプロファイルのみをチェックし、~/.aws/configはチェックしません。

https://forum.serverless.com/t/sample-serverless-yml-for-multiple-aws-accounts-needed/1528/12

Serverless Framework のフォーラムでも議論されていたようで、一応解決策はあるようですが、正直よくわかりませんでした。

とりあえずデプロイのためだけに IAM ユーザーを作成したくなかったので、この点を SAM で解決しました。

AWS Serverless Application Model (AWS SAM) を使用する方法

こちらの方法では以下のツールを使用します。

AWS CLI
Composer
PHP
AWS SAM CLI

なお、SAM CLI で使用する profile 情報は、./aws/config に記載済みの情報を使用するので、新たに IAM ユーザーを作成する必要はありません。

config
[profile Study]
role_arn = arn:aws:iam::{Account-Id}:role/OrganizationAccountAccessRole
source_profile = default
region = ap-northeast-1
  1. S3 バケット作成
    デフォルト設定で S3 バケットを作成します。

  2. bref のインストール

composer require bref/bref
  1. 関数の作成
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

[1] Event-driven function を選択します。

  1. template.yaml を作成
    参考サイトの内容を参考に、以下のような template.yaml を作成しました。
template.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: 'test'
Transform: AWS::Serverless-2016-10-31


Resources:
  PhpFunction:
    Type: AWS::Serverless::Function

    Properties:
        FunctionName: 'PhpFunction'
        Description: test
        CodeUri: .
        Runtime: provided.al2
        Handler: index.php
        MemorySize: 1024
        Timeout: 30
        Layers:
            - arn:aws:lambda:ap-northeast-1:209497400698:layer:php-81:25
  1. sam package
    S3 バケット名や profile 名は適宜変更してください。
sam package \
--template-file template.yaml \
--output-template-file phpsl-output.yaml \
--s3-bucket my-s3-bucket-name \
--profile Study
  1. sam deploy
    profile 名やリージョンは適宜変更してください。
sam deploy \
--template-file phpsl-output.yaml \
--stack-name phpsl-service \
--capabilities CAPABILITY_IAM \
--profile Study \
--region ap-northeast-1

デプロイ後、東京リージョン (ap-northeast-1) に PhpFunction という Lambda 関数が作成されます。
Lambda コンソールからテスト実行すると、以下の結果が返ってきます。

"Hello world"

ポイント

template.yaml 内にポイントが 2 つあります。

1. Layer

Layer の部分には、Serverless Framework でデプロイした時に、Lambda コンソールから確認できる Layer の ARN を指定しました。

また、ARN 内のリージョンについても、bref のドキュメントにリージョンごとの ARN が記載されていたので、東京リージョンの ARN を指定しました。

https://bref.sh/docs/runtimes/

2. Runtime: provided.al2

参考サイト通りだと、Runtime は provided になりますが、実行すると以下のエラーが発生しました。

PHP Warning:  require(/var/task/vendor/autoload.php): Failed to open stream: No such file or directory in /var/runtime/bootstrap on line 25

Serverless Framework でデプロイした Lambda 関数との差分を確認したところ、Serverless Framework でデプロイした Lambda 関数の Runtime は provided.al2 になっていました。

AWS 公式ドキュメントを確認すると、provided.al2 は OS が Amazon Linux 2 になるようです。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html

provided では OS が Amazon Linux なので、ここが原因でエラーが発生していたようです。
Runtime: provided.al2 と指定することで、エラーは解消されました。

IAM ユーザーの新規作成が不要

Serverless Framework を使用する方法で気になる点として記載した、デプロイ用の IAM ユーザーの作成ですが、SAM を使用することで既存の profile が使用することで解決できました。

IAM ユーザーは増えるごとに情報漏洩のリスクや管理の煩雑さが増すので、できるだけ増やしたくないものです。

まとめ

今回は Lambda で PHP を実行する際にハマったので、その解決策として、2 つの方法を紹介しました。
もしかしたら、AWS 公式の手順も Runtime が原因かもしれませんが、どこを変更すればよいのかわからないので、気になる方は試してみてください。

今回の内容が参考になれば幸いです。

Discussion