🚀

【AWS】AWS SAMで「API Gateway + Lambda」構成をテンプレート化する

2022/07/28に公開


はじめに

ご覧いただきありがとうございます。阿河です。

最近「サーバレスな構成を複数のアカウントにデプロイする」機会があり、設定ミス/労力の軽減をするためにテンプレート化することは大切だなと改めて実感しました。

以前の記事でCloudFormationで基本的なシングル構成を構築するをテーマとして書きましたが、今回はサーバレス版ということでAWS SAMをテーマに記事を書こうと思います。

対象者

  • AWSを運用中
  • 構築管理の手間を省きたい
  • サーバレス構成に興味がある

概要

  1. 手作業で「API Gateway + Lambda」構成を作成
  2. AWS SAMで「API Gateway + Lambda」構成を自動構築する
  3. リソース確認/動作検証

各種ドキュメントを参考に進めていきます。

1. 手作業で「API Gateway + Lambda」構成を作成

事前準備

  • S3バケットの作成
  • Cloud9環境の準備

Lambda用のIAMロールを作成

  • 信頼されたエンティティタイプ: AWSのサービス
  • 一般的なユースケース: Lambda
  • ポリシー: AWSLambdaBasicExecutionRole/TranslateFullAccess
  • ロール名: ※任意の名前をつけてください

Lambda関数の作成

まずは手動でリソースを作成します。
Lambda関数の中身は、Amazon Translateを利用して「日本語⇒英語」に翻訳するものです。

AWSマネジメントコンソールで、Lambdaのページに移動してください。
関数を作成します。

  • オプション: 一から作成
  • 関数名: ※任意の名前
  • ランタイム: Python3.8
  • アーキテクチャ: x86_64
  • アクセス制限: ※先程作成したLambda用のロールを付与

関数作成後、設定タブからタイムアウトの秒数を10秒に変更。

続いてコードを作成します。

import json
import boto3

def lambda_handler(event, context):
    
    test_input_text = event['queryStringParameters']['user_input'] 
    trans_client = boto3.client('translate')
    res = trans_client.translate_text(
            Text=test_input_text,
            SourceLanguageCode='ja',
            TargetLanguageCode='en'
            )
    
    out_text = res['TranslatedText']
    return {
        'statusCode': 200,
        'body': json.dumps({
            'trans_text': out_text
        }),
	'headers': {},
	'isBase64Encoded': False
    }

クエリパラメータの値を、翻訳対象のテキストとして受け取ります。
受け取ったテキストをAmazon Translateのtranslate_textで翻訳を行います。

API Gatewayの設定

API Gatewayの各機能/詳細については、Black Beltの説明が分かりやすいので、別途参照ください。

  • APIタイプ: REST API
  • 新しいAPIの作成: 新しいAPI
  • 名前: ※任意の名前
  • エンドポイントタイプ: リージョン

APIを作成したら、アクションから「リソース」と「メソッド」を追加します。

REST APIは、「/」を最上位としたツリー構造にて、「リソース」を定義します。
各リソースに受け付けるHTTPメソッドを指定します。

今回は「/」配下に「test」というリソースを定義し、メソッドとして「GET」を指定しました。
GETの右横にあるチェックボックスをクリックします。

  • 統合タイプ: Lambda関数
  • Lambdaプロキシ統合の使用: 有効
  • Lambda関数: ※作成したLambda関数を指定

自動で権限設定が行われます。

メソッドリクエストの設定で、URLクエリ文字列パラメータの設定を追加します。

APIをデプロイする

アクションから「APIのデプロイ」を選択します。

ステージを新規作成して、デプロイを実行します。


URLが発行されました。
ステージ作成後に一番初めに表示されるURLでなく、/testの階層に表示されているURLにアクセスを行います。

https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/prod/test?user_input=これはテストです

実際にURLにアクセスしてみます。
URLの指定の際に「?input_text=※渡したい日本語文字列」を追加します。

クエリ文字列パラメータで渡した値が、翻訳されて表示されました。

手動での「API Gateway + Lambda」の構築は完了です。
同様の構成をAWS SAMでテンプレート化していきます。

2. AWS SAMで「API Gateway + Lambda」構成を自動構築する

Cloud9上でディレクトリ構成をつくる

まず作業用のディレクトリと、pythonコードを格納するディレクトリを作成します。

$ cd ~/environment
$ mkdir -p sam-test/sam-test-function
$ cd sam-test/sam-test-function/

pythonファイルを作成

次にsam-test-function配下に、pythonファイルを作成します。

$ vi sam-test-function.py

ファイルの内容は下記の通りです。

import json
import boto3

def lambda_handler(event, context):
    
    test_input_text = event['queryStringParameters']['user_input'] 
    trans_client = boto3.client('translate')
    res = trans_client.translate_text(
            Text=test_input_text,
            SourceLanguageCode='ja',
            TargetLanguageCode='en'
            )
    
    out_text = res['TranslatedText']
    return {
        'statusCode': 200,
        'body': json.dumps({
            'trans_text': out_text
        }),
	'headers': {},
	'isBase64Encoded': False
    }

前セクションで手作業で作成したLambdaコードと変わらないので、説明は割愛します。

yamlファイルの作成

次にyamlファイルを作成します。

$ cd ../
$ vi template.yaml

ファイルの中身は以下の通りです。

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Resources:
  Lambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: sam-test-function
      Handler: sam-test-function.lambda_handler
      Runtime: python3.8
      Timeout: 10
      CodeUri: ./sam-test-function
      MemorySize: 128
      Policies:
        - TranslateFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /sam-test
            Method: get
            RestApiId: !Ref API
  API:
    Type: AWS::Serverless::Api
    Properties:
      Name: sam-test-get-api
      EndpointConfiguration: REGIONAL
      StageName: dev

こちらはAWS SAMのDeveloper Guideを参照します。

AWS SAMはサーバーレスアプリケーション構築用のオープンソースフレームワークで、Lambda関数、API Gateway、DynamoDBなどのリソースを、迅速に記述可能な構文で定義することができます。

AWS SAMはCloudFormationの拡張であるため、CloudFormationのデプロイ機能を利用できます。

テンプレートの構成についてこちらで確認します。

  • Transform (必須)
    この宣言は、CloudFormationテンプレートファイルをSAMテンプレートファイルとして識別します。
  • Globals (オプション)
    サーバーレス関数とAPIに共通のプロパティを定義。
  • Description (オプション)
    テンプレートについての説明。
  • Metadata (オプション)
    テンプレートに関する追加情報を提供するオブジェクト。
  • Parameters (オプション)
    実行時に(スタックを作成または更新するときに)テンプレートに渡す値。
  • Mappings (オプション)
    条件付きパラメーター値を指定するために使用できるキーと関連する値のマッピング。
  • Conditions (オプション)
    制御する条件
  • Resources (必須)
    スタックリソースとそのプロパティ。SAMテンプレートでは、 Resourcesセクションに「CloudFormationリソース」と「SAMリソース」の組み合わせを含めることができます。
  • Outputs (オプション)
    スタックのプロパティを表示するたびに返される値。

今回は「Transform」と「Resources」を記述しています。

合わせて「Resources」部分を個別に見ていきます。
まずAPIの部分です。

API:
    Type: AWS::Serverless::Api
    Properties:
      Name: sam-test-get-api
      EndpointConfiguration: REGIONAL
      StageName: dev

AWS::Serverless:Apiは、HTTPSエンドポイントを介して呼び出すことができる「AmazonAPIGatewayリソースとメソッドのコレクション」を作成します。

  • Name(オプション)
    APIGatewayのRestApiリソースの名前

  • EndpointConfiguration
    RESTAPIのエンドポイントタイプ。手作業で作成したときと同様に、リージョンタイプを選択します。

  • StageName(必須)
    APIGatewayがURIの呼び出しの最初のパスセグメントとして使用するステージの名前。

次にLambdaの設定を見ていきます。

Lambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: sam-test-function
      Handler: sam-test-function.lambda_handler
      Runtime: python3.8
      Timeout: 10
      CodeUri: ./sam-test-function
      MemorySize: 128
      Policies:
        - TranslateFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /sam-test
            Method: get
            RestApiId: !Ref API

AWS::Serverless::Functionは、Lambda関数、IAMロール、関数をトリガーするイベントソースマッピングを作成します。

  • FunctionName(オプション)
    関数の名前。

  • Handler(条件付き)
    実行を開始するために呼び出されるコード内の関数。

  • Runtime(条件付き)
    関数のランタイムの識別子。

  • Timeout(オプション)
    関数が停止するまでに実行できる最大時間(秒単位)

  • CodeUri(条件付き)
    関数コードのAmazonS3URI、ローカルフォルダへのパス、またはFunctionCodeオブジェクト。PackageTypeプロパティがZip(デフォルト)に設定されている場合は、CodeUriまたはInlineCode(インラインコード)が必要です。今回はインラインコードではなく、CodeUriを指定。「sam-test-function」のパスを指定しています。

  • MemorySize(オプション)
    関数の呼び出しごとに割り当てられたメモリのサイズ(MB単位)

  • Policies(オプション)
    この関数に必要な1つ以上のポリシーで、関数のデフォルトの役割に追加されます。
    今回はAWSマネージドポリシーである「TranslateFullAccess」を追加しています。

  • Events(オプション)
    この関数をトリガーするイベントを指定します。こちらを参照します。「同じテンプレート内で作成しているRestApiリソースの識別子」「関数が呼び出されるURIパス」「関数が呼び出されるHTTPメソッド」を指定しています。

以上がテンプレートの説明です。

パッケージング

$ aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket [※S3バケット名] \
     --output-template-file pack_template.yaml

Cloud9でCLIコマンドを入力します。

aws cloudformation packageで、テンプレートが参照するローカルアーティファクト(ローカルパス)をパッケージ化します。ローカルアーティファクトをS3バケットにアップロードします。このコマンドはテンプレートのコピーを返し、ローカルアーティファクトへの参照をアーティファクトがアップロードされたS3 URIに置き換えます。

コマンドの実行結果として、パッケージ化されたyamlファイルが生成されました。

デプロイ

$ aws cloudformation deploy \
     --template-file ./pack_template.yaml \
     --stack-name sam-test-stack \
     --capabilities CAPABILITY_IAM

aws cloudformation deployは、指定されたAWSCloudFormationテンプレートをデプロイします。

コマンドを実行します。

CloudFormationのスタック作成が始まりました。
しばらくするとリソースが作成されます。

3. リソース確認/動作検証

それぞれのリソースを見てみましょう。

  • IAMロール

TranslateFullAccessが追加されています。

  • Lambda

コードが反映されています。

  • API Gateway

API Gatewayもしっかり設定されています。

URLにアクセスしてみます。

無事翻訳されています。

さいごに

以上 手で作成した「API Gateway + Lambda」をテンプレート化できました。
御覧いただき ありがとうございました!!

MEGAZONE株式会社 Tech Blog

Discussion