こんにちは!
本記事は、「Serverless Framework での AWS 構築を通じてサーバーレスの価値を体験」を目的に、スタートガイドを公開します。
これからサーバーレスをはじめたい、Amplify の自動開発をやめて自前でのインフラ構築に取り組みたい方は必見です。
AWS Lambda をはじめとした、AWS サーバーレス製品のデプロイ・モニタリング・CI.CD に対応するオールインワン開発フレームワークです。
Serverless Framework は複数の AWS 以外のクラウドベンダー(GCP 等々)にも対応しているため、マルチクラウドの環境づくりにも最適です。
では、早速 Serverless Framework でサーバーレスを体験してみましょう!
Serverless Framework の最もわかりやすい価値として、「API 構築の自動化」が挙げられます。
まずはサーバーレスで構成された REST API をすばやくデプロイ・起動・実行してみましょう。
まずはデプロイする場所(AWS アカウント)が必要になります。
サーバーレス開発は、アプリケーションを可能な限り迅速に Web に移行するためにクラウドベンダー(LaaS)に依存しており、最も広く使用されているベンダーが AWS(Amazon Web Service)です。
AWS アカウントを既にお持ちの場合は、この項目はスキップしてください。
お持ちでない場合は、AWSアカウント作成ページに移動しアカウントを作成してください。
Serverless Framework のインストールはとても簡単です。
NPM モジュールであるため、Node と NPM さえあれば、インストールすることができます。
以下のコマンドで Serverless Framework をグローバルインストールしてください。
$ npm install -g serverless
開始するには空のフォルダーにて、CLI で次のコマンドを実行するだけです。
$ serverless
たったこれだけでプロセスが開始され、スターターキットとしてテンプレートの選択も可能です。これは新しいサービスを実行するのに役立ちます。
最初のオプションは、サービスのベースにするテンプレートタイプの設定です。(初めに設定する必要はありますが、後ほど変更することもできます)
サーバーレスダッシュボードは、Serverless Framework が提供するツールであり、AWS への接続の管理を容易にし、サービスの構成データ、モニタリング機能、Lambda 関数のログを読み取る機能などを提供してくれます。
ダッシュボードは、無料で使用できます。
ダッシュボードを使用すると、実行するデプロイで AWS アカウントへの接続を非常に簡単に管理できます。
Y を選択して(または Enter キーを押して)、ダッシュボードを設定します。これにより、ブラウザにウィンドウが開きます。
下部にある[Register]をクリックして、GiHub、Google、または自分のメールアドレスとパスワードを使用してアカウントを作成しましょう。
[Register]をクリックし、ユーザー名の入力を求められたら、先に進み、数字と小文字のみを含むユーザー名を入力します。
アカウントが作成されると、CLI は次の2つのいずれかを実行します。
「AWS Access Role」を選択すると、別のブラウザウィンドウが開きます。(そうでない場合は、CLI がウィンドウを手動で開くために使用するリンクを提供します)ダッシュボードアカウント内でプロバイダを設定します。
次のステップで、必ず「Simple」オプションを選択し、「Connect AWS provider」(AWS プロバイダーに接続)をクリックしてください。
これにより、「Quick create stack」(クイック作成スタック)というタイトルの AWS アカウントのページが開きます。
ここでは変更する必要はありませんので、ページの下部にある確認ボックスをオンにするために下にスクロールして、[Create Stack](スタックの作成)をクリックします。
この時点で、AWS が必要なものを作成するまで数秒待つ必要があります。ステータスが「CREATE_COMPLETE」になると、左側のリストの更新ボタンをクリックできるようになります。
完了したらタブを閉じて、ダッシュボードのプロバイダ作成ページに戻ることができます。
ダッシュボードは、プロバイダが正常に作成されたことを自動的に検出し、CLI も同様に検出します。
展開に関する質問に「Y」と返信し、新しいサービスが展開されるまで数分待ちましょう!
デバイスにすでに AWS 認証情報があり、デプロイするかどうかを尋ねられたときに「No」を選択した場合でも、プロバイダーをセットアップする必要があります。
ありがたいことに、セットアップはとても簡単で、app.serverless.com にアクセスして、上記で説明したようにアカウントを登録するだけです。
次に、アプリのリストページに移動したら、左側の[org]をクリックし、[providers]タブを選択して、最後に[add]を選択します。プロバイダの追加は上記とまったく同じであり、完了したら、CLI でサービスに戻ることができます。
また、必ず cd で services フォルダに移動してから「serverlessdeploy」を実行してください。
ダッシュボードアカウントでプロバイダを設定したくない場合は、自分のデバイスでローカルの認証情報の設定を使用できます。
これには、適切な権限を持つユーザーを作成し、デバイスに認証情報を追加することが含まれます。
デプロイが成功すると、ダッシュボードまたは CLI のいずれかで、呼び出すことができる HTTP エンドポイントがあることがわかります。また、お気に入りの IDE またはテキストエディタで作成したばかりのサービスを開き、serverless.yml のコンテンツを確認すると、サービスのほとんどすべてを制御することができます。
持っている関数があるセクションにイベントとそれらが繋がったことがわかるでしょう。
また、この HTTP エンドポイントが呼び出されたときに実行されるコードは、handler.js ファイルの「hello」という関数で定義されていることに注意してください。
このファイルを編集してから「サーバーレスデプロイ」を実行すると、変更が AWS アカウントにプッシュされ、次にブラウザまたは curl を使用してそのエンドポイントを呼び出すと、変更が反映されていることがわかります。
$ curl {your_endpoint_URL}
いくつかの基本事項がわかったので、これをさらに拡張して、いくつかの有用なエンドポイントを追加しましょう。
データベースに新しいレコードを追加できるように、POST エンドポイントがあると便利です。
これを行うために、DynamoDB と呼ばれる AWS サービスを使用します。これにより、Lambda 関数のデータストアをすばやく簡単に作成できます。
これを行うには、serverless.yml を開き、ファイルの最後に以下を貼り付けます。
resources:
Resources:
CustomerTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
- AttributeName: primary_key
AttributeType: S
BillingMode: PAY_PER_REQUEST
KeySchema:
- AttributeName: primary_key
KeyType: HASH
TableName: ${self:service}-customerTable-${sls:stage}
そして、createCustomer.js という serverless.yml と同じフォルダに新しいファイルを作成し、それに次のコードを追加しましょう。
'use strict'
const AWS = require('aws-sdk')
module.exports.createCustomer = async (event) => {
const body = JSON.parse(Buffer.from(event.body, 'base64').toString())
const dynamoDb = new AWS.DynamoDB.DocumentClient()
const putParams = {
TableName: process.env.DYNAMODB_CUSTOMER_TABLE,
Item: {
primary_key: body.name,
email: body.email
}
}
await dynamoDb.put(putParams).promise()
return {
statusCode: 201
}
}
AWS との通信に役立つ npm モジュールが含まれていることに気付いたかもしれません。そのため、次のコマンドを使用して、サービスの一部としてこの必要な npm モジュールをインストールしてください。
$ npm install –save aws-sdk
注:このプロジェクト全体をクローンの参照として使用する場合は、GitHub で見つけることができます。ただ、デプロイする前に、サーバーレスダッシュボードアカウントに接続するために独自の組織名とアプリ名を serverless.yml に追加することを忘れないでください。
関数がどのテーブルにアクセスするかを知るためには、その名前が使用可能である必要があります。
Lambda には環境変数の概念があります。
serverless.yml に環境変数を設定して、コードで関数にアクセスできるようにすることができます。 serverless.yml のプロバイダセクションに以下を追加します。
provider:
environment:
DYNAMODB_CUSTOMER_TABLE: ${self:service}-customerTable-${sls:stage}
関数コードでは、`process.env.DYNAMODB_CUSTOMER_TABLE`ようにこの環境変数にアクセスしていることに気付いたかもしれません。
環境変数は、必要な構成の詳細を Lambda 関数に渡すための非常に強力な方法になります。
先に進んで変更を既にデプロイすることはできますが(「serverless deploy」コマンドを使用して自由にデプロイできます)、コードがデータベースと通信できるようにするために、もう1つ追加する必要があります。
デフォルトでは、セキュリティ上の理由から、AWS では Lambda 関数が他の AWS サービスにアクセスできるようにするための明示的なアクセス許可を追加する必要があります。
これには、serverless.yml にいくつかの構成を追加する必要があります。
serverless.yml の「provider」ブロック内に、次のものがあることを確認してください。
provider:
iamRoleStatements:
- Effect: "Allow"
Action:
- "dynamodb:PutItem"
- "dynamodb:Get*"
- "dynamodb:Scan*"
- "dynamodb:UpdateItem"
- "dynamodb:DeleteItem"
Resource: arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/${self:service}-customerTable-${sls:stage}
これらのパーミッションは、DynamoDB に接続できるようデプロイされたときに、Lambda 関数に適用されるようになります。
データベースの構成を追加し、データベースと通信するためのコードを記述しましたが、現時点では記述したコードをトリガーする方法はありません。一旦修正しましょう。
serverless.yml で、functions ブロック内に次のブロックを貼り付けます。
functions:
createCustomer:
handler: src/createCustomer.createCustomer
events:
- http:
method: POST
path: /
「serverless deploy」(サーバーレスデプロイ)を実行してみましょう。数秒後、デプロイしたすべての変更が AWS アカウントにプッシュされ、デプロイ後の概要でエンドポイントについて必要な情報が提供されます。
デプロイしたら、エンドポイントをテストします。API の HTTP エンドポイントをテストするための方法は、どれでも使用可能ですが、CLI で curl を素早く使用することができます。
curl -X POST -d '{"name":"Gareth Mc Cumskey","email":"gareth@mccumskey.com"}' --url https://[insert your url here]/
API にデータを挿入できるようになったので、クイックエンドポイントをまとめてすべての顧客を取得しましょう。まず、次の関数構成を serverless.yml に挿入します。
getCustomers:
handler: getCustomers.getCustomers
events:
- httpApi:
path: /
method: get
次に、getCustomers.js というファイルを作成し、getCustomers 関数に次のコードをドロップする必要があります。
'use strict'
const AWS = require('aws-sdk')
module.exports.getCustomers = async (event) => {
const scanParams = {
TableName: process.env.DYNAMODB_CUSTOMER_TABLE
}
const dynamodb = new AWS.DynamoDB.DocumentClient()
const result = await dynamodb.scan(scanParams).promise()
if (result.Count === 0) {
return {
statusCode: 404
}
}
return {
statusCode: 200,
body: JSON.stringify({
total: result.Count,
items: await result.Items.map(customer => {
return {
name: customer.primary_key,
email: customer.email
}
})
})
}
}
ここで実際に注意する必要があるのは、その環境変数を再利用して DynamoDB テーブルにアクセスすることと、DynamoDB のスキャンメソッドを使用してすべてのレコードを取得することです。
プロジェクトの最終バージョンで、デフォルトの関数定義と handler.js ファイルを削除したことに気付いたかもしれません。必要に応じて、今すぐ実行してください。
「serverless deploy」(サーバーレスデプロイ)の後、新しいエンドポイントができました。そして、それに対してcurl コマンドを実行し、前に挿入したアイテムを取得する必要があります。
curl –url {insert_URL_here}
本記事のように Serverless Framework を使用すると、エンドポイントの起動を非常に高速に行うことができます。
スムーズに行けば30分もかからないでしょう。
これで、実際には本番環境に対応した2つのエンドポイントができました。 AWS では多くのサーバーレス製品は3つのアベイラビリティーゾーンにわたって完全に冗長化されており、負荷分散されていますので可用性の点も安心です。
私たちは通常時 Serverless Framework でインフラ構築を行い、最短工数でお客様のサービスインをサポートいたします。
サーバーレスの開発は、お気軽にご相談ください。