AWS Lambdaを使った開発を行う機会があったので、AWS SAMを使ってみました。
Lambda開発といえばServerless Frameworkが有名みたいですが、今回はAmazon公式という点とテンプレートが充実していそうという点でAWS SAMを採用しました。
AWS SAMとは
AWS SAMとは、サーバーレスアプリケーション構築用のフレームワークであり、AWS CloudFormationテンプレートの拡張機能です。
Lambda関数やロール、API Gatewayの作成などをYAMLを使ったテンプレートで定義できます。
アプリの構築にはAWS SAM CLIを使います。テンプレートで定義されたアプリの構築、テストを行うコマンドラインツールです。
準備
AWS CLIのインストール
まずはAWS CLIをインストールします。 AWS SAM CLIを使うにはAWS CLIも必要になるので、導入していない場合は併せてインストールが必要です。
ドキュメント沿ってやっていきます。
Installing, updating, and uninstalling the AWS CLI version 2 on Linux - AWS Command Line Interface
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"unzip awscliv2.zipsudo ./aws/install
AWS CLIがインストールできたら認証プロファイルの設定もしておきます。
aws configure
AWS SAM CLIのインストール
続いてAWS SAM CLIのインストールを行います。
こちらもドキュメントを参考に。
Installing the AWS SAM CLI on Linux - AWS Serverless Application Model
curl -L "https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip" -o "awssamcli.zip"unzip awssamcli.zip -d awssamsudo ./awssam/install
これで準備は完了です。
テンプレートをダウンロードする
sam init
で既存のテンプレートを使って、プロジェクトを初期化できます。
言語ごとにクイックスタートが用意されており、はじめて触る場合はここから慣れていけばよさそうです。
今回はPython3.8のHello Worldを選択。LambdaはZipファイルまたはコンテナイメージでデプロイできますが、今回はZipファイルで行います。
$ sam initWhich template source would you like to use?1 - AWS Quick Start Templates2 - Custom Template LocationChoice: 1What package type would you like to use?1 - Zip (artifact is a zip uploaded to S3)2 - Image (artifact is an image uploaded to an ECR image repository)Package type: 1Which runtime would you like to use?1 - nodejs14.x2 - python3.83 - ruby2.74 - go1.x5 - java116 - dotnetcore3.17 - nodejs12.x8 - nodejs10.x9 - python3.710 - python3.611 - python2.712 - ruby2.513 - java8.al214 - java815 - dotnetcore2.1Runtime: 2Project name [sam-app]:Cloning app templates from https://github.com/aws/aws-sam-cli-app-templatesAWS quick start application templates:1 - Hello World Example2 - EventBridge Hello World3 - EventBridge App from scratch (100+ Event Schemas)4 - Step Functions Sample App (Stock Trader)5 - Elastic File System Sample AppTemplate selection: 1-----------------------Generating application:-----------------------Name: sam-appRuntime: python3.8Dependency Manager: pipApplication Template: hello-worldOutput Directory: .Next steps can be found in the README file at ./sam-app/README.md
Python3.8のHello Worldの場合は以下のファイルが作られます。
sam-app/├── README.md├── __init__.py├── events # ローカル実行用のEvent│ └── event.json├── hello_world # Lambda本体のコード│ ├── __init__.py│ ├── app.py│ └── requirements.txt├── template.yaml # AWS SAMのテンプレート└── tests # テストコード├── __init__.py├── integration│ ├── __init__.py│ └── test_api_gateway.py├── requirements.txt└── unit├── __init__.py└── test_handler.py
Lambdaコード
Lambdaで実行されるhello_world/app.py
の中身は以下の通り。
import json# import requestsdef lambda_handler(event, context):"""Sample pure Lambda functionParameters----------event: dict, requiredAPI Gateway Lambda Proxy Input FormatEvent doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-formatcontext: object, requiredLambda Context runtime methods and attributesContext doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.htmlReturns------API Gateway Lambda Proxy Output Format: dictReturn doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html"""# try:# ip = requests.get("http://checkip.amazonaws.com/")# except requests.RequestException as e:# # Send some context about this error to Lambda Logs# print(e)# raise ereturn {"statusCode": 200,"body": json.dumps({"message": "hello world",# "location": ip.text.replace("\n", "")}),}
今回のサンプルはAPI Gatewayをトリガーとして実行し、レスポンスボディにメッセージを返すだけの簡単なコードです。
コードのコメントにも記載がありますが、lambda_handlerの引数、返り値はAPI Gatewayのフォーマットに合わせる必要があります。
SAMテンプレート
アプリケーションの構成を定義しているtemplate.yaml
の中身はこちら。
AWSTemplateFormatVersion: '2010-09-09'Transform: AWS::Serverless-2016-10-31Description: >sam-appSample SAM Template for sam-app# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rstGlobals:Function:Timeout: 3Resources:HelloWorldFunction:Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunctionProperties:CodeUri: hello_world/Handler: app.lambda_handlerRuntime: python3.8Events:HelloWorld:Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#apiProperties:Path: /helloMethod: getOutputs:# ServerlessRestApi is an implicit API created out of Events key under Serverless::Function# Find out more about other implicit resources you can reference within SAM# https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#apiHelloWorldApi:Description: "API Gateway endpoint URL for Prod stage for Hello World function"Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"HelloWorldFunction:Description: "Hello World Lambda Function ARN"Value: !GetAtt HelloWorldFunction.ArnHelloWorldFunctionIamRole:Description: "Implicit IAM Role created for Hello World function"Value: !GetAtt HelloWorldFunctionRole.Arn
基本的にはAWS CloudFormationのテンプレートと同じ構造でリソースを定義できますが、AWS SAMではTransform: AWS::Serverless-2016-10-31
が必要になります。
これを設定しておくことで、AWS SAMによる拡張をCloudFormation準拠のテンプレートに変換する処理を行っています。
アプリケーションのリソース定義はResourcesで行っています。
Lambda関数の作成にはAWS::Serverless::Function
を使用しており、LambdaとLambdaに関連するリソースをまとめて定義できます。
今回のサンプルではRuntimeでPython3.8が、EventsのTypeでApi(API Gateway)が指定されていることが確認できます。
ビルド
sam build
コマンドでアプリケーションをビルドします。
$ sam buildBuilding codeuri: /home/****/sam-app/hello_world runtime: python3.8 metadata: {} functions: ['HelloWorldFunction']Running PythonPipBuilder:ResolveDependenciesRunning PythonPipBuilder:CopySourceBuild SucceededBuilt Artifacts : .aws-sam/buildBuilt Template : .aws-sam/build/template.yamlCommands you can use next=========================[*] Invoke Function: sam local invoke[*] Deploy: sam deploy --guided
ビルドに成功すると.aws-sam/build
にアプリケーションの依存関係を含めたデプロイ用のファイルが作られます。
テスト
ローカルで実行するにはAWS Lambdaの実行環境を再現するためdockerイメージが使用されます。
sam local invoke
コマンドでLambdaをローカルで実行できます。
$ sam local invokeInvoking app.lambda_handler (python3.8)Image was not found.Building image.......................................................................................................................................................................................................................................................................Skip pulling image and use local one: amazon/aws-sam-cli-emulation-image-python3.8:rapid-1.22.0.Mounting /home/daisuke/sam-app/.aws-sam/build/HelloWorldFunction as /var/task:ro,delegated inside runtime containerSTART RequestId: e80b6598-1f4d-43d0-ab92-38c7482817d3 Version: $LATESTEND RequestId: e80b6598-1f4d-43d0-ab92-38c7482817d3REPORT RequestId: e80b6598-1f4d-43d0-ab92-38c7482817d3 Init Duration: 0.11 ms Duration: 60.86 ms Billed Duration: 100 msMemory Size: 128 MB Max Memory Used: 128 MB{"statusCode": 200, "body": "{\"message\": \"hello world\"}"}
レスポンスが正しく確認できました!
デプロイ
sam deploy
コマンドでアプリケーションをデプロイします。
--guided
オプションをつけることで、デプロイ設定を対話的に実行できます。
$ sam deploy --guidedConfiguring SAM deploy======================Looking for config file [samconfig.toml] : Not foundSetting default arguments for 'sam deploy'=========================================Stack Name [sam-app]:AWS Region [ap-northeast-1]:#Shows you resources changes to be deployed and require a 'Y' to initiate deployConfirm changes before deploy [y/N]: y#SAM needs permission to be able to create roles to connect to the resources in your templateAllow SAM CLI IAM role creation [Y/n]:HelloWorldFunction may not have authorization defined, Is this okay? [y/N]: ySave arguments to configuration file [Y/n]:SAM configuration file [samconfig.toml]:SAM configuration environment [default]:Looking for resources needed for deployment: Not found.Creating the required resources...Successfully created!Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-****A different default S3 bucket can be set in samconfig.toml~~~~(省略)
Save arguments to configuration file [Y/n]:
と聞かれるのでY
と答えておくと、デプロイ時の設定ファイルが作成されるので、次回からはsam deploy
のみでデプロイできます。
はじめてSAMを利用する場合は、S3のバケットを作成するCloudFormationが走ります。 これはビルドしたアプリケーションをアップロードするために使用されます。