Open12

【AWS】Serverless Frameworkメモ

noknok

はじめに

ローカル端末上でLambdaの開発を進めたく、Serverless Framework を実際に使ってみながらメモを残す。

補足

似たツールで「AWS SAM」もあるが、今回は利用を見送った。
(ローカル実行する際にDockerが必要で、仕事で使うにはDockerの有料サブスクリプションの契約が必要になるため)

Serverless Framework参考

https://aws.amazon.com/jp/serverless/getting-started/?serverless.sort-by=item.additionalFields.createdDate&serverless.sort-order=desc
https://www.serverless-dev.com/

noknok

開発環境

最低限のツール類のインストールと、IAMユーザーの作成&認証情報の設定(Profileの設定)は完了済みとする。

環境 バージョンなど 備考
MacOS Sonoma v14.5 -
AWS CLI aws-cli/2.17.22 Python/3.11.9 Darwin/23.5.0 exe/x86_64 -
Node.js v20.11.1 -
npm v10.2.4 Node.jsと一緒にインストールされたバージョンを利用
noknok

Serverless Frameworkのインストール

  • インストール(v3系をインストールしたいので、以下とした)
ターミナル
npm install -g serverless@3.39.0
  • バージョン確認
ターミナル
sls -v

# 出力例:
Framework Core: 3.39.0
Plugin: 7.2.3
SDK: 4.5.1

バージョン情報の参考元

今回インストール時に指定したバージョンは、以下から参照して選択した
https://www.npmjs.com/package/serverless?activeTab=versions

noknok

Serverlessプロジェクトを作成する

  • プロジェクト用のディレクトリ作成
ターミナル
mkdir serverless-func
cd serverless-func
  • Serverlessプロジェクト作成(今回は Node.jsのHTTP API として作成する)
    「serverless or sls」コマンドを入力すると、対話形式でプロジェクトを作成できた
ターミナル
% sls

Creating a new serverless project
? What do you want to make? (Use arrow keys)
   AWS - Node.js - Starter 
❯ AWS - Node.js - HTTP API 
  AWS - Node.js - Scheduled Task 
  AWS - Node.js - SQS Worker 
  AWS - Node.js - Express API 
  AWS - Node.js - Express API with DynamoDB 
  AWS - Python - Starter 
  AWS - Python - HTTP API 
  AWS - Python - Scheduled Task 
  AWS - Python - SQS Worker 
  AWS - Python - Flask API 
  AWS - Python - Flask API with DynamoDB 
  Other

? What do you want to call this project? serverless-lambda

✔ Project successfully created in serverless-lambda folder

? Register or Login to Serverless Framework No
? Do you want to deploy now? No

What next?
Run these commands in the project directory:

serverless deploy    Deploy changes
serverless info      View deployed endpoints and resources
serverless invoke    Invoke deployed functions
serverless --help    Discover more commands

作成されたプロジェクト構成と設定ファイル内容

デフォルトは以下のフォルダ構成と、設定ファイル内容(serverless.yml)で作成された
フォルダ構成
serverless.yml

noknok

プロジェクト内の関数を、ローカル実行する

  • ローカル実行
ターミナル
# 作成したプロジェクト配下へ移動
cd serverless-lambda

# 実行
## 書式: serverless invoke local --function <ファンクション名>
## 書式(エイリアス版): sls invoke local -f <ファンクション名>
sls invoke local -f api
  • 実行結果
    ローカル実行後、「index.js」に記載された内容が出力されたら完了
出力例
{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless v3.0! Your function executed successfully!\",\n  \"input\": \"\"\n}"
}

serverless.ymlの参考情報

https://www.serverless.com/framework/docs/providers/aws/guide/serverless.yml#aws-lambda-functions

noknok

プロジェクト内の関数を、AWS上にデプロイする

  • 「serverless.yml」の変更
    プロファイルやリージョンの指定など、以下最低限の変更を加えた
index.js
service: serverless-lambda
frameworkVersion: '3'

provider:
  name: aws
--   runtime: nodejs18.x
++   runtime: nodejs20.x
++   stage: dev
++   region: ap-northeast-1
++   profile: <認証用プロファイル名>
functions:
  api:
    handler: index.handler
    events:
      - httpApi:
          path: /
          method: get

  • デプロイの実行
ターミナル
sls deploy

デプロイされた環境の確認

AWS上に、LambdaとAPI Gatewayが一つずつ作成された
デプロイ後の名称に「dev」などのステージ名がついているが、デフォルトだとそれぞれ以下になる?

  • Lambda名: <作成時に指定したPJ名>-${sls:stage}-<ファンクション名>
  • API Gateway名: ${sls:stage}-<作成時に指定したPJ名>
    Lambda関数
    API Gateway
noknok

デプロイした関数を実行する

デプロイ時にAPIのエンドポイントが出力されるので、エンドポイントをcurlコマンドで叩いてみる

  • API呼び出し
ターミナル
curl https://<id>.execute-api.ap-northeast-1.amazonaws.com/
  • 実行結果
ターミナル
{
  "message": "Go Serverless v3.0! Your function executed successfully!",
  "input": {
    "version": "2.0",
    "routeKey": "GET /",
    "rawPath": "/",
    "rawQueryString": "",
    "headers": {
      "accept": "*/*",
      "accept-encoding": "gzip, deflate, br",
      "cache-control": "no-cache",
      〜省略〜
}

デプロイ後のレスポンス結果が、想定していた内容と異なる点の確認

元々は、以下のレスポンス内容を想定していた。
異なるレスポンス結果だったため、何か設定やパスに誤りがあったのか確認進める。
※:想定していたレスポンス内容

{
    "statusCode": 200,
    "body": "{\n  \"message\": \"Go Serverless v3.0! Your function executed successfully!\",\n  \"input\": {}\n}"
}

確認結果

Serverless Frameworkの、公式のGitHubのREADMEを参照すると、以下の記載があった。そのため上記のレスポンス結果で問題ない模様。

呼び出し
デプロイが成功すると、作成されたアプリケーションを HTTP 経由で呼び出すことができます。
curl https://xxxxxxx.execute-api.us-east-1.amazonaws.com/
次のような応答が返されるはずです (input簡潔にするためにコンテンツは削除されています)。
{
"message": "Go Serverless v2.0! Your function executed successfully!",
"input": {
...
}
}

noknok

デプロイしたリソースの削除

以下コマンドで削除可能
今回だと、デプロイされたLambdaとAPI Gatewayの両方がAWS上から削除される

ターミナル
sls remove
noknok

Lambdaのみをデプロイしたい(API Gatewayを含まない形でデプロイしたい)

上記で試した「AWS - Node.js - HTTP API 」のプロジェクトだと、デプロイ後にAPI Gatewayも同時に作成される形であった。
Lambdaのみをデプロイしたいので、別のテンプレートプロジェクトについて確認する

結論

プロジェクト作成時に、「AWS - Node.js - Starter(aws-nodeテンプレート)」を選択するとLambdaのみのデプロイが可能そう。
※上記を選択してプロジェクト作成したところ、READMEに以下記載があっため

This template demonstrates how to deploy a NodeJS function running on AWS Lambda using the traditional Serverless Framework. The deployed function does not include any event definitions as well as any kind of persistence (database).

日本語訳
このテンプレートは、従来の Serverless Framework を使用して AWS Lambda で実行される NodeJS 関数をデプロイする方法を示します。デプロイされた関数には、イベント定義や永続性 (データベース) は含まれません。
引用元: Serverless Framework AWS NodeJS Example

aws-nodeテンプレートの参考情報(v3)

https://github.com/serverless/examples/tree/v3/aws-node

noknok

「serverless.yml」による、Lambdaのロール指定

デフォルトの「serverless.yml」のままデプロイすると、IAMロールが新規作成されたものが付与される。
既存のIAMロールを指定する方法について確認する。

結論

「serverless.yml」に、以下の「iam.role」部分を追加すると既存のIAMロールを指定できた。

serverless.yml
service: serverless-starter-api
frameworkVersion: '3'

provider:
  name: aws
  runtime: nodejs20.x
++  iam:
++    role: arn:aws:iam::xxxxxxxxxxxx:role/xxxxx-role/xxxxxxxxxx <=IAMロールのARNを設定

functions:
  hello:
    handler: index.handler

ロール設定に関する参考情報

https://www.serverless.com/framework/docs/providers/aws/guide/iam#at-glance

noknok

AWS SDK(v3)の動作確認

ローカル実行した際に、AWS上のリソースアクセスも問題ないのか確認したい。
今回はS3へのアクセスについて、簡単な動作確認を行ってみる。

AWS SDK(v3)のインストール

ターミナル
# 書式: npm install @aws-sdk/client-SERVICE

npm install @aws-sdk/client-s3

index.jsの編集

以下の公式ドキュメントより、S3のバケットリストを取得するコードを試す
Amazon S3 examples using SDK for JavaScript (v3)

エディター
// The following code example shows how to use ListBuckets.
const { ListBucketsCommand, S3Client } = require('@aws-sdk/client-s3');

const client = new S3Client({});

module.exports.handler = async (event) => {
  const command = new ListBucketsCommand({});

  try {
    const { Owner, Buckets } = await client.send(command);
    console.log(
      `${Owner.DisplayName} owns ${Buckets.length} bucket${
        Buckets.length === 1 ? "" : "s"
      }:`,
    );
    console.log(`${Buckets.map((b) => `${b.Name}`).join("\n")}`);
  } catch (err) {
    console.error(err);
  }
};

ローカル実行

認証情報に問題あるせいかWARNINGが出たものの、正常にバケット一覧が出力されることを確認できた。

ターミナル
# 書式: sls invoke local -f <ファンクション名>

sls invoke local -f api
出力結果例
@aws-sdk/credential-provider-node - defaultProvider::fromEnv WARNING:
    Multiple credential sources detected: 
    Both AWS_PROFILE and the pair AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY static credentials are set.
    This SDK will proceed with the AWS_PROFILE value.
    
    However, a future version may change this behavior to prefer the ENV static credentials.
    Please ensure that your environment only sets either the AWS_PROFILE or the
    AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY pair.

<AWSアカウント名> owns 7 buckets:
 • <バケット名1><バケット名2><バケット名3><バケット名4><バケット名5><バケット名6><バケット名7>

参考情報

https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/welcome.html
https://docs.aws.amazon.com/ja_jp/sdk-for-javascript/v3/developer-guide/migrate-whats-different.html
https://dev.classmethod.jp/articles/aws-sdk-for-javascript-v2-v3-diff/