こんにちは、株式会社カミナシのエンジニア @Taku です。
前回、GolangでLambda Authorizer用関数をやってみましたが、 Golangはコードエディタが使えず、テストするには毎回zipで固めてアップするという一手間がありました。 kaminashi-developer.hatenablog.jp
そんな中、先日「AWS SAMを使うとAPI Gateway等とまとめて作成できるので便利だよ!」という話を伺ったので今回使ってみることとしました。
AWS SAMとは
YAMLで記載したテンプレートを利用して、CLIにてサーバーレスのアプリケーションを構築できるオープンソースフレームワークです。
例として、以下のようなYAMLを作成することでサーバーレスのアプリケーションを構築できます。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > sam-app Sample SAM Template for sam-app # More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst Globals: Function: Timeout: 3 Resources: HelloWorldFunction: Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.7 Events: HelloWorld: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /hello Method: get Outputs: # 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#api HelloWorldApi: 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.Arn HelloWorldFunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt HelloWorldFunctionRole.Arn
(チュートリアルでsam init
した際に作成されるもの)
利用するメリットとして、
- サーバーレスのアプリケーションの一元管理
- Lambdaに似た実行環境をローカルに構築することができるので、テストのために逐一アップロードするという手間が省ける
ということがあると思います。
CloudFormation の拡張機能であるとのことで、同じように記載ができるので、そちらに馴染みがある方は比較的簡単に利用できるのではないかと思われます(ただし、AWS SAMはJSONでの記載は不可でYAMLのみ)
詳細なテンプレートの記載方法については以下をご参照ください。
AWS SAM CLIのインストール
AWS SAMを利用するにはまずCLIをインストールする必要があります。
前提としてAWSアカウントや、ローカルで起動するためにはDockerのインストールが必要となりますので、以下を参照してご自身の環境に合わせてセットアップください。
前回やったサーバーレスアプリケーションをSAMで構築
続いて、早速ですが前回作成したものをSAMテンプレートを利用して作成していきます。
軽いおさらいとして、前回の構成は以下です。
今回はこの中から、
をAWS SAMで構築していきます。
詳細は省きますが、チュートリアルや以下の公式ドキュメントを参考に設定しました、
LambdaAuthorizerの設定 docs.aws.amazon.com
Lambda関数の作成 docs.aws.amazon.com
※日本語版のドキュメントは作成されておらず自動翻訳となっているため、読んでてわかりづらい箇所は英語のまま読む方が良いと感じました。
今回実際に作成したテンプレートは以下です。
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Sample API Gateway Lambda Authorizer by Golang. Resources: # API Gatewayの作成 SampleRestApi: Type: AWS::Serverless::Api Properties: StageName: dev Description: "This is Sample Rest API" Cors: AllowMethods: "'GET, OPTIONS'" AllowHeaders: "'*'" AllowOrigin: "'*'" Auth: DefaultAuthorizer: MyLambdaAuthorizerFunction Authorizers: MyLambdaAuthorizerFunction: FunctionArn: !GetAtt LambdaAuthorizerFunction.Arn # API Gatewayのレスポンス作成 ApiFunction: Type: AWS::Serverless::Function Properties: Events: ApiEvent: Type: Api Properties: Path: / Method: get RestApiId: Ref: SampleRestApi Runtime: python3.7 Handler: index.handler InlineCode: | def handler(event, context): return {'body': 'Hello World!', 'statusCode': 200} # LambdaAuthorizer用の関数の作成 LambdaAuthorizerFunction: Type: AWS::Serverless::Function Properties: FunctionName: samAuth CodeUri: ./lambda_auth # buildされるが、configがアップされなかったので、`/build/関数名`のディレクトリに手動で配置 Handler: app.lambda_handler Runtime: go1.x # SAMでdeployした後、コンソールに表示するもの(URL表示したり) Outputs: SampleRestApi: Description: "Sample API Gateway Lambda Authorizer by Golang." Value: !Sub "https://${SampleRestApi}.execute-api.${AWS::Region}.amazonaws.com/dev/"
前回とちょっと違う点として、API GatewayのエンドポイントにMockを指定する方法を見つけられなかったのでLambda Fanctionを利用して簡単なレスポンスを返す関数を置いてみました。
# API Gatewayのレスポンス作成 ApiFunction: Type: AWS::Serverless::Function Properties: Events: ApiEvent: Type: Api Properties: Path: / Method: get RestApiId: Ref: SampleRestApi Runtime: python3.7 Handler: index.handler InlineCode: | def handler(event, context): return {'body': 'Hello World!', 'statusCode': 200}
チュートリアルのサンプルを元にしたものですが、SAMであればこれもサクッと追加できるのが良いですね。
ビルド & デプロイ
テンプレートの作成が完了しましたら、ビルド及びデプロイをやっていきます。
ビルド
ビルドは作成したテンプレートが存在するディレクトリで sam build
コマンドを実行します。
-> % sam build Building codeuri: /Users/takuya/dev/new_technology_learning/lambda/sam/api-gateway-authorizer-golang/lambda_auth runtime: go1.x metadata: {} functions: ['LambdaAuthorizerFunction'] Running GoModulesBuilder:Build Build Succeeded Built Artifacts : .aws-sam/build Built Template : .aws-sam/build/template.yaml Commands you can use next ========================= [*] Invoke Function: sam local invoke [*] Deploy: sam deploy --guided
ハマったポイントとして、前回はLambdaAuthorizer用のファイルはzipでまとめてアップすれば良かったのですが、SAMですと設定が悪いのかビルドするディレクトリを指定してもその中のconfigがアップされませんでした。 (ビルド&デプロイはできるが、Lambda関数実行する際にconfigが指定箇所に存在しないエラーとなる)
# LambdaAuthorizer用の関数の作成 LambdaAuthorizerFunction: Type: AWS::Serverless::Function Properties: FunctionName: samAuth CodeUri: ./lambda_auth # buildされるが、configがアップされなかったので、`/build/関数名`のディレクトリに手動で配置 Handler: app.lambda_handler Runtime: go1.x
そのため今回は、デプロイ前にビルド後作成された .aws-sam/build
ディレクトリ配下の、生成されたLambda関数のディレクトリに手動でconfigを配置することで対応しました。
-> % tree -a . . ├── .aws-sam │ ├── build │ │ ├── LambdaAuthorizerFunction │ │ │ ├── app.lambda_handler │ │ │ └── config │ │ │ └── jwt-lambda-auth-firebase-adminsdk-3sa6r-c2e0d97f93.json // ここに手動で配置 │ │ └── template.yaml │ └── build.toml ├── lambda_auth │ ├── config │ │ └── jwt-lambda-auth-firebase-adminsdk-3sa6r-c2e0d97f93.json │ ├── go.mod │ ├── go.sum │ └── main.go ├── samconfig.toml ├── template.yaml └── web ├── js │ └── config.js ├── login.html └── pets.html
デプロイ
ビルドが完了しましたら同じディレクトリで sam deploy --guided
コマンドを実行します。
-> % sam deploy --guided Configuring SAM deploy ====================== Looking for config file [samconfig.toml] : Found Reading default arguments : Success Setting default arguments for 'sam deploy' ========================================= Stack Name [sample-auth]: AWS Region [ap-northeast-1]: #Shows you resources changes to be deployed and require a 'Y' to initiate deploy Confirm changes before deploy [Y/n]: Y #SAM needs permission to be able to create roles to connect to the resources in your template Allow SAM CLI IAM role creation [Y/n]: Y Save arguments to configuration file [Y/n]: Y SAM configuration file [samconfig.toml]: SAM configuration environment [default]: Looking for resources needed for deployment: Found! ... CloudFormation outputs from deployed stack ------------------------------------------------------------------------------------------------- Outputs ------------------------------------------------------------------------------------------------- Key SampleRestApi Description Sample API Gateway Lambda Authorizer by Golang. Value https://x7ow8vkh09.execute-api.ap-northeast-1.amazonaws.com/dev/ ------------------------------------------------------------------------------------------------- Successfully created/updated stack - sample-auth in ap-northeast-1
正常に終了した場合、AWS(API Gateway、CloudFormation、Lambda)を確認するとリソースが追加されているかと思います。
ローカルで起動
ローカルでテストしたい場合、ビルド完了後 sam local start-api
コマンドでDockerを利用したシミュレーターを起動してテストすることができます。
-> % sam local start-api Mounting ApiFunction at http://127.0.0.1:3000/ [GET, OPTIONS] You can now browse to the above endpoints to invoke your functions. You do not need to restart/reload SAM CLI while working on your functions, changes will be reflected instantly/automatically. You only need to restart SAM CLI if you update your AWS SAM template 2021-03-30 08:33:52 * Running on http://127.0.0.1:3000/ (Press CTRL+C to quit)
テストをしながらLambda関数を作成する場合これは便利かと思います。
おわりに
AWS SAMを使ってみて、私自身まだLambda関数やCloudFormationに慣れていないこともあり、最初はテンプレート作成に時間がかかりましたが、慣れてしまうとまとめての構築やローカルでテストができるため便利なものかと思いました。
また、サーバーレスアプリケーションを構築するには、 Serverless Framework というツールもあるとこことのため、こちらも時間がある際に試してみたいと考えてます。
(Freeのオープンソース版と有料のPro版があり)
最後までご覧いただきありがとうございました。
不備やこうした方が良いよ!というのがあればコメント等いただけると幸いです。