それサーバレスでできません? 〜③Lambdaを使ったAPIのサーバレス化(Node.js)
本章のゴール
EC2上でホストされているAPI(Node.js)をLambdaとAPI Gatewayを使った構築に移行する。
使用するサービスは下記
①Lambda
②API Gateway
(以下CI/CDパイプラインに利用)
③Code Commit
④Code Build
⑤CloudFormation
⑥Code Pipeline
移行によるメリット
そもそもの話ですが、S3でのサイト構築同様、サーバーレス構成にすることで金銭面と運用面でメリットが得られます。具体的な内容は下記になります。
金銭面
課金形態が使用時間からリソースの使用量に変更されます。リクエスト数が少ない場合はLambdaの方が、膨大なリクエストを処理する必要がある場合は、EC2の方がお得になります。ただ、Lambdaでは冗長性が標準で備わっているため、サービス利用料以外についても考慮が必要となります。
・課金形態
Lambdaでの運用:利用処理負荷あたりの従量課金
EC2:利用時間あたりの従量課金
一定程度のアクセスであればLambdaの方がサービス利用料が低いですが、大量のトラフィックを扱う場合はEC2の方がサービス利用料が低くなります。尚、どちらの構成とするかについては、運用にかかる人件費を含めて検討する必要があります(運用面でのポイントは後続の内容を参照)。
運用面
Lambdaは非機能要件の観点で以下が保証されています。
インフラの管理が不要(OSの更新、使用量に合わせたスケールイン・スケールアウト など)
AZ全体での耐障害性を保証
自動スケーリング
他AWSサービスとの連携が容易
リクエスト数などの都合により、サービス利用料自体がEC2の方が安い場合でも、運用の際に必要な人的リソースを加味することで、総合的な費用が安くなることがあります。
構築手順
1. CICDパイプライン、Lambda関数の作成
Node.jsのAPIについては、パイプラインのテンプレートを使用することができます。このテンプレートを使用して叩き台となるパイプラインを作成します。
1-1. アプリケーションの作成
AWSマネジメントコンソールから、Lambdaへ移動し、アプリケーションの新規作成を行います。
「一から作成」を選択します。
各設定を行い、パイプラインを作成します(設定は以下参照)。
・アプリ名:(任意の名称)
・ランタイム:Node.js 10.x
・ソース管理サービス:Code Commit
1-2. 1-1で「作成」押下後、CICDパイプラインに関連するリソースが作成されたことを確認できます。
※下図赤枠内のリソースが作成される。
2. API Gatewayの追加
手順1でCICDパイプラインとLambda関数は作成されたので、API Gatewayを追加します。
2-1. ローカル環境へのリポジトリのクローン
手順1で作成されたリソースの各設定を変更するため、ローカル環境へリポジトリ(Code Commit)をクローンします。
Code Commitのリポジトリ一覧上、作成したアプリと同名のリポジトリのURLをコピーします。
ローカル環境(≒お使いのデスクトップ)で、作業を行うフォルダを作成し、作成したフォルダにリポジトリをクローンします。
#"https://~" は上図でコピーしたURLを記載
$ git clone https://~
#クローンされたフォルダ(リポジトリ内のコード一式)へ移動
#"sample-lambda-nodejs"はリポジトリ名
cd sample-lambda-nodejs
以下内容のディレクトリ構造がダウンロードされたことを確認できます。
- __tests__ -> ビルドの際に実行されるテストコード
- src -> APIとして実行されのソースコード
.DS_Store
.gitignore
buildspec.yml -> ビルド設定
LICENSE
package.json
README.md
template.yml -> デプロイ設定(CloudFormataionのテンプレート)
2-2. デプロイ設定(template.yml)の変更
手順1で作成したLambda関数を外部から実行できるよう、API Gatewayを追加します。
※template.ymlにAPI Gatewayの設定(下記コードの "Events"以下)を追記する
AWSTemplateFormatVersion: 2010-09-09
Description: >-
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
PermissionsBoundary: !Sub 'arn:${AWS::Partition}:iam::${AWS::AccountId}:policy/${AppId}-${AWS::Region}-PermissionsBoundary'
Parameters:
AppId:
Type: String
Resources:
helloFromLambdaFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: ./
Handler: src/handlers/hello-from-lambda.helloFromLambdaHandler
Runtime: nodejs10.x
MemorySize: 128
Timeout: 60
Description: A Lambda function that returns a static string.
Policies:
- AWSLambdaBasicExecutionRole
#Events配下にAPI Gatewayの設定として以下内容を追加する
Events:
HelloWorld:
Type: Api
Properties:
Path: /get
Method: get
2-3. ビルド設定(buildspec.yml)の変更
手順1で作成されてビルド設定には、初期設定向けのテストコードがあるため、コメントアウトします。
※テストコードが必要な場合は適宜アレンジください。
version: 0.2
phases:
install:
commands:
# Install all dependencies (including dependencies for running tests)
- npm install
#テスト用の設定を一度コメントアウトする
#pre_build:
#commands:
# Discover and run unit tests in the '__tests__' directory
#- npm run test
# Remove all unit tests to reduce the size of the package that will be ultimately uploaded to Lambda
#- rm -rf ./__tests__
# Remove all dependencies not needed for the Lambda deployment package (the packages from devDependencies in package.json)
#- npm prune --production
build:
commands:
# Use AWS SAM to package the application by using AWS CloudFormation
- aws cloudformation package --template template.yml --s3-bucket $S3_BUCKET --output-template template-export.yml
artifacts:
type: zip
files:
- template-export.yml
2-4. APIコード(~/src/handlers/hello-from-lambda.js)の変更
API Gatewayと連携するために、特定のヘッダー情報が必要になります。
レスポンスとしてこのヘッダー情報が返されるよう、APIの処理として使用されるコードを編集します。
/**
* A Lambda function that returns a string.
*/
exports.helloFromLambdaHandler = async () => {
// If you change this message, you will need to adjust tests in hello-from-lambda.test.js
const message = 'Hello from Lambda!';
// All log statements are written to CloudWatch by default. For more information, see
// https://docs.aws.amazon.com/lambda/latest/dg/nodejs-prog-model-logging.html
console.log(message);
//return message;
//responseの内容として特定のヘッダーを返すよう変更
var response = {
"statusCode": 200,
"headers": {
"my_header": "my_value"
},
"body": message,
"isBase64Encoded": false
};
return response;
};
2-5. 変更内容の反映
リポジトリへ、2-2~2-4で変更した内容を反映します。
$ git add .
$ git commit -m 'Initial Commit'
$ git push
リポジトリの変更を検知してCode Piplineがビルドとデプロイを自動実行します。
デプロイ後API Gatewayで発行されたURLへWebブラウザでアクセスし、レスポンスが返されることを確認できれば設定は完了となります。