1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

前置き

仕事でAWS LambdaとTypeScriptで開発をすることになった
ただAWSの知識はそんなに持ってないし開発環境どうすればいいんだ…
と悩んでいたところに以下の記事を発見。

更に公式でDockerイメージが提供されており使用方法の説明もあった。

じゃあ両方うまいこと合わせたらいい感じの環境を作れるか?

環境構築

最終的にプロジェクトの構成は以下のようにした。
/src配下のtsをビルドして/dist配下に生成し
/distをdocker上にマウントして動作させるという構成。

/project_dir
 ┣ /src
 ┃  ┗ index.ts
 ┣ /dist
 ┃  ┣ index.js
 ┃  ┗ index.js.map
 ┣ /node_module
 ┣ Dockerfile
 ┣ docker-compose.yaml
 ┣ package.json
 ┣ package-lock.json
 ┣ lambda-exec.sh
 ┗ docker-command.sh

nodeインストール

作業環境は WSL 上の ubuntu を利用することとして
デフォルトだと node のバージョンが低いので nvm を導入

nvm 入れたらとりあえず node が最新版になったので
AWS lambda 公式マニュアルに従い node プロジェクトを作成する。

$ mkdir ~/project_dir
$ cd ~/project_dir
$ npm init
$ npm install -D @types/aws-lambda esbuild

packege.json にビルド用コマンドを追記
マニュアルから少し変更し index.tssrc/index.ts と指定

package.json
  "scripts": {
    "build": "esbuild src/index.ts --bundle --minify --sourcemap --platform=node --target=es2020 --outfile=dist/index.js"
  }

TypeScriptコード記述

/srcディレクトリを作成し、その下にコードを記述。
このコードはマニュアルをそのまま利用。

$ mkdir src
$ touch src/index.ts
index.ts
import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';

export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
    console.log(`Event: ${JSON.stringify(event, null, 2)}`);
    console.log(`Context: ${JSON.stringify(context, null, 2)}`);
    return {
        statusCode: 200,
        body: JSON.stringify({
            message: 'hello world',
        }),
    };
};

index.tsが作成出来たらとりあえずビルド。
ビルドすると /dist 配下に index.js が作成される。

$ pwd
/project_dir
$ npm run build

Docker準備

Dockerfiledocker-compose.yaml を作る。
冒頭の記事を参考にしてなんかいい感じに調整。
もっといい書き方とか不要な記述はあるかもしれない

$ pwd
/project_dir
$ touch Dockerfile
$ touch docker-compose.yaml
Dockerfile
FROM public.ecr.aws/lambda/nodejs:22 as builder
WORKDIR ${LAMBDA_TASK_ROOT}
COPY package.json ./
RUN npm install
docker-compose.yaml
services:
  lambda-local:
    build:
      context: .
      dockerfile: Dockerfile
    environment:
      LAMBDA_TASK_ROOT: /var/task
    command: [ "index.handler" ]
    restart: always
    volumes:
      - ./dist:/var/task/
    ports:
      - "9000:8080"
    logging:
      options:
        max-size: "5m"
        max-file: "10"

ファイルを作ったらとりあえずビルドして起動。

$ docker compose build --no-cache
$ docker compose up -d

動作確認

Dockerをビルドして問題なく起動できたら
マニュアルの curl コマンドを使って動くか試す

$ curl "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'

以下のようなレスポンスが返ってくれば成功

{"statusCode":200,"body":"{\"message\":\"hello world\"}"}

変更を反映する

これで環境ができたのでコードの編集を行っていく。
変更した場合はまた index.ts をビルドして dockerを再起動する必要がある。

$ pwd
/project_dir
$ npm run build
$ docker compose restart lambda-local

nodeなら自動ビルドもあるけど一旦それは置いといて・・・

シェルスクリプトを作っておく

書いた関数の動作確認に長い curl コマンド覚えられないし
変更を反映させるために毎回コマンドを実行するのはちょっとめんどくさいので
簡単なシェルスクリプトを作っておいてちょっと楽をしたい。

lambda-exec.sh
#!/bin/bash
curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{}'
docker-command.sh
#!/bin/bash
cd ~/project_dir
param=$1
if [ -z "$param" ]; then
    echo option is "up" "restart" "down" "rebuild"
elif [ $param = "up" ]; then
    npm run build
    docker compose up -d
elif [ $param = "restart" ]; then
    npm run build
    docker compose restart lambda-local
elif [ $param = "down" ]; then
    docker compose down
elif [ $param = "rebuild" ]; then
    docker compose build --no-cache
fi

これでお試しできる環境が一通り揃ったと思う。

番外編:POSTでパラメータを渡す

ちょっと詰まったので備忘録として

POSTでパラメータを渡したとき、lambda関数上でどう受け取るか
マニュアルの curl コマンドだと上手く表示できなかったので色々試した

まずはindex.tsを編集してパラメータを表示するように修正

index.ts
import { Context, APIGatewayProxyResult, APIGatewayEvent } from 'aws-lambda';

export const handler = async (event: APIGatewayEvent, context: Context): Promise<APIGatewayProxyResult> => {
    const requestBody = event.body ? JSON.parse(event.body) : null;
    console.log('Request Body:', requestBody);

    const response: APIGatewayProxyResult = {
        statusCode: 200,
        body: JSON.stringify({
            message: 'Received the request body',
            data: requestBody,
        }),
    };

    return response;
};

変更後、動作を確認するために以下のcurlコマンドでうまく行った。
APIGatewayEvent という型を使った場合、大元をbodyとする必要があった。

// 実行
$ curl -X POST "http://localhost:9000/2015-03-31/functions/function/invocations" -d '{"body": "{\"payload\":\"hello world!\"}"}'

// レスポンス
{"statusCode":200,"body":"{\"message\":\"Received the request body\",\"data\":{\"payload\":\"hello world! APItester\"}}"}

上手くできたらlambda-exec.shを更新しておく。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?