のんびりSEの議事録

プログラミング系のポストからアプリに関してのポストなどをしていきます。まれにアニメ・マンガなど

AWS SAMを利用したサーバレスAPIの構築

f:id:tatsu_tora:20190420182416p:plain

最近少しAWSに触れる機会が減ってしまっているため、久々にAWSネタです。

AWS SAM(サーバレスアプリケーションモデル)とは

AWS上でサーバーレスアプリケーションを構築するために使用することができるオープンソースフレームワークです。

提供してくれること

  • AWS SAMテンプレートを使用したサーバレスアプリケーションの構築
  • ローカル上でのテスト、デバッグ
  • サーバレスアプリケーションのデプロイ

インストール(Macの場合)

  • Dockerがインストールされていることが前提(ローカル上でのテストでDockerを内部で利用しているため)
$ brew upgrade
$ brew tap aws/tap
$ brew install aws-sam-cli

CLIツールの概要

init

AWS SAMテンプレートを利用したサーバレスアプリケーションの初期化

$ sam init --runtime <runtime>
  • AWS Lambdaで使用できるランタイム

AWS Lambda ランタイム - AWS Lambda

invoke

ローカル上で擬似的にLambdaを呼び出す

$ sam local invoke [OPTIONS] [FUNCTION_IDENTIFIER]

option

  • --event|-e : 呼び出された時にLambda関数に渡されるイベントファイル(JSON)

generate-event

Amazon S3Amazon API GatewayAmazon SNSなどのさまざまなイベントソースからサンプルペイロードを生成します。 これらのペイロードには、イベントソースがLambda関数に送信する情報が含まれています。

$ sam local generate-event

現状使用できるリソース

  • alexa-skills-kit
  • alexa-smart-home
  • apigateway
  • batch
  • cloudformation
  • cloudfront
  • cloudwatch
  • codecommit
  • codepipeline
  • cognito
  • config
  • dynamodb
  • kinesis
  • lex
  • rekognition
  • s3
  • ses
  • sns
  • sqs
  • stepfunctions

local

start-api

サーバレスアプリケーションをローカル上で実行可能なHTTPサーバを立ち上げます。(Dockerを内部で利用) API Gateway+Lambdaをローカル上で確認するのに役立ちます。

$ sam local start-api [OPTIONS]

start-lambda

AWS Lambdaをエミュレートするローカルエンドポイントを起動します。エンドポイントに対して、AWS SDKAWS CLIを利用してローカルでLambda関数を呼び出すことができます。

$ sam local start-lambda
# 立ち上げたままで、endpoint-urlをローカルの物にして呼び出すことができる
$ aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt

invoke

local上でLambda関数を呼び出します。呼び出が完了した後終了します。

$ sam local invoke [FunctionName] --event event.json

validate

AWS SAMのテンプレートのバリデーションを行います。

$ sam validate

logs

Lambda関数によって生成されたログを取得します。

$ sam logs -n FunctionName

package

AWS SAMアプリケーションをパッケージ化します。 これはaws cloudformationパッケージのエイリアスです。

sam package \
    --output-template-file packaged.yaml \
    --s3-bucket REPLACE_THIS_WITH_YOUR_S3_BUCKET_NAME
  • --output-template-file : コマンドがパッケージ化されたテンプレートを書き込むファイルへのパス。
  • --s3-bucket: アップロード先のS3のバケット名を指定する。

deploy

AWS SAMアプリケーションをデプロイします。 これはaws cloudformation deployエイリアスです。

sam deploy \
    --template-file packaged.yaml \
    --stack-name <stack-name> \
    --capabilities CAPABILITY_IAM

publish

AWS SAMアプリケーションをAWS Serverless Application Repositoryに公開します。 このコマンドは、パッケージ化されたAWS SAMテンプレートを受け取り、指定されたリージョンにアプリケーションを公開します。

$ sam publish

build

このコマンドを使用して、Lambdaソースコードをビルドし、Lambdaの実行環境をターゲットとするデプロイメント成果物を生成します。 依存関係を含むマニフェストファイル(Pythonならrequirements.txt等)を探し、依存関係をビルドパッケージに含めることが出来ます。

$ sam build

AWS SAMテンプレート

AWS SAMテンプレートは、AWS CloudFormationテンプレートの拡張です。 つまり、AWS CloudFormationテンプレートで宣言できるリソースであれば、AWS SAMテンプレートでも宣言できます。 さらに、AWS SAMが提供する追加のリソースタイプ(サーバーレスリソースの宣言で説明されているリソースなど)を、サーバーレスアプリケーションの一部のコンポーネントのショートカットとして使用できます。

例) python3.7のランタイムを使用したAPI Gatewayの作成

AWS SAMを利用した初期化

$ sam init --runtime python3.7
$ cd sam-app

Localでのテスト(* Dockerが既にインストールされていることが前提)

$ sam local start-api
$ curl http://127.0.0.1:3000/hello

ビルドとデプロイ

$ aws s3 mb s3://bucket_name # bucketは新規に必要
$ sam package \
    --output-template-file packaged.yaml \
    --s3-bucket bucket_name
$ sam deploy \
    --template-file packaged.yaml \
    --stack-name sam-app \
    --capabilities CAPABILITY_IAM

API Gatewayの動作確認

$ aws cloudformation describe-stacks \
    --stack-name sam-app \
    --query 'Stacks[].Outputs[?OutputKey==`HelloWorldApi`]' \
    --output table
$ curl -XGET ${OutputValue} // 上記の結果のOutputValueに対してAPIを呼び出し、レスポンスが返ってくればOK

セキュリティについて

API Gatwayに対して、アクセス制限をかけたい場合、APIリソースに対して、リソースポリシーを設定することでアクセス制限を掛けることが出来ます。 基本IAMポリシーの記述と同じようです。

Amazon API Gateway リソースポリシーを使用して API へのアクセスを制御する - Amazon API Gateway

所感

今までLambda Function自体は、小さいバッチ等に利用することが多かったですが、AWS SAMを利用することにより、API Gatewayとの連携がしやすくなり、簡単なモックを作るのに適しているように感じました。

疑問点

API Gatway想定で作られているからか、新規にバケットから作成する必要があるので、API想定ならドメインとかも考えるのでいいとして、通常のバッチ用途とかの場合でも、新規バケットからだと、バケット命名がちょっとつらそうな気がしました。。。S3にアップロードされているものは拡張子はないですが、パッケージングされたzipのようです。