AWS Lambda用のTypeScriptコードをTerraformでデプロイする備忘録

# はじめに
TypeScriptをよく使うので、TypeScriptでLambdaを書きたいなというのと、Terraformを使ってみたいなということで書きました。

VSCodeのDev Containersを用いてコンテナで開発する前提で書いています。
ECRは料金がかかるため、zipファイルでデプロイする方法をとっています。

# Githubリポジトリ
下記にサンプルコードを置いています。

https://github.com/tanakalucky/typescript-lambda-sample

# フォルダ構成
最終的なフォルダ構成は以下になります。
```
.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── package-lock.json
├── package.json
├── src
│   └── index.ts
├── terraform
│   ├── iam.tf
│   ├── lambda.tf
│   ├── main.tf
│   ├── terraform.tfvars
│   └── variables.tf
└── tsconfig.json
```


# Docker関連ファイル作成
Dockerを使用するためのファイルを追加します。

```json:devcontainer.json
{
  "service": "typescript-lambda-sample",
  "dockerComposeFile": "../docker-compose.yml",
  "workspaceFolder": "/typescript-lambda-sample",
}
```

```Dockerfile:Dockerfile
# Lambdaが対応しているバージョンを使用する
FROM node:20-slim

ARG TERRAFORM_VERSION=1.8.0

# AWS CLIインストールに必要なものをインストール
RUN apt-get update && apt-get install -y curl unzip bash jq groff less

# AWS CLIバージョン2のインストール
RUN curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && \
    unzip awscliv2.zip && \
    ./aws/install && \
    rm -rf awscliv2.zip ./aws

# Terraformのインストール
RUN curl -O https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip && \
    unzip terraform_${TERRAFORM_VERSION}_linux_amd64.zip -d /usr/bin && \
    rm terraform_${TERRAFORM_VERSION}_linux_amd64.zip
```

```yml:docker-compose.yml
services:
  typescript-lambda-sample:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/typescript-lambda-sample
    tty: true
```


# TypeScriptプロジェクト作成
コマンドを実行して、tsconfig.jsonやpackage.jsonなどを生成します。
```shell
npm init -y

npm i typescript @types/node ts-node

npx tsc --init --rootDir src --outDir dist \
--esModuleInterop --resolveJsonModule --lib es6,dom --module commonjs
```



ビルドコマンドをpackage.jsonに追加します。
```json:package.json
{
  ...
  "scripts": {
    "build": "tsc -p .",
  },
  ...
}

```

適宜Lambdaの開発がしやすくなるライブラリをインストールします。
ライブラリは他にもあるようなので、必要に応じて追加してください。
```
npm i @types/aws-lambda
```

# ソースコード作成
サンプルコードを作成します。
```ts:index.ts
import { APIGatewayProxyResult } from 'aws-lambda';

export const handler = async (): Promise<APIGatewayProxyResult> => {
  return {
    statusCode: 200,
    body: JSON.stringify({
      message: 'success',
    }),
  };
};

```

# Terraformファイル作成

下記を参考にファイルを作成します。一部違いがある箇所を記載します。

https://qiita.com/curlneko/items/15607f8ef319cc97a75e

### lambda.tf
記事と異なるのはruntimeやhandlerの記載になります。
```terraform: lambda.tf
data "archive_file" "typescript_lambda_sample" {
  type        = "zip"
  source_dir  = "../dist"
  output_path = "../typescript_lambda_sample.zip"
}

resource "aws_lambda_function" "typescript_lambda_sample" {
  function_name    = "typescript_lambda_sample"
  filename         = data.archive_file.typescript_lambda_sample.output_path
  source_code_hash = data.archive_file.typescript_lambda_sample.output_base64sha256
  runtime          = "nodejs20.x"
  role             = aws_iam_role.lambda_iam_role.arn
  handler          = "index.handler"
}
```

### variable.tf
記事ではデフォルト値を設定していましたが、terraform.tfvarsで設定した値が入ってくるので、特に設定していません。
```terraform:variable.tf
variable "region" {
  type = string
}

variable "access_key" {
  type = string
}

variable "secret_key" {
  type = string
}
```

### terraform.tfvars
このファイルで記載した値がvariable.tfで定義した変数に設定されます。



```terraform:terraform.tfvars
region = "ap-xxxxxxxx-1"
access_key = "XXXXXX"
secret_key = "XXXXXX"
```

:::note alert
実際はAWSから取得したアクセスキーなどを記載するため、terraform.tfvarsはgithubなどにあげないようにしてください。
:::

# デプロイ
プロジェクトルートで以下のコマンドを実行し、ビルドします。
```
npm run build
```

terraformフォルダ配下で以下のコマンドを実行します。
初回以降は必要なくなるはずです。
```shell
terraform init
```

以下のコマンドを実行し、何が作成されるかを確認します。
```shell
terraform plan
```

上記で特に問題なければ以下を実行します。
```shell
terraform apply
```
実行するかを聞かれるため、yesと入力して実行します。
```shell
Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes
```

これでAWS上にLambdaが生成されます！

デプロイしたLambdaを使う予定がないなら以下で削除も簡単にできます。
```
terraform destroy
```


# 終わりに
TerraformはCloudFormationと比べて、情報が探しやすかったように思いました。
AWSに限らず使えると思うので、これから積極的に使っていこうと思います。



# 参考記事
https://typescript-jp.gitbook.io/deep-dive/nodejs

https://qiita.com/dingtianhongjie/items/366390eefe0caa1aaaf9