【Terraform】TerraformでもLambdaはTypeScriptで書きたい
目次
こんにちは、クラウドビルダーズのきむです。
TerraformでもLambdaをTypeScriptで書きたい!!!!!
前回のブログではAWS CDKでデプロイするLambdaをTypeScriptで実装する方法を紹介しました。
業務ではTerrafromも使うことが多いのでTerraformでもTypeScriptでLambdaを実装する方法を紹介します。
やること
やることは前回のブログとほどんと変わりません。AWS CDKを使うのがTerrafromに変わった程度です。
- LambdaをTypeScriptで記述する
- node_modulesをLambda Layerに含める
- 自作関数もLambdaLayerに含める
- Terraformでデプロイ
フォルダ構成
最終的なフォルダ構成は下記のとおりです。
.
├── README.md
├── deploy.sh
├── dist
├── esbuild.ts
├── lambda
│ ├── lambda-layer
│ │ ├── index.ts
│ │ ├── now
│ │ │ └── index.ts
│ │ ├── package.json
│ │ └── tsconfig.json
│ ├── package-lock.json
│ ├── package.json
│ └── src
│ └── index.ts
├── main.tf
├── node_modules
├── output
├── package-lock.json
├── package.json
├── run.sh
├── terraform.tfstate
├── terraform.tfstate.backup
├── tsconfig.json
└── variables.tf
esbuildの実装
LambdaやLambda Layerの内容やフォルダ構成は前回から変更無しです。tsconfig.jsonについても変更はありません。
Lambda Layerは前回同様tscによるbuildを行いますが、Lamdaにデプロイするコードはesbuildによるビルドを行います。
AWS CDKのNodejsFunctionコンストラクタではesbuildでのビルドを行なっているのでTerraformでも同様の挙動にします。
esbuildをinstallしましょう。
npm install -D esbuild
次にビルドスクリプトを作成します。
import * as esbuild from 'esbuild';
const config: esbuild.BuildOptions = {
entryPoints: ['lambda/src/index.ts'],
bundle: true,
minify: false,
sourcemap: false,
platform: 'node',
target: ['es2020'],
format: 'esm',
outfile: 'dist/src/index.mjs',
external: ['*'],
};
esbuild.build(config);
作成したesbuild.tsをts-nodeで実行することで指定したtsファイルがmjsファイルにコンパイルされます。
AWS CDKでの実装と同様にformat: ‘esm’,external: [‘*’]でコンパイル後の可読性の向上とLayerに含まれるライブラリを除外することでパッケージサイズの縮小を行なっています。
minify: trueとすることでさらにパッケージのサイズは縮小されますが、コンパイル後のコードが短縮された形式になります。
import{now as r}from"lambda-layer";var c=async(e,n)=>r();export{c as handler};
今回はLambda上でもわかりやすい形式にしたいのでminify: falseとしています。
作成したビルドスクリプトを実行するpackage.jsonのスクリプトを追加します。
{
"name": "my-terraform",
"version": "1.0.0",
"scripts": {
"build": "tsc",
"esbuild": "ts-node esbuild.ts"
},
"devDependencies": {
"@types/aws-lambda": "^8.10.143",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.9",
"jest": "^29.7.0",
"ts-jest": "^29.1.5",
"ts-node": "^10.9.2",
"typescript": "~5.5.3",
"esbuild": "^0.23.1"
},
"dependencies": {
"dayjs": "^1.11.12"
}
}
Terraformの実装
それではTerraformを実装していきます。記載量も少ないのでmain.tfに全て記載しています。
terraform {
required_version = "1.8.4"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
data "aws_iam_policy_document" "lambda" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}
resource "aws_iam_role" "lambda" {
name = "lambda-role"
assume_role_policy = data.aws_iam_policy_document.lambda.json
}
resource "aws_iam_role_policy_attachment" "lambda" {
role = aws_iam_role.lambda.name
policy_arn = "arn:aws:iam::aws:policy/AWSLambdaExecute"
}
data "archive_file" "layer" {
type = "zip"
source_dir = "${path.module}/dist"
output_path = "${path.module}/output/layer.zip"
excludes = ["src"]
}
resource "aws_lambda_layer_version" "lambda" {
layer_name = "common-layer"
filename = data.archive_file.layer.output_path
source_code_hash = data.archive_file.layer.output_base64sha256
compatible_runtimes = ["nodejs20.x"]
}
data "archive_file" "lambda" {
type = "zip"
source_dir = "${path.module}/dist/src"
output_path = "${path.module}/output/lambda.zip"
}
resource "aws_lambda_function" "lambda" {
function_name = "test-lambda"
filename = data.archive_file.lambda.output_path
runtime = "nodejs20.x"
handler = "index.handler"
role = aws_iam_role.lambda.arn
source_code_hash = data.archive_file.lambda.output_base64sha256
memory_size = 128
timeout = 3
layers = [aws_lambda_layer_version.lambda.arn]
}
デプロイ
それではデプロイしてみましょう。
今回も一連の処理をdeploy.shに定義しています。
前回のものと比較するとnpm run esbuildが追加されたのとcdk deployがterraform applyに変更されています。
#!/bin/bash
set -e
rm -rf dist output
mkdir -p dist/nodejs/node_modules
cp lambda/package.json lambda/package-lock.json dist/nodejs/
pushd dist/nodejs
npm ci
popd
pushd lambda/lambda-layer
npm run build
popd
npm run esbuild # esbuildを実行
terraform apply -auto-approve
実行権限を付与してdeploy.shを実行すればデプロイ完了です。
さいごに
AWS CDKとの違いはesbuildによるビルドスクリプトの実装をする点ですが、内容も難しいものではないためサクッとできてしまいます。ぜひ活用してみてください。