LoginSignup
2
1

AWS Lambdaで手軽にNode.jsコンテナ稼働

Last updated at Posted at 2023-12-11

Node.jsなLambdaを、お手軽にコンテナ化して運用したい。

分かりやすいメリットとしては、以下のようなものがある。

サンプルアプリ

環境変数 NAME を出力するLambdaである「my-app」を例として話を進めていく(あくまで例なので、処理自体に深い意味は無い)。

index.js

環境変数を読み込むために、外部ライブラリとして env-var を使用している。

const env = require('env-var');
const NAME = env.get('NAME').required().asString();
exports.handler = async (event) => {
    console.debug('Say hello to CloudWatch Logs');
    return `It's me, ${NAME}!`;
};

package.json

おそらくこんな感じ。
env-var をインストールしたからには package-lock.json も生成されているのであろう。

{
  "name": "my-app",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "dependencies": {
    "env-var": "^7.4.1"
  }
}

コンテナ化

公式の導入手順と、以下の情報を、合わせて眺めていくと分かり易いはず。

Dockerfile

Dockerfileを作成する。
AWSベースイメージを土台として、手元の構成を再現すればよい。

FROM public.ecr.aws/lambda/nodejs:18

COPY index.js ./
COPY package.json ./
COPY package-lock.json ./

RUN npm clean-install

CMD ["index.handler"]

Amazon ECR

イメージの保存先であるECRリポジトリを、Lambdaと同リージョンにて作成する。
Lambdaサービスがイメージを読み込むことになるため、その動作を許可しておくこと。

以下はCloudFormationでの設定例。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::LanguageExtensions
#
# ...略...
#
Resources:
  EcrRepository:
    Type: AWS::ECR::Repository
    Properties:
      RepositoryName: my-app
      #
      # ...略...
      #
      RepositoryPolicyText:
        Fn::ToJsonString:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service: lambda.amazonaws.com
              Action:
                - ecr:BatchGetImage
                - ecr:GetDownloadUrlForLayer

イメージの作成とプッシュ

イメージを作成してECRリポジトリにプッシュする。

以下はコマンド例。

docker build . --tag my-app:local
aws ecr get-login-password | docker login --username AWS --password-stdin 111122223333.dkr.ecr.ap-northeast-1.amazonaws.com
docker tag my-app:local 111122223333.dkr.ecr.ap-northeast-1.amazonaws.com/my-app:v1.0.0
docker push 111122223333.dkr.ecr.ap-northeast-1.amazonaws.com/my-app:v1.0.0

Lambdaでのイメージ使用

Lambdaの設定において、プッシュしたイメージを指定する。

以下はCloudFormationでの設定例。

AWSTemplateFormatVersion: '2010-09-09'
#
# ...略...
#
Resources:
  LambdaFunc:
    Type: AWS::Lambda::Function
    Properties:
      PackageType: Image
      Code:
        ImageUri: 111122223333.dkr.ecr.ap-northeast-1.amazonaws.com/my-app:v1.0.0
      #
      # ...略...
      #
      Environment:
        Variables:
          NAME: Red

以上

このように、AWSベースイメージを元に簡単にコンテナ運用することができる。

TypeScript組み込み例

TypeScriptにした場合でも基本は変わらず、トランスパイルしたものをイメージに組み込む、という処理をそれっぽく行えばよい。

以下は組み込み例。

package.json (TypeScript)

esbuild した成果物を dist ディレクトリに出力するような build を設定する。

{
  "name": "my-app",
  "version": "1.0.0",
  "private": true,
  "main": "index.js",
  "dependencies": {
    "env-var": "^7.4.1"
  },
  "devDependencies": {
    "esbuild": "^0.19.8"
  },
  "scripts": {
    "build": "rm -rf dist && esbuild index.ts --bundle --minify --sourcemap --platform=node --target=node18 --outdir=dist"
  }
}

Dockerfile (TypeScript)

ベースイメージにて用意されている環境変数 LAMBDA_TASK_ROOT (ベースイメージの WORKDIR でもある)を利用して、ビルド出力物である dist ディレクトリの中身だけをイメージに組み込む。

FROM public.ecr.aws/lambda/nodejs:18 AS builder
COPY index.ts ./
COPY package.json ./
COPY package-lock.json ./
COPY tsconfig.json ./
RUN npm clean-install
RUN npm run build

FROM public.ecr.aws/lambda/nodejs:18
COPY --from=builder ${LAMBDA_TASK_ROOT}/dist/* ./
CMD ["index.handler"]

その他メモ

  • Lambdaサービスのコンテナ起動スピードは良好
  • LambdaサービスからのECRリポジトリコンテナイメージダウンロード料金は無料
  • コンテナ以外のデプロイパッケージ(CFnで言うところの PackageType)で稼働していた既存Lambda関数リソースを、そのままコンテナ利用に切り替えることはできない
    • デプロイパッケージを途中で切り替えることはできない、というLambdaサービス仕様のため。大人しく新リソースを作成するんだ……
2
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
2
1