こちらの記事は「コドモン Advent Calendar 2023」の 22日目の記事です🎅
こんにちは、プロダクト開発部の西銘です!
最近、業務でPHPをLambdaで動かす実装をしたのですが、環境構築がちょっと面倒だったので、
AWS CDK (以下、CDK) を使って簡単に始める方法をご紹介しようと思います!
題して、 10分で作る! PHP x Lambda 環境 by AWS CDK
の始まり〜
はじめに
前提
- 使う技術
- AWS CDK ( 2.x )
- Docker ( 24.x )
- TypeScript ( 5.x )
- Node.js( 20.x )
- PHP ( 8.2.x )
- bref ( 2.1.x )
- 事前知識
- Docker操作
- ローカル環境でDocker CLI を叩けるようにしておいてください
- AWS認証情報
~/.aws/credentials
に必要な認証情報が入ってる前提で進めます
- Docker操作
なぜ PHP x Lambda ?
弊社ではバックエンドの7割くらいはPHPで書かれています。
そのため、ビジネスロジックを別言語に分散させずに再利用してLambdaを構築したい
という開発要件を満たすために、業務でも採用されました。
なぜ AWS CDK ?
CDKは他のIaCツールと比較して以下のメリットがあります。
- プログラミング言語でAWSリソースを構築できる
- AWSリソースの構築に不慣れな方でも始めやすい
- ( この記事ではTypeScriptを採用しています )
- IDEのコード補完が豊富
- SDKの型補完や内部の実装追跡などが容易に出来るため、IDE上で実装が完結しやすい
- 必要なIAM権限を最小限で自動作成する
- AWSリソースになれない人が最初に感じる壁であるIAM権限をほぼ意識しないで構築できる
これらのメリットが私が関わった業務でも他の開発者にも受け入れられ、
実際に私以外の開発者もAWSリソース構築に関わることが容易にできたため、
この記事でも採用しました。
( もっと詳しくCDKについて知りたい!という方はぜひ 公式ガイド をご覧ください )
PHP x Lambda 環境の構築手順
1. 作業環境準備
まず最初に、CDKコマンドを使うための作業環境をDockerで用意しましょう。
$ mkdir ~/10PunPhpLambda $ touch ~/10PunPhpLambda/docker-compose.yml $ touch ~/10PunPhpLambda/Dockerfile
作成したディレクトリに作業環境を作ったら移動して中身を確かめておきましょう。
※この後の作業では基本的に ~/10PunPhpLambda
にいる前提でコマンドを叩きます
$ cd ~/10PunPhpLambda/ $ ls -1 docker-compose.yml Dockerfile
次に、中身を空で作成した docker-compose.yml
と Dockerfile
に下記を入力してください。
docker-compose.yml
version: '3' services: local-cdk: build: ./ tty: true volumes: - ./app:/usr/src/app - ~/.aws/:/root/.aws/ local-composer: image: composer command: composer require bref/bref volumes: - ./app/src:/app local-bref: image: bref/php-82-fpm-dev volumes: - ./app/src:/var/task command: ["vendor/bin/bref-local", "index.php", "$PARAM"] environment: HANDLER: index.php
Dockerfile
FROM node:20 WORKDIR /usr/src/app RUN npm -g i typescript aws-cdk
Dockerfile
は node 環境に cdk をインストールしただけのシンプルな構成です。
docker-compose.yml
は作成したcdk, composer, bref のコンテナ環境とローカル環境をVolumeで紐付けてます。
これで作業環境は準備完了です!
2. CDKプロジェクト構築
続いて、CDKプロジェクトを構築していきましょう。
まずは作成したDockerを立ち上げましょう。
$ docker compose up local-cdk -d
次に、立ち上げたDockerコンテナの中に入ります。
$ docker compose exec local-cdk bash
( 以降、コンテナ内作業は #
始まりとします )
コンテナ環境に入りましたら、下記コマンドを実行して早速CDKプロジェクトを構築しましょう
# cdk init --language=typescript
実行が完了すると、下記のような構成になっていると思います。
10PunPhpLambda/app |-- README.md |-- bin | `-- app.ts |-- cdk.json |-- jest.config.js |-- lib | `-- app-stack.ts |-- package-lock.json |-- package.json |-- test | `-- app.test.ts `-- tsconfig.json
こちらの構成について少し補足すると、注目していただきたいのは bin/app.ts
と lib/app-stack.ts
です。
lib/app-stack.ts
- CDK で構築するAWSリソースが定義されるファイルです
- ここで記述したコードが、実際にAWSリソースとして作られます
bin/app.ts
- CDK のエントリポイントのファイルです
lib/app-stack.ts
で定義されたリソースを呼び出す箇所です
lib/app-stack.ts
を修正してデプロイコマンドを叩くことで実際にAWS環境にリソースが作られます
後ほどPHPコードを書いたら実際に修正しますが、一旦置いておきます。
下記コマンドでコンテナの外に出て次の手順に進みましょう。
# exit;
3. PHPのサンプルコード準備
では、CDKプロジェクトができたので、PHPのサンプルコードを作りましょう。
appディレクトリの下にsrc ディレクトリを作り、さらにその配下に index.php を追加します。
$ mkdir app/src $ touch app/src/index.php
中身が空の index.php
に下記を入力しましょう。
index.php
<?php require __DIR__ . '/vendor/autoload.php'; return function ($event, $context) { print_r($event); print_r($context); return 'Hello ' . ($event['name'] ?? 'world'); };
index.php
を追加したら、LambdaでPHPを動かすためのライブラリである bref
を準備します。
下記コマンドを実行して composer で追加しましょう。
$ docker compose up local-composer -d
bref 追加後は src ディレクトリ配下は下記のようになっていればOKです。
$ ls -1 app/src composer.json composer.lock index.php vendor
ここまで書いたらPHPのサンプルコードは完成です!
4. ローカル実行検証
ではサンプルコードができたので、早速ローカル実行してみましょう。
ローカル実行は下記コマンドを実行するだけです。
$ docker compose up local-bref
実行すると下記結果が表示されます。
WARN[0000] The "PARAM" variable is not set. Defaulting to a blank string. [+] Running 19/1 ✔ local-bref 18 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 123.2s [+] Running 1/1 ✔ Container 10PunPhpLambda-local-bref-1 Created 0.3s Attaching to 10PunPhpLambda-local-bref-1 10PunPhpLambda-local-bref-1 | START 10PunPhpLambda-local-bref-1 | Bref\Context\Context Object 10PunPhpLambda-local-bref-1 | ( 10PunPhpLambda-local-bref-1 | [awsRequestId:Bref\Context\Context:private] => fake-aws-request-id 10PunPhpLambda-local-bref-1 | [deadlineMs:Bref\Context\Context:private] => 1701736394000 10PunPhpLambda-local-bref-1 | [invokedFunctionArn:Bref\Context\Context:private] => fake-invoked-function-arn 10PunPhpLambda-local-bref-1 | [traceId:Bref\Context\Context:private] => fake-trace-id 10PunPhpLambda-local-bref-1 | ) 10PunPhpLambda-local-bref-1 | END Duration: 4 ms Max Memory Used: 1 MB 10PunPhpLambda-local-bref-1 | 10PunPhpLambda-local-bref-1 | "Hello world" 10PunPhpLambda-local-bref-1 exited with code 0
“Hello world” の文字が見えたら成功です!
せっかくですし、Lambdaに引数を渡して実行する方法も見てみましょう。
下記コマンドを実行してください。
PARAM='{"name":"local test"}' docker compose up local-bref
上記は環境変数経由で $event 変数に入るJSONパラメータを指定して実行したコマンドです。
実行すると下記結果が表示されます。
[+] Running 1/1 ✔ Container 10PunPhpLambda-local-bref-1 Recreated 0.4s Attaching to 10PunPhpLambda-local-bref-1 10PunPhpLambda-local-bref-1 | START 10PunPhpLambda-local-bref-1 | Array 10PunPhpLambda-local-bref-1 | ( 10PunPhpLambda-local-bref-1 | [name] => local test 10PunPhpLambda-local-bref-1 | ) 10PunPhpLambda-local-bref-1 | Bref\Context\Context Object 10PunPhpLambda-local-bref-1 | ( 10PunPhpLambda-local-bref-1 | [awsRequestId:Bref\Context\Context:private] => fake-aws-request-id 10PunPhpLambda-local-bref-1 | [deadlineMs:Bref\Context\Context:private] => 1701736719000 10PunPhpLambda-local-bref-1 | [invokedFunctionArn:Bref\Context\Context:private] => fake-invoked-function-arn 10PunPhpLambda-local-bref-1 | [traceId:Bref\Context\Context:private] => fake-trace-id 10PunPhpLambda-local-bref-1 | ) 10PunPhpLambda-local-bref-1 | END Duration: 4 ms Max Memory Used: 1 MB 10PunPhpLambda-local-bref-1 | 10PunPhpLambda-local-bref-1 | "Hello local test"
print_r で標準出力した内容がログとして出ていることと、
最後に return した文字列が、 "Hello "
と引数で渡した name
の値が結合した文字列が表示されていれば成功です。
5. AWS環境デプロイ準備
ローカル実行ができたところで、実際にAWS環境にデプロイする準備をしましょう。
Lambdaをデプロイするためにまず app/lib/app-stack.ts
のコードを下記のように書き換えます。
app/lib/app-stack.ts
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class AppStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); /** * NOTE: * brefRuntimeLayerArnは、下記サイトを参考に対象のレイヤー(php82の最新)を指定する * https://runtimes.bref.sh/?region=ap-northeast-1 **/ const brefRuntimeLayerArn = "arn:aws:lambda:ap-northeast-1:534081306603:layer:php-82:52" const brefLayer = cdk.aws_lambda.LayerVersion.fromLayerVersionArn(this, "php-82", brefRuntimeLayerArn) new cdk.aws_lambda.Function(this, "10PunPhpLambda", { runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2, handler: "index.php", code: cdk.aws_lambda.Code.fromAsset("./src"), memorySize: 512, layers: [brefLayer], }); } }
書いてる内容としては、下記部分でLambdaでPHPを動かすために必要なLambdaレイヤーの設定をしています。
const brefRuntimeLayerArn = "arn:aws:lambda:ap-northeast-1:534081306603:layer:php-82:52" const brefLayer = cdk.aws_lambda.LayerVersion.fromLayerVersionArn(this, "php-82", brefRuntimeLayerArn)
brefRuntimeLayerArn
の値は bref が公式で配布しているARNパスなので、デプロイしたいPHPバージョンに合わせて変えてください。
( 私のAWSアカウントIDが漏洩しているわけではないのでご安心ください )
定義したLambdaレイヤーを設定したLambdaリソースの定義を下記で実装しています。
new cdk.aws_lambda.Function(this, "10PunPhpLambda", { runtime: cdk.aws_lambda.Runtime.PROVIDED_AL2, handler: "index.php", code: cdk.aws_lambda.Code.fromAsset("./src"), memorySize: 512, layers: [brefLayer], });
その他の詳細を説明していると10分すぎてしまうので割愛しますが、
気になる方はぜひCDK の公式ドキュメントを読んでみてください!
CDKのコードの準備ができたらデプロイの準備です。
再びコンテナの中に入りましょう。
$ docker compose exec local-cdk bash
下記コマンドを実行してデプロイコマンドを叩ける準備をしましょう。
( このコマンド実行は、1つのCDKプロジェクトで一度実行したらその後は実行不要です )
# cdk bootstrap Unable to resolve AWS account to use. It must be either configured when you define your CDK Stack, or through the environment root@************:/usr/src/app# cdk bootstrap --profile codmon-sandbox ⏳ Bootstrapping environment aws://************/ap-northeast-1... Trusted accounts for deployment: (none) Trusted accounts for lookup: (none) Using default execution policy of 'arn:aws:iam::aws:policy/AdministratorAccess'. Pass '--cloudformation-execution-policies' to customize. ✨ hotswap deployment skipped - no changes were detected (use --force to override) ✅ Environment aws://************/ap-northeast-1 bootstrapped (no changes).
実行が完了すると上記のような内容が出力されます。エラー等出てなければ成功です。
※cdkコマンド実行の際に、認証にProfileの指定が必要な場合は --profile {profile名}
オプションをつけてください
6. AWS環境デプロイ実行
準備ができたら下記コマンドを実行していざAWS環境にデプロイです!
# cdk deploy
※こちらも認証にProfileの指定が必要な場合は --profile {profile名}
オプションをつけてください
たくさんの標準出力が流れるのを見守り、途中で「 Do you wish to deploy these changes (y/n)?
」と聞かれるので「y」を入力してEnter押してください。
下記のような文字が見えたら完了です!
AppStack: creating CloudFormation changeset... ✅ AppStack ✨ Deployment time: 47.21s Stack ARN: arn:aws:cloudformation:ap-northeast-1:************:stack/AppStack/************-****-****-****-******************** ✨ Total time: 58.67s
デプロイが完了したので、AWSマネジメントコンソール画面を開き、Lambdaの関数一覧を見ると、、、
デデーーン!!
あっという間にPHP x Lambda 環境の完成です!
少し補足すると、CDKで作成したリソースは基本的に自動で命名されます。
無理やり指定した名前をつけることもできますが、基本的には自動命名を使うのがベストプラクティスです。
( ちょっとわかりづらいですよねー、、 )
ついでに画面の赤線部分を選択していくとAWSマネジメントコンソール画面上からテスト実行が出来るのでやってみましょう。
デデーーン!!
AWS環境上でも実行可能なことを確認できました!
ここまで出来た方は大成功ですね!
以上、「PHP x Lambda 環境の構築」でした。
PHP x Lambda 環境お掃除
1. CDKでリソースを削除
PHP x Lambda 構築を一通り楽しんだら最後にリソースを削除していきましょう。
まず始めに、下記コマンドを実行してください。
# cdk destroy
※こちらも認証にProfileの指定が必要な場合は --profile {profile名}
オプションをつけてください。
このコマンド実行の際に「 Are you sure you want to delete: AppStack (y/n)?
」と聞かれるので、「y」を入力してEnterしてください。
こちらが完了し、下記が出力されるとCDKで作成したリソースはほぼすべて削除されました。
Are you sure you want to delete: AppStack (y/n)? y AppStack: destroying... [1/1] ✅ AppStack: destroyed
2. CDKで削除できないリソースを削除
実は cdk destroy コマンドを実行しても消せないリソースがあるので、そちらも消していきましょう。
AWSマネジメントコンソール画面を開き、CloudWatchの画面を開いてください。
サイドバーでロググループを選択すると、先ほど作成・実行したLambdaのログが残っています。
こちらは手動で削除してあげてください。
これで後片付けは完了です。
もし、今回の作業のためだけにIAMユーザー・アクセスキーを作った方がいたらこちらも削除しておくと安全です。
おわりに
いかがでしたしょうか?
この記事は、私と同じようにPHP x Lambda 環境をサクッと試したいだけなのに色々インストールするの面倒だなぁと思ってる方や、
普段AWSやIaCに触る機会が少ない方、Lambdaを触ってみたいけどやったことない方のためになればと思い、書きました。
この記事を読んで「Lambdaを活用した実装してやるぞ!」「CDKでIaC勉強していくぞ!」といったモチベーションの糧になれば幸いです。
最後まで読んでいただきありがとうございました!
明日は弊社SREチーム期待の星、三口さんの記事です。お楽しみに!