📝

AWS SAMを用いてサーバーレスな環境を自動構築する

2021/06/07に公開

ゴール

・AWS Serverless Application Model (SAM)を用いて、サーバーレス構成を自動構築する
・今回は、前回のハンズオンで構築した構成を、SAMで少しずつ作っていきます

  1. 前回のハンズオンの復習と今回のハンズオンの概要
  2. AWS SAMの紹介とAWS Cloud9の紹介
  3. Cloud9のセットアップ + Cloud9で簡単なLambda関数を作成する
  4. SAMでLambda関数を作成する1
  5. SAMでLambda関数を作成する2
  6. SAMでAPI Gatewayのリソースを作成し、Lambda関数と連携させる
  7. SAMでDynamoDB TBLを作成し、Lambda関数を連携させる
  8. SAM CLIを使ってみる
  9. SAM CLIを使ってみる
  10. クリーンアップ&落穂ひろい

前回のハンズオンの復習

AWS Lambdaの特徴
・サーバーのプロビジョニング/管理なしでプログラムを実行できるサービス
・コードの実行やスケーリングに必要なことは、Lambda側で実施するので、開発者の方はコードを書くことにより集中できる
・リクエストベースの料金体系(実行回数+実行時間)

Amazon API Gatewayの特徴
・サーバーをプロビジョニング/管理することなく、APIを作成・管理できるマネージドサービス
・可用性の担保、スケーリング、APIキー管理といったAPI開発で必要なことをAPI Gatewayに任せることで、開発者はビジネスの差別化につながる作業に集中できる
・REST APIとWebSocketに対応
・リクエストベースの料金体系(REST APIの場合 実行回数+キャッシュメモリ量+データ転送料金)

Amazon DymamoDBの特徴
・フルマーネジド型のNoSQLデータベースサービス
・3つのAvailability Zoneに保存されるので信頼性が高い
・性能要件に応じて、テーブルごとにスループットキャパシティを定義するキャパシティのAuto Scaling、オンデマンドキャパシティといった設定も可能
・ストレージの容量制限がない
・料金体系(設定したRead・Writeキャパシティユニット+ストレージ利用料+オプション機能料金

今回はテンプレート化することでバージョン管理ができるようにする。

AWS CloufFormation

・AWSリソースのモデル化、およびセットアップ
・利用するAWSリソースをテンプレートに記述すると、各リソースのプロビジョニング・設定をAWS CloudFormationが実施する
・AWSリソースに関する記述が、テンプレート(テキストファイル)に集約されるので、現状の把握や変更の追跡が容易に
・YAML形式orJSON形式
・関連リソースはCloudFormationスタックに紐づく形で作成される。スタックを削除すればリソース群をまとめて削除することもできる

AWS Serverless Application Model(SAM)

・サーバーレスアプリケーション構築用のオープンソースフレームワーク
・AWS CloudFormationの拡張機能で、より簡潔にテンプレートを記述可能
・SAMテンプレートもYAML形式もしくはJSON形式で記述できる
・SAM CLIも提供されている

AWS SAMテンプレートの書き方

  1. リソースタイプを選択
  2. リソースタイプごとに必要なプロパティを記述

AWS SAM利用の流れ

  1. SAMテンプレートを記述
  2. パッケージングする
  3. デプロイする

ほとんどコマンドで対応する。

AWS Cloud9

・ブラウザのみでコードを記述、実行、デバッグ可能クラウドベースの統合開発環境(IDE)
・複数人でリアルタイムに共同コーディングできるチャット機能を利用し、ペアプログラミングも
・サーバーレスアプリケーションを簡単に構築できる
・ホストされるEC2インスタンス+EBS分の料金

AWS Cloud9のセットアップ

  1. マネジメントコンソールへログインする
  2. 東京リージョンで作成
  3. Cloud9を検索
  4. Create environment
  5. 環境名を入力、説明はなしでもOK
  6. デフォルトの設定で起動する
  7. AWS Resources
  8. Lambda Functionの作成
  9. FunctionNameとApplicationNameの入力
  10. ランタイムをPythonに設定
  11. ブループリントをempty-pythonに設定
  12. API Gatewayなどは設定せずに
  13. そのほかもデフォルトで設定
  14. 関数を少し編集
  15. デプロイ

SAMでLambda関数を作成する1

  1. Cloud9に戻る
  2. aws --versionで確認
  3. コマンドラインでS3バケットを作成

バケット名はユニークにする必要がある

aws s3 mb s://hands-on-serverless-matsumoto
  1. S3のコンソールで作成を確認
  2. ディレクトリ等の作成
$ mkdir hands-on-serverless-2
$ cd hands-on-serverless-2
$ mkdir translate-function
$ touch translate-function/translate-function.py
$ touch template.yaml
  1. translate-function.pyとtemplate.yamlを貼り付け

translate-function.py

import json
import logging

logger = logging.getLogger()
logger.setLevel(logging.INFO)

def lambda_handler(event, context):

    logger.info(event)

    return {
        'statusCode': 200,
        'body': json.dumps('Hello Hands on world!')
    }

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
  1. それぞれのパラメータの確認
  2. cloudformationのパッケージ化
aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket *your-backet-name* \
     --output-template-file packaged-template.yaml
  1. cloudformationのdeploy
aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM
  1. Lambdaで確認する

SAMでLambda関数を作成する

  1. ファイル内容の修正
  2. input_textに何かしらの日本語を入力
  3. yamlファイルにポリシーを追加
Policies:
  - TranslateFullAccess

translate-function.py

import json
import boto3

translate = boto3.client('translate')

def lambda_handler(event, context):

    input_text = "こんにちは"

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode='ja',
        TargetLanguageCode='en'
    )

    output_text = response.get('TranslatedText')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        })
    }

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
  1. パッケージング化
aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket *your-backet-name* \
     --output-template-file packaged-template.yaml
  1. デプロイ
aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM
  1. Lambdaコンソールで更新の確認

SAMでAPI Gatewayのリソースを作成しLambda関数と連携させる

  1. コピペ

translate-function.py

import json
import boto3

translate = boto3.client(service_name='translate')

def lambda_handler(event, context):

    input_text = event['queryStringParameters']['input_text']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="ja",
        TargetLanguageCode="en"
    )

    output_text = response.get('TranslatedText')

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId: !Ref TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api-2
      StageName: dev
      EndpointConfiguration: REGIONAL
  1. パッケージング化
aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket *your-backet-name* \
     --output-template-file packaged-template.yaml
  1. デプロイ
aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM
  1. Lambdaで確認

  2. APIのGETメソッドで確認する

SAMでDynamoDBテーブルを作成して、Lambda関数と連携させる

  1. コピペ

translate-function.py

import json
import boto3
import datetime

translate = boto3.client(service_name='translate')

dynamodb_translate_history_tbl = boto3.resource('dynamodb').Table('translate-history-2')

def lambda_handler(event, context):

    input_text = event['queryStringParameters']['input_text']

    response = translate.translate_text(
        Text=input_text,
        SourceLanguageCode="ja",
        TargetLanguageCode="en"
    )

    output_text = response.get('TranslatedText')

    dynamodb_translate_history_tbl.put_item(
      Item = {
        "timestamp": datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
        "input": input_text,
        "output": output_text
      }
    )

    return {
        'statusCode': 200,
        'body': json.dumps({
            'output_text': output_text
        }),
        'isBase64Encoded': False,
        'headers': {}
    }

template.yaml

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Hands-on for Beginners - Serverless 2
Resources:
  TranslateLambda:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: translate-function-2
      CodeUri: ./translate-function
      Handler: translate-function.lambda_handler
      Runtime: python3.7
      Timeout: 5
      MemorySize: 256
      Policies:
        - TranslateFullAccess
        - AmazonDynamoDBFullAccess
      Events:
        GetApi:
          Type: Api
          Properties:
            Path: /translate
            Method: get
            RestApiId: !Ref TranslateAPI
  TranslateAPI:
    Type: AWS::Serverless::Api
    Properties:
      Name: translate-api-2
      StageName: dev
      EndpointConfiguration: REGIONAL
  TranslateDynamoDbTbl:
    Type: AWS::Serverless::SimpleTable
    Properties:
      TableName: translate-history-2
      PrimaryKey:
        Name: timestamp
        Type: String
      ProvisionedThroughput:
        ReadCapacityUnits: 1
        WriteCapacityUnits: 1
  1. パッケージング化
aws cloudformation package \
     --template-file template.yaml \
     --s3-bucket *your-backet-name* \
     --output-template-file packaged-template.yaml
  1. デプロイ
aws cloudformation deploy \
     --template-file ./packaged-template.yaml \
     --stack-name hands-on-serverless-2 \
     --capabilities CAPABILITY_IAM
  1. DynamoDBのテーブル確認
  2. Lambdaで確認
  3. APIのGETメソッドで確認する
  4. DynamoDBの更新確認

SAM CLIを使ってみる(ここは少し構築方法が変わっているので確認する必要があります。)

AWS SAM Command Line Interfaceとは
・AWS SAMをローカル環境で利用する上で、様々な便利な機能を提供するCLI

  • 要Dockerインストール
  • 現在は一般提供中

・テンプレートを使ってサーバーレスアプリケーションを対話形式で初期化 sam init
・ローカル環境でビルド sam build
・AWS環境へデプロイ sam deploy --guided
・SAMテンプレートの事前検証 sam validate
・LambdaローカルエンドポイントやAPIエンドポイントを起動し、実行のテストが可能
sam local start-lambda / start-api

Cloud9にはSAM CLIがそもそも入っています。

初期化からビルド

sam init
1
9
Project Nameは空欄
キックスターターは1
cd sam-app
sam validate
sam build

sam deploy --guided
Stack Nameは空欄
ap-northeast-1
y
y
y
y

sam local start-lambda

別ターミナルでファンクションの実行をする
aws lambda invoke --function-name "HelloWorldFunction" --endpoint-url "http://127.0.0.1:3001" --no-verify-ssl out.txt
sam local start-api

curl http://http://127.0.0.1:3000/hello

削除

スタックを削除していく

Discussion