エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

Serverless FrameworkならLambda(Node.js)をらくらく作れるよ

ちょっとしたLambda関数を作りたい時は、Node.jsやPythonエンジンのLambdaを作ることが多いのですが、実はいままで自前のシェルスクリプトでzip化した後にLambdaへアップロードしてデプロイしていました。 (今思うとなかなかに面倒な作業でした…)

しかし、設定周りはAWSコンソール上でぽちぽち操作する必要があるので、Roleやレイヤー、タイムアウト設定が大変苦痛になってきたのでServerless Frameworkを導入しました。

Serverless Frameworkのメリット

  • Lambdaや付随するサービスの設定をコードベースで管理できるようになります。
  • LambdaのRole、レイヤー、VPC、タイムアウト、メモリ等の各種設定値を予めコードに記述するだけで、デプロイ時にServeless Frameworkが更新してくれるので時短になります。
  • API Gatewayの構成も記述できるので、Lambda + API Gatewayの各種設定をコードに書いておけばすぐに使えるAPIがデプロイできます。便利!
  • APIの構成がコードになっているので第三者も相関関係が把握しやすい。

Node.jsの単純なAPIを作ってみる

開発環境

  • OS: Windows 10 Home (20H2)
$ aws --version
aws-cli/2.1.19 Python/3.7.9 Windows/10 exe/AMD64 prompt/off

$ node -v
v15.14.0

$ npm -v
7.7.6
  • Node.js, AWS CLIを予めインストールしておきます。

docs.aws.amazon.com

  • AWS CLIはアクセスキー、シークレットキー等の基本設定を完了しておきます。

docs.aws.amazon.com

下準備

  • Serveless Frameworkはnpmパッケージなので、まずは開発用の端末にてグローバルインストールします。 ※もし、Node.js自体が入っていない場合はまずはNode.js 6.x以降をインストールしておいて下さい。
$ npm install -g serverless

インストールできたか確認しましょう。

$ serverless -v
Framework Core: 2.34.0
Plugin: 4.5.3
SDK: 4.2.2
Components: 3.8.2

プロジェクトの新規作成

プロジェクトを作成したいパスで下記コマンドを実行します。

いくつか質問されますので回答していきます

$ serverless
# 新規にプロジェクトを作りたいのでYを入力
Serverless: No project detected. Do you want to create a new one? (Y/n)

# カーソルキー上下でLambdaのエンジンを選択しエンター
Serverless: What do you want to make? (Use arrow keys)
> AWS Node.js
  AWS Python
  Other

# プロジェクト名を指定してエンター
Serverless: What do you want to call this project? 

Project successfully created in 'EasyAPI' folder.
# Serverlessアカウントを作ればモニタリング等ができるようですが、無くてもデプロイは可能なので今回はnを入力(お好みでどうぞ)
You can monitor, troubleshoot, and test your new service with a free Serverless account.

Serverless: Would you like to enable this? (Y/n)

回答が終わると指定したプロジェクト名のディレクトリとファイルが生成されているはずです。

APIの構成を記述する

今回はEasyAPIという名前のNode.jsのプロジェクトを作成してみました。

プロジェクトディレクトリ内には下記のファイルが生成されています。

  • handler.js
  • serverless.yml
  • .npmignore

serverless.ymlにLambdaの各種パラメータを記述しておけば、後はSererless Frameworkがうまい具合に設定してくれます。 今回はAPI GatewayでクライアントからのGETリクエストを受け、API Gateway経由でLambda関数を実行するような構成を作ってみます。

serverless.yml

# サービス名を指定(Lambda, APIGatewayの名称の一部に使われる)
service: easyapi
frameworkVersion: '2'
provider:
  name: aws
  runtime: nodejs12.x
  lambdaHashingVersion: 20201221
  # dev, prod等の任意のステージ名を指定できます。Lambda, APIGatewayの名前に連結されます。
  stage: dev
  # Lambdaのリージョン
  region: ap-northeast-1
  # Lambdaの環境変数
  environment:
    TZ: Asia/Tokyo
  # Lambdaのメモリサイズ
  memorySize: 512
  # Lambdaのタイムアウト設定
  timeout: 10
functions:
  # ファンクション名を指定(Lambda, APIGatewayの名称の一部に使われる)
  hello:
    # Lambdaのハンドラ。handler.{****}の****にはhandler.jsの最初に呼ばれるメソッド名を指定。
    handler: handler.hello
    # Lambdaの説明文
    description: this is practice project.
    events:
      # API GatewayでHTTP APIを作成するよう指定
      - httpApi:
          # APIで受け付けるメソッドとパスを指定
          path: /hello-world
          method: get

↓他にもymlに指定できるパラメータはありますので、いろいろと触ってみると良いです。

www.serverless.com

APIのロジックを書く

デフォルトのhandler.jsにちょっとだけ手を加えました。 クライアントへ返したい値をお好みで書きましょう。

handler.js

'use strict';

module.exports.hello = async (event) => {
  const today = new Date();
  return {
    statusCode: 200,
    body: JSON.stringify(
      {
        message: `Hello, world. It's ${today.toString()}`,
      },
      null,
      2
    ),
  };
};

デプロイする

下記のコマンドを叩くことでserverless.ymlの設定に沿ったサービスが作成されます。

$ serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service easyapi.zip file to S3 (602 B)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.........
Serverless: Stack update finished...
Service Information
service: easyapi
stage: dev
region: ap-northeast-1
stack: easyapi-dev
resources: 11
api keys:
  None
endpoints:
  GET - https://************.execute-api.ap-northeast-1.amazonaws.com/hello-world
functions:
  hello: easyapi-dev-hello
layers:
  None

初回実行時は完了までに数分程度かかります。

完了後、AWSコンソールでLambda, APIGatewayのページを覗くと下記が作成されていると思います。

  • Lambda: easyapi-dev-hello
  • API Gateway(HTTP API): dev-easyapi

名称はserverless.ymlのサービス名、ファンクション名、ステージ名を参照したものになっています。 Lambdaのタイムアウトやメモリサイズといったパラメータは、serverless.ymlで指定したものが反映されています。

裏ではCloudFormationが動いている

実はServerless Frameworkの裏側ではCloudFormationのスタックが作成されています。

f:id:tansantktk:20210409200027p:plain

f:id:tansantktk:20210409200137p:plain

AWSコンソールで確認すると実際の処理が確認できますね。

APIを実行してみる

APIGatewayに$defaultステージが用意されていますので、URLをブラウザやPostman等でGETリクエストしてみましょう。

f:id:tansantktk:20210409201152p:plain

今回の例だと↓のようなURLにGETリクエストをすればレスポンスが返ってきます。

https://*************.execute-api.ap-northeast-1.amazonaws.com/hello-world

レスポンス

{
  "message": "Hello, world. It's Fri Apr 09 2021 20:10:59 GMT+0900 (Japan Standard Time)"
}

これだけでAPIが完成してしまいました! AWSコンソールでポチポチ設定する手間が無くなるのは嬉しいですね😎

ソースコード変更時のデプロイ方法は?

新規作成時と同様にserverless deployを叩くと更新されます。

API Gatewayはいらない時

APIGateway無しでLambdaだけを純粋に作りたい場合は、serverless.ymlevents.httpApiを記述しなければOK。

あとがき

今回はNode.js向けの記事でしたが、Pythonの場合も初回作成時のエンジンをPythonに指定するだけですので以降の手順はほぼ同じです。

便利なツールは積極的に使っていきたいですね!