このモジュールでは、アプリケーションコードをサーバーレスコンピューティングサービスである AWS Lambda にデプロイします。AWS Lambda では、サーバー管理やキャパシティープランニングについて心配する必要はありません。実行するコードをアップロードするだけで、AWS は設定されたイベントトリガーが発生するたびにコードを実行します。

Lambda で使用できるイベントトリガーの 1 つは Amazon API Gateway です。Amazon API Gateway では、リクエストを AWS Lambda 関数に転送する HTTP エンドポイントを設定できます。Lambda と API Gateway の間で、サーバーをプロビジョニングまたは管理することなく、完全に機能するウェブアプリケーションを構築できます。さらに、Lambda と API Gateway はどちらも従量制料金で請求されます。つまり、支払うのは、使用した分に対してのみです。

次の手順では、Lambda 関数を設定し、AWS コマンドラインインターフェイス (AWS CLI) を使用して API Gateway で HTTP ルートを設定します。Lambda と API Gateway を使用してアプリケーションを構築している場合、AWS サーバーレスアプリケーションモデル (AWS SAM)Serverless Framework などのツールを使用して、インフラストラクチャをコードとして用いてサーバーレスアプリケーションを管理できます。

モジュールの所要時間: 15 分


  • ステップ 1:ネットワークリソースを作成する

    前のモジュールでは、セキュリティグループを作成し、AWS Lambda 関数からアクセスできるように Neptune インスタンスを設定しました。Neptune インスタンスには、パブリックインターネット経由ではなく、VPC 内からアクセスする必要があります。

    このモジュールでは、AWS Lambda で実行するアプリケーションコードをデプロイします。AWS Lambda 関数が Neptune インスタンスにアクセスするには、VPC のサブネットに配置され、Neptune インスタンスにアクセスできるセキュリティグループで構成されている必要があります。

    Lambda 関数は、AWS SDK を使用して Amazon Cognito ユーザープールにアクセスする必要もあります。Amazon Cognito とのすべての通信は、パブリックインターネット経由で行われます。プライベートサブネットの Lambda 関数がパブリックインターネットにアクセスできるようにするには、プライベートネットワークトラフィックをパブリックインターネットトラフィックに変換する NAT ゲートウェイを構成する必要があります。

    必要なネットワークリソースの内部の詳細は、このチュートリアルの範囲外です。ここでは、scripts/ ディレクトリの create-networking.sh スクリプトを使用して、必要なリソースをプロビジョニングできます。

    次のコマンドでこのスクリプトを実行できます。

    bash scripts/create-networking.sh

    次の出力が表示されます。

    Fetching VPC Id
    Fetching subnet Id
    Creating Elastic IP address
    Creating NAT Gateway
    Waiting for NAT Gateway to be ready...
    Creating private subnet
    Creating route table
    Creating route
    Associating route table with subnet
    Networking resources created!
    

    プライベートサブネットおよび関連するネットワークリソースを作成しました。次のステップでは、アプリケーションコードを Lambda 関数にデプロイします。

  • ステップ 2:コードをパッケージ化して Lambda にデプロイする

    最初に、関数コードをパッケージ化し、AWS Lambda にデプロイする必要があります。Lambda は、すべてのアプリケーションコードを含む ZIP ファイルをアップロードすることを期待しています。さらに、使用するランタイムと、コードのエントリポイントとして機能するファイルと関数を指定します。このエントリポイントはハンドラーと呼ばれ、着信イベントがコードをトリガーするたびに呼び出されます。

    関数コードに加えて、Lambda 関数に AWS Identity and Access Management (IAM) ロールを指定する必要もあります。このロールは実行時に関数が引き受けるため、データベースからの読み取りや書き込み、キューへのメッセージ送信、Amazon CloudWatch への出力のログ記録など、AWS リソースへのアクセス許可があります。

    scripts/ ディレクトリには、create-lambda.sh というファイルがあります。このスクリプトは次の 4 つのことを行います。

    1. Lambda 関数で使用する application/ ディレクトリのコンテンツを圧縮します。
    2. Lambda 関数が引き受ける IAM ロールを作成します。
    3. IAM ポリシーを IAM ロールに追加して、Lambda 関数が Amazon Aurora Serverless データベースの Data API にアクセスできるようにします。
    4. zip ファイルをアップロードして Lambda 関数を作成します。

    これらのステップを実行するために使用する AWS CLI コマンドを表示するには、ファイルエクスプローラーで scripts/create-lambda.sh ファイルを開きます。

    スクリプトを実行するには、ターミナルで次のコマンドを実行します。

    bash scripts/create-lambda.sh

    次の出力が表示されます。

    Building zip file
    Creating IAM role
    Adding policy to IAM role
    Sleeping for IAM role propagation
    Creating Lambda function
    Lambda function created with ARN <functionArn>

    Lambda 関数が正常に作成されました。

  • ステップ 3:API Gateway REST API を作成および設定する

    Lambda 関数をデプロイしたので、Amazon API Gateway を使用して HTTP 経由でアクセスできるように設定できます。API Gateway は、バックエンドサービスへの強力なアクセスレイヤーを提供します。高度な設定が可能で、認証、検証、レート制限などを行えます。

    scripts/ ディレクトリに、API Gateway REST API をプロビジョニングして Lambda 関数に接続する create-rest-api.sh というファイルがあります。このスクリプトは、以下を含む多くのことを処理します。

    1. API Gateway で REST API を作成します。
    2. すべての着信リクエストパスとメソッドを単一の Lambda 関数に送信するように、REST API でプロキシリソースとメソッドを設定します。
    3. Lambda 関数をトリガーする REST API の権限を追加します。

    API Gateway には多くの設定オプションがあり、このチュートリアルではすべての詳細をカバーすることはできません。詳細については、「Amazon API Gateway の概念」を参照してください。

    ターミナルで次のコマンドを実行して、スクリプトを実行し、REST API を設定します。

    bash scripts/create-rest-api.sh

    ターミナルに次の出力が表示されます。

    Creating REST API
    Fetching root resource
    Creating proxy resource
    Creating method
    Adding integration
    Creating deployment
    Fetching account ID
    Adding lambda permission
    REST API created
    
    Your API is available at: https://<id>.execute-api.<region>.amazonaws.com/prod

    これで、Lambda 関数に接続するように REST API を設定しました。出力の最後には、REST API にアクセスするためのベース URL が含まれていました。

    ベース URL の値が env.sh ファイルに追加されました。ここでそのファイルを入手して、ターミナルで BASE_URL 環境変数を設定します。

    source env.sh
  • ステップ 4:API エンドポイントをテストする

    API がライブになったので、テストしてみましょう。エンドポイントの 1 つをテストする前に、コードについて簡単に説明します。

    ウェブアプリケーションは、一般的な Node.js ウェブアプリケーションフレームワークである Express.js を使用して構築します。AWS Lambda でアプリケーションを構築するときに Express.js のような既存のウェブフレームワークを使用する必要はありませんが、Express の経験があれば素早く習得できるでしょう。

    Express アプリケーションのコアは application/app.js にあります。ファイルエクスプローラーでファイルを開きます。

    	// application/app.js
    const express = require('express')
    const bodyParser = require('body-parser')
    const { createUser, fetchUser, fetchUserRecommendations, followUser } = require('./data')
    const { createCognitoUser, login, verifyToken } = require('./auth')
    const { validateCreateUser, validateFollowUser } = require('./validate')
    
    const app = express()
    app.use(bodyParser.json())
    
    function wrapAsync(fn) {
      return function(req, res, next) {
        fn(req, res, next).catch(next);
      };
    }
    // Login
    app.post('/login', wrapAsync(async (req, res) => {
      const idToken = await login(req.body.username, req.body.password)
      res.json({ idToken })
    }))
    
    // Create user
    app.post('/users', wrapAsync(async (req, res) => {
      const validated = validateCreateUser(req.body)
      if (!validated.valid) {
        throw new Error(validated.message)
      }
      await createCognitoUser(req.body.username, req.body.password, req.body.email)
      const user = await createUser(req.body.username, req.body.interests)
      res.json(user)
    }))
    
    // Fetch user
    app.get('/users/:username', wrapAsync(async (req, res) => {
      const user = await fetchUser(req.params.username)
      res.json(user)
    }))
    
    // Follow user
    app.post('/users/:username/friends', wrapAsync(async (req, res) => {
      const validated = validateFollowUser(req.body)
      if (!validated.valid) {
        throw new Error(validated.message)
      }
      const token = await verifyToken(req.header('Authorization'))
      if (token['cognito:username'] != req.params.username) {
        throw new Error('Unauthorized')
      }
      const friendship = await followUser({ follower: req.params.username, friend: req.body.username })
      res.json(friendship)
    }))
    
    // Fetch user recommendations
    app.get('/users/:username/recommendations', wrapAsync(async (req, res) => {
      const recommendations = await fetchUserRecommendations(req.params.username)
      res.json(recommendations)
    }))
    
    app.use(function(error, req, res, next) {
      res.status(400).json({ message: error.message });
    });
    
    module.exports = app
    

    このファイルの最上部で、前のモジュールで確認した認証ヘルパー機能やデータアクセス機能など、Express やその他の依存関係をインポートします。次に、ユーザーがログインして ID トークンを取得する /login や特定のユーザーの詳細を取得する /users/:username など、関数に必要なさまざまなルートを設定します。最後に、ファイルの下部で、スクリプトは Express アプリケーションをエクスポートします。

    次に、application/handler.js を見てください。これは、Lambda に着信リクエストで呼び出すように指示する entrypoint メソッドを持つファイルです。このファイルの内容は次のとおりです。

    // application/handler.js
    const awsServerlessExpress = require('aws-serverless-express')
    const app = require('./app')
    const server = awsServerlessExpress.createServer(app)
    
    exports.handler = (event, context) => { awsServerlessExpress.proxy(server, event, context) }

    このハンドラーは aws-serverless-express パッケージを使用しています。このパッケージは、着信 API Gateway リクエストを Express.js フレームワークが期待する標準リクエストに変換します。これにより、Lambda と API Gateway を使用して Express.js コードを簡単に実行できます。

    サンプルデータにロードされたユーザーの興味対象を取得して、エンドポイントをテストしましょう。このリクエストは API Gateway を介して Lambda 関数に送られ、Lambda 関数は Neptune にリクエストを送信して結果を返します。

    ターミナルで次のコマンドを実行します。

    curl -X GET ${BASE_URL}/users/amy81

    VPC リソースがまだプロビジョニングされているため、最初のリクエストには数秒かかるか、エラーが返されることもあります。以降のリクエストははるかに速くなります。 

    ターミナルに次の出力が表示されます。

    {"username":"amy81","friends":["gilbertamber"],"interests":["Cooking","Sports","Woodworking","Nature"]}

    成功しました! API エンドポイントをヒットしました。これにより Lambda 関数がトリガーされ、リクエストされたユーザーの友人と興味対象が Neptune から取得されました。


このモジュールでは、Lambda 関数をデプロイし、API Gateway で REST API を設定しました。次に、アプリケーションの動作を確認し、エンドポイントを呼び出してテストしました。

次のモジュールでは、アプリケーションのすべての機能について説明します。新規ユーザーを作成し、認証情報を使用してログインします。次に、レコメンデーションを表示して、新しい友人をフォローします。