このページの本文へ

サービス開発の新潮流「サーバーレス」をNode.jsとAWS Lambdaで体感しよう

2017年01月23日 04時56分更新

文●Kev Zettler

  • この記事をはてなブックマークに追加
本文印刷
ここ1〜2年前から耳にするようになったWebサービスの開発手法「サーバーレス」。「AWS Lambda」でマイクロサービスを作りながら、サーバーレスの開発フローを体験してみましょう。

サーバー作業にタッチせずにWebアプリやAPIを作成できたら、と思ったことがある人にはアマゾンのLambdaがうってつけでしょう。

Amazon Web Services (AWS)はアマゾンが開発し公式に提供している開発者向けツールです。この記事では、AWSの新ツール「Lambda」を使います。GitHub APIを使って、GitHubからリポジトリ情報を取得し、JSONレスポンスを返すリクエストを生成するHTTP GETエンドポイントを作成します。

この記事の内容を理解して実践するにはAWSアカウントの取得が必要です。ここから無料のAWSアカウントを作成できます。

AWS Lambdaとは?

Lambdaのキャッチコピーは「サーバーレスでコードを実行」とうたっています。これは一見分かりにくく思えるかもしれません。それならコードは実際どこでどのように実行されるのでしょうか。

サーバーレスとFunctions as a Service

「サーバーレス」という最近のソフトウェア・インフラ用語には聞き覚えがあるかもしれません。この用語はコードをオンデマンドで実行するソリューションを指して使われます。「サーバーレス」という用語は誤解を招きかねません。というのは、実は「サーバーレス」環境にはれっきとしたサーバーが存在しているからです。「FaaS」または「Functions as a Service」のほうが的確に表現していると言えるでしょう。

FaaS、Functions as a Serviceのどちらの定義も新しい開発・デプロイメントを指しています。こうした方法が「サーバーレス」とみなされるのは、コードを実行するサーバーを開発者の側で管理したり、監視したり、スケールしたりする必要がないからです。FaaSプロバイダー(ここではAWS Lambda)にコードをアップロードさえすれば、あとはFaaSプロバイダーが実行し、バックヤードであらゆるインフラを管理してくれるのです。

サーバーレスアーキテクチャのメリット・デメリット

「サーバーレス」アーキテクチャの拡張された定義を踏まえて、Lambda導入のメリットとデメリットを説明します。

■メリット

  • 使用分のオンデマンド課金制
    従来のサーバーホスティングは継続課金サイクル制で、サーバーは常に稼働状態のうえ、リソースを使用し入力を待機している。月額や年額で支払いをし、課金サイクル期間中サーバーの稼働を維持する。Lambdaではオンデマンド課金制で、使った機能ごとに料金が計算される。プロジェクトで利用するLambdaの機能の需要量がそれほど高くない場合、従来のホスティングソリューションにかかっていた莫大な費用を節約できる。Lambdaの料金設定は次のようになっている。

    • 100万リクエストにつき0.20ドル
    • 1GB‐秒のコンピューティング時間につき0.00001667ドル(1実行ごとに100ミリ秒単位で切り上げ)

    詳しくはここを参照

  • 「auto scaling」の搭載
    従来のホスト型インフラでは、パフォーマンスやスケーリングについて心配なときがある。アプリケーションのトラフィックや使用量が増えるにつれインフラが需要についていけるように、より多くのホスト型サーバーの追加が必要になる場合もあり、ユーザー側にエラーやボトルネック状態を引き起こしかねない。Lambdaは必要に応じて人知れずスケーリングを実行するので、余計な「cognitive overhead(認知上のオーバーヘッド)」をなくせる

■デメリット

  • ローカル開発ワークフローが統一されない
    Lambdaの関数コードをローカルで記述し単独でテストできるが、Lambdaとの統合バージョンを作成しないとローカルで本番環境のシミュレーションはできない

Lambdaの主要なコンセプト

関数コードとトリガー

Lambdaには「コード」と「トリガー」という、2つの主要なコンセプトがあります。「コード」は見てのとおりの意味です。例えば期待した反応を生じさせるためにユーザーが記述してLambdaにアップロードするJavaScriptコードのことです。

コードをアップロードしても、それだけで動くわけではありません。Lambdaのもう1つのコンセプト「トリガー」は、実行のためにLambda関数にデータを渡す、個別のAWSサービスによって発生するイベントのことです。

下にトリガーの例を挙げます。

  • AWS APIゲートウェイへのHTTPリクエスト
  • CloudWatch Eventsからのcronジョブなど、間隔を置いて発生するイベント
  • DynamoDBのテーブルの更新

Lambdaの関数コードのシグネチャ

目的のLambdaシグネチャと一致する普通の関数をJavaScriptからエクスポートしてLambda関数を定義できます。

exports.myLambdaFunction = (event, context, callback) => {
   // Use callback() and return 
}

この関数は次の3つの引数を受け取ります。

  1. event:Lambdaが関数に渡す「トリガーデータ」のキーと値のペアの辞書
  2. context:AWSリクエストID、Lambdaの期限切れタイムアウト、ログ情報などAWSの内部情報(詳しくはここを参照)
  3. callback:標準の非同期JavaScriptコールバックハンドラー(詳しくはここを参照)

Lambda関数の作成

新しいLambda関数の作成を始めるには「https://console.aws.amazon.com/lambda/home?region=us-east-1#/functions?display=list」からLambdaのダッシュボードにアクセスしてください。

次のような画面が表示されます。

Screenshot of the AWS Lambda dashboard

「Create a Lambda function」の青いボタンをクリックして始めます。

blueprintの選択

blueprint(設計図)の選択を促す画面が表示されフィルタ可能なblueprintのリストが表示されます。オプションの「Blank Function」をクリックしてください。blueprintのリストの1番目に出ているはずです。このページはあとで参照してLambdaの別のユーティリティを確認するために使えます。

トリガーの設定

「Configure Triggers」画面は次のようになります。

Screenshot of the Configure triggers screen

「Next」をクリックしてこの画面をスキップします。関数の設定を完了してからトリガーを割り当てます。

関数の設定

Screenshot of the fields on the Configure function screen

Lambda関数に名前を付けます。例では名前をGithubGetとします。任意で関数の説明も記入できます。

Lambda関数コードを指定

デフォルトで、LambdaのUIは「Edit code inline」に設定されています。サンプル関数の入ったインラインエディターが次のように表示されます。

Screenshot of the online function editor

インラインエディターを使えばあっという間にLambdaコードをアップロードして実行できますが、記事ではさらに高度な方法を紹介します。

依存オブジェクトを持つ複雑な関数の作成

現実的には、npm経由でインストールしたサードパーティーライブラリーを使ったさらに複雑な関数の作成が必要になるでしょう。

npm依存プロジェクトを使用するカスタム関数を作成し、Lambdaにアップロードします。以下のステップのよう進めるか、またはサンプルのリポジトリから自由にコードを入手してください。

■新しい関数の作成
新しい関数用のフォルダーを設定し、次のようにnpmで初期化してデフォルトのpackage.jsonファイルを作成します。

npm init -f

次にGitHubクライアントをインストールします。

npm install github

下のコードでindex.jsファイルを作成します。

var GitHubApi = require('github');
var github = new GitHubApi();

exports.handler = (event, context, callback) => {

  github.search.repos({
    q: 'sitepoint',
    sort: 'stars'
  }, function(err, res){
    if(err){
      callback(err);
    }

    var results = res.items.map((repo) => {
      return {
        url: repo.html_url,
        stars: repo.stargazers_count
      };
    });

    callback(null, {
      statusCode: 200,
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(results)
    });
  });

};

コードの内容を簡単に説明します。

  1. GitHub APIを読み込み、初期化する
  2. Lambdaシグネチャに一致する関数handlerを定義する
  3. handlerが呼び出されると、クエリとして「sitepoint」と一致するすべてのリポジトリについてGitHubに検索リクエストを送信する
  4. Githubのレスポンスフォームで各リポジトリに関するurlとスター数を含むマップが作成される
  5. 最後にAPIゲートウェイとの予想される統合に適合するHTTPレスポンスなどのオブジェクトでLambdaコールバックを呼び出す

■AWS Lambdaへのアップロード
任意の使い慣れたzipユーティリティで関数ファイルのzipファイルを作成します。OS Xでコマンドラインzipユーティリティを使った場合次のようになります。

zip -r lambdaupload.zip ./index.js ./node_modules/

Lambdaにコードをアップロードする場合、「Code entry type」のオプションを「Edit code inline」から「Upload a zip file」に変更し、フォームからコードをアップロードしてください。

Animated GIF showing the upload to Lambda process

■関数のハンドラーとロール(role)を設定する
このセクションでは値を設定します。HandlerはアップロードしたJavaScriptファイル内のLambda関数を参照します。デフォルトではindex.handlerとなっています。indexファイル(例ではindex.js)の探索によってアップロードしたコードにマッピングし、関数handlerのエクスポートステートメント(例ではexport.handlerに対応)を探索します。

「Role」フィールドに次の情報を設定してLambda関数の基本的なロールを作成します。

  • Role:Create new role from template(s)(を選択)
  • Role name:LambdaGetRole
  • Policy templates:Simple Microservice permissions(を選択)

Screenshot of the settings mentioned above

このセクションが完成したら「Next」ボタンをクリックして続行します。構成をまとめた「Review」画面が表示されます。

Review screen summarizing the chosen options

不備がなければ「Create function」ボタンをクリックして続行します。

新しい関数にトリガーを割り当てる

関数の作成と初期化が完了したら、呼び出せなければなりません。このタイミングで関数にトリガーを割り当てます。トリガーにはAPI Gatewayを使います。

API Gatewayは別のAWSサービスで、レスポンスを構成できるHTTPエンドポイントを自動的に作成します。Lambda関数をAPI Gatewayレスポンスとしてアタッチします。

  1. 「Triggers」をクリック
  2. 「Add trigger」をクリック
  3. 「Lambda」の横にある四角い枠をクリック
  4. 「API Gateway」を選択
  5. 画面下部の「Security」で「Open」を選択
  6. 「Submit」をクリック

上のステップを示す画像です。

Animated walk-through of the steps to add an AWS Lambda function trigger

トリガーが正常に追加されると「Triggers」タブで関数にトリガーがアタッチされているのを確認できます。

Triggers tab, showing the newly created API Gateway trigger

API GatewayのIDの下にURLが表示されます。ブラウザーでアクセスすると、以下のようなJSONレスポンスが確認できます。

[{"url":"https://github.com/bodrovis/Sitepoint-source","stars":106},
{"url":"https://github.com/Azzurrio/moviestore","stars":80},
{"url":"https://github.com/bodrovis/SitepointMiniChat","stars":54},
{"url":"https://github.com/upchuk/d8-demo-modules","stars":34},

おめでとうございます! Lambdaでコードが正常にデプロイされ、トリガーされました。

次なるステップとLambdaの今後

この記事がAWS Lambdaで作業するための基礎になれば幸いです。関数コードでサードパーティクライアント(GitHub)インテグレーションを使いましたが、ほかのクライアントAPIやデータベースクライアントとの接続でも代用できます。

サーバーレスフレームワーク

記事で紹介してきたLambdaの設定方法は手作業が多く、少し頼りなく感じられますが、AWS APIで運用するLambdaの設定や初期化の方法はほかにもあります。

現在、AWS APIに加えてこのプロセスの合理化に役立つフレームワークが構築されつつあります。

  • Serverless
    「Serverless」は、現在もっとも堅牢なサーバーレスフレームワーク。しかし、この記事の執筆時点で、Serverlessは0.5から1.0公式リリースへのメジャーバージョンアップグレード途上だが、残念ながらこのアップグレードは後方互換性がない。0.5で評判の良かったプラグインの大半は1.0リリース完了時点で使えなくなる。Serverlessの有効なプラグインを使えば、確実にとても包括的なLambdaのサービスが体験できる。迅速なアップデートが可能なローカル開発環境、Lambdaコードの自動デプロイメント、デプロイメントステージング環境をはじめ、たくさんのことが提供される
  • OpenLambda
    OpenLambdaはLambda環境のシミュレートを目的としたローカル開発サービスを提供している。Lambdaコードをデプロイしやすくするツールも提供していて迅速なアップデートが可能になる。これにより先ほど挙げたLambdaのデメリットが1つ改善される

※本記事はCamilo ReyesJoan YinYaphi BerhanuMoritz Krögerが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。

(原文:Create Serverless Microservices with Node.js and AWS Lambda

[翻訳:新岡祐佳子/編集:Livit

Web Professionalトップへ

WebProfessional 新着記事