Cloud9でSAMローカルテスト
2022/02/10
せっかくテストするので、Amazon CloudSearchからAmazon Elasticsearch Serviceへ変えましたで作った、トレーニングコースを全文検索するLambdaでテストしてみようと思います。
目次
Cloud9
Cloud9はデフォルトのままでインスタンスタイプだけ、t3.nanoで作成しました。
1 2 3 |
$ sam --version SAM CLI, version 0.38.0 |
samのバージョンを確認すると、0.38でした。
SAMアプリケーション作成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
$ sam init Which template source would you like to use? 1 - AWS Quick Start Templates 2 - Custom Template Location Choice: 1 Which runtime would you like to use? 1 - nodejs12.x 2 - python3.8 3 - ruby2.5 4 - go1.x 5 - java11 6 - dotnetcore2.1 7 - nodejs10.x 8 - nodejs8.10 9 - python3.7 10 - python3.6 11 - python2.7 12 - java8 13 - dotnetcore2.0 14 - dotnetcore1.0 Runtime: 10 Project name [sam-app]: demo-app Quick start templates may have been updated. Do you want to re-download the latest [Y/n]: Y AWS quick start application templates: 1 - Hello World Example 2 - EventBridge Hello World 3 - EventBridge App from scratch (100+ Event Schemas) Template selection: 1 ----------------------- Generating application: ----------------------- Name: demo-app Runtime: python3.8 Dependency Manager: pip Application Template: hello-world Output Directory: . Next steps can be found in the README file at ./demo-app/README.md |
python3.6で、Hello World Exampleのテンプレートにしました。
3.6にしたのは、Cloud9のPythonのバージョンが3.6でしたのであわせました。
Swagger
API Gatewayの定義を記述しているSwaggerは、API Gateway 作成済REST APIの定義をSwaggerの形式でエクスポートでエクスポートしたSwaggerを基にしました。
変更したのは、x-amazon-apigateway-integration: のuri:です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
swagger: "2.0" info: version: "1.0.0" title: "coursesearch" basePath: "/Prod" schemes: - "https" paths: /search: get: consumes: - "application/json" produces: - "application/json" parameters: - name: "query" in: "query" required: false type: "string" responses: 200: description: "200 response" schema: $ref: "#/definitions/Empty" headers: Access-Control-Allow-Origin: type: "string" x-amazon-apigateway-integration: uri: Fn::Sub: arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${SearchFunction.Arn}/invocations responses: default: statusCode: "200" responseParameters: method.response.header.Access-Control-Allow-Origin: "'*'" requestTemplates: application/json: "{\n \"query\": \"$input.params('query')\"\n}" passthroughBehavior: "when_no_templates" httpMethod: "POST" contentHandling: "CONVERT_TO_TEXT" type: "aws" options: consumes: - "application/json" produces: - "application/json" responses: 200: description: "200 response" schema: $ref: "#/definitions/Empty" headers: Access-Control-Allow-Origin: type: "string" Access-Control-Allow-Methods: type: "string" Access-Control-Allow-Headers: type: "string" x-amazon-apigateway-integration: responses: default: statusCode: "200" responseParameters: method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'" method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" method.response.header.Access-Control-Allow-Origin: "'*'" requestTemplates: application/json: "{\"statusCode\": 200}" passthroughBehavior: "when_no_match" type: "mock" definitions: Empty: type: "object" title: "Empty Schema" |
用意したSwaggerファイルを任意のS3バケットにアップロードしておきます。
修正
必要最低限の箇所だけ修正しています。
requirements.txt
1 2 3 |
elasticsearch requests_aws4auth |
2つのモジュールを含めるようにしました。
hello_world/app.py
以下に置き換えました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
import traceback import logging.config import boto3 import os from elasticsearch import Elasticsearch, RequestsHttpConnection, helpers from requests_aws4auth import AWS4Auth logger = logging.getLogger() logger.setLevel(logging.INFO) ENDPOINT = os.environ.get('ENDPOINT', '') REGION = os.environ.get('REGION', '') def lambda_handler(event, context): try: logger.info(event) if ('queryStringParameters' in event): query_keyword = event['queryStringParameters']['query'] else: query_keyword = event['query'] awsauth = AWS4Auth( os.environ.get('AWS_ACCESS_KEY_ID', ''), os.environ.get('AWS_SECRET_ACCESS_KEY', ''), REGION, 'es', session_token=os.environ['AWS_SESSION_TOKEN'] ) es = Elasticsearch( hosts=[{ 'host': ENDPOINT, 'port': 443 }], http_auth=awsauth, use_ssl=True, verify_certs=True, connection_class=RequestsHttpConnection, timeout=1500 ) response = es.search( index="course_index", body={ "query": { "match": { 'name': query_keyword } } } ) logger.debug(response) return { 'statusCode': 200, 'body': response } except: logger.error(traceback.format_exc()) |
template.yaml
1 2 3 4 5 6 7 8 9 |
Globals: Function: Timeout: 3 Environment: Variables: ENDPOINT: ES_ENDPOINT REGION: ap-northeast-1 TZ: Asia/Tokyo |
環境変数を追加しました。
ElasticSearchのエンドポイントやリージョンを指定しました。
1 2 3 4 5 6 7 8 9 10 11 |
Resources: SearchApi: Type: AWS::Serverless::Api Properties: StageName: Prod DefinitionBody: Fn::Transform: Name: AWS::Include Parameters: Location: s3://swagger-bucekt/swagger.yaml |
ResourcesにAPIの定義をSwaggerを参照するように追記しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
SearchFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.6 FunctionName: DemoFunction Role: arn:aws:iam::123456789012:role/RoleName Layers: - arn:aws:lambda:ap-northeast-1:123456789012:layer:my-layer:1 Events: HelloWorld: Type: Api Properties: Path: /search Method: get RestApiId: !Ref SearchApi |
LambdaFunctionのセクションをこちらに変更しました。
IAMロールとLayersはあらかじめ作成済のものを指定しました。
sam build
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
$ sam build Building resource 'SearchFunction' Running PythonPipBuilder:ResolveDependencies Running PythonPipBuilder:CopySource 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 |
成功しました。
このとき、ローカルとランタイムのPythonのバージョンがあっていないと以下のエラーになりました。
1 2 3 |
Build Failed Error: PythonPipBuilder:None - Binary validation failed! |
sam local start-api
Cloud9ローカルでテストをします。
1 2 |
$ sam local start-api |
API Gatewyの設定は反映されないようで、lambdaに対してそのまま実行するAPIのようです。
ですので、responseにはステータスコードが必要でした。
また、統合リクエストのマッピングもしてないので、eventにqueryStringParametersが含まれるかどうかで判定しています。
もっといいやり方があるかもしれません。
別のターミナルを開いて、curlコマンドでGETしてみます。
1 2 |
$ curl http://127.0.0.1:3000/search?query=python |
成功しました。
以下のようなレスポンスが返ってきました。
1 2 3 |
{'took': 4, 'timed_out': False, '_shards': {'total': 5, 'successful': 5, 'skipped': 0, 'failed': 0}, 'hits': {'total': 4, 'max_score': 6.7389565, 'hits': [{'_index': 'course_index', '_type': 'course', '_id': 'PRC0092G', '_score': 6.7389565, '_source': {'name': 'Pythonプログラミング入門(PRC0092G)'}}, {'_index': 'course_index', '_type': 'course', '_id': 'PRC0104G', '_score': 5.4415946, '_source': {'name': 'Pythonプログラミング2 オブジェクト指向編(PRC0104G)'}}, {'_index': 'course_index', '_type': 'course', '_id': 'PRC0103G', '_score': 5.2457385, '_source': {'name': 'Pythonプログラミング1 基本文法編(PRC0103G)'}}, {'_index': 'course_index', '_type': 'course', '_id': 'PRC0110G', '_score': 4.6417665, '_source': {'name': 'インフラエンジニアをめざす新入社員のためのPython初級(PRC0110G |
sam deploy
デプロイしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
$ sam deploy --guided Configuring SAM deploy ====================== Looking for samconfig.toml : Found Reading default arguments : Success Setting default arguments for 'sam deploy' ========================================= Stack Name [demo-app]: AWS Region [us-east-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 samconfig.toml [Y/n]: Y Looking for resources needed for deployment: Found! Managed S3 bucket: aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxx A different default S3 bucket can be set in samconfig.toml Saved arguments to config file Running 'sam deploy' for future deployments will use the parameters saved above. The above parameters can be changed by modifying samconfig.toml Learn more about samconfig.toml syntax at https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html Deploying with following values =============================== Stack name : demo-app Region : ap-northeast-1 Confirm changeset : True Deployment s3 bucket : aws-sam-cli-managed-default-samclisourcebucket-xxxxxxxx Capabilities : ["CAPABILITY_IAM"] Parameter overrides : {} Initiating deployment ===================== Uploading to demo-app/xxxxxxxxxxxx 688001 / 688001.0 (100.00%) Uploading to demo-app/xxxxxxxxxxxx.template 1571 / 1571.0 (100.00%) Waiting for changeset to be created.. CloudFormation stack changeset --------------------------------------------------------------------------------------------------------------------- Operation LogicalResourceId ResourceType --------------------------------------------------------------------------------------------------------------------- + Add SearchApiDeployment7ca385d720 AWS::ApiGateway::Deployment + Add SearchApiProdStage AWS::ApiGateway::Stage + Add SearchApi AWS::ApiGateway::RestApi + Add SearchFunctionHelloWorldPermissionPro AWS::Lambda::Permission d + Add SearchFunction AWS::Lambda::Function --------------------------------------------------------------------------------------------------------------------- Changeset created successfully. arn:aws:cloudformation:ap-northeast-1:123456789012:changeSet/~省略~ Previewing CloudFormation changeset before deployment ====================================================== Deploy this changeset? [y/N]: y 2020-05-19 04:54:49 - Waiting for stack create/update to complete CloudFormation events from changeset --------------------------------------------------------------------------------------------------------------------- ResourceStatus ResourceType LogicalResourceId ResourceStatusReason --------------------------------------------------------------------------------------------------------------------- CREATE_IN_PROGRESS AWS::Lambda::Function SearchFunction - CREATE_IN_PROGRESS AWS::Lambda::Function SearchFunction Resource creation Initiated CREATE_COMPLETE AWS::Lambda::Function SearchFunction - CREATE_IN_PROGRESS AWS::ApiGateway::RestApi SearchApi - CREATE_IN_PROGRESS AWS::ApiGateway::RestApi SearchApi Resource creation Initiated CREATE_COMPLETE AWS::ApiGateway::RestApi SearchApi - CREATE_IN_PROGRESS AWS::ApiGateway::Deployment SearchApiDeployment7ca385d7 - 20 CREATE_IN_PROGRESS AWS::Lambda::Permission SearchFunctionHelloWorldPer Resource creation Initiated missionProd CREATE_IN_PROGRESS AWS::Lambda::Permission SearchFunctionHelloWorldPer - missionProd CREATE_COMPLETE AWS::ApiGateway::Deployment SearchApiDeployment7ca385d7 - 20 CREATE_IN_PROGRESS AWS::ApiGateway::Deployment SearchApiDeployment7ca385d7 Resource creation Initiated 20 CREATE_IN_PROGRESS AWS::ApiGateway::Stage SearchApiProdStage - CREATE_IN_PROGRESS AWS::ApiGateway::Stage SearchApiProdStage Resource creation Initiated CREATE_COMPLETE AWS::ApiGateway::Stage SearchApiProdStage - CREATE_COMPLETE AWS::Lambda::Permission SearchFunctionHelloWorldPer - missionProd CREATE_COMPLETE AWS::CloudFormation::Stack demo-app - --------------------------------------------------------------------------------------------------------------------- Successfully created/updated stack - demo-app in ap-northeast-1 |
デプロイ完了後、APIエンドポイントにcurlコマンドでgetリクエストしてみて、ローカルテストと同じ結果を確認できました。
削除はCloudFormationスタックの削除です。
最後までお読みいただきましてありがとうございました!
【PR】 「AWS認定試験対策 AWS クラウドプラクティショナー」という本を書きました。
【PR】 「AWSではじめるLinux入門ガイド」という本を書きました。
【PR】 「ポケットスタディ AWS認定 デベロッパーアソシエイト」という本を書きました。
【PR】 「AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル」という本を書きました。

開発ベンダー5年、ユーザ企業システム部門通算9年、ITインストラクター5年目でプロトタイプビルダーもやりだしたSoftware Engineerです。
質問はコメントかSNSなどからお気軽にどうぞ。
出来る限りなるべく答えます。
このブログの内容/発言の一切は個人の見解であり、所属する組織とは関係ありません。
このブログは経験したことなどの共有を目的としており、手順や結果などを保証するものではありません。
ご参考にされる際は、読者様自身のご判断にてご対応をお願いいたします。
また、勉強会やイベントのレポートは自分が気になったことをメモしたり、聞いて思ったことを書いていますので、登壇者の意見や発表内容ではありません。
ad
ad
関連記事
-
-
AWS Service Catalogポートフォリオを他のアカウントと共有する
AWS Service Catalogチュートリアルで作成したポートフォリオの他 …
-
-
AWS Systems Manager AutomationでEC2の自動停止
Systems Manager Automationがない時代に、Lambdaを …
-
-
kintone webhookからAWS API Gateway – Lambdaを実行しレコードの値を渡す
2017年2月のアップデートでkintoneにWebhook機能がリリースされま …
-
-
AWSのサービス数を数えてみました(2020/5/23)
何をもってサービスという単位にするかというのはあるかもしれませんが、とりあえず情 …
-
-
Amazon EC2 Auto Scalingのライフサイクルフック
EC2 Auto Scalingにライフサイクルフックという機能があります。 ス …
-
-
Amazon Rekognitionでイベント参加者の顔写真を解析して似ている人ランキングをその場で作る
2017/9/21に開催されたAWS Cloud Roadshow 2017 大 …
-
-
RDSの拡張モニタリングを有効にしました
RDS for MySQLです。 変更メニューで、[拡張モニタリングを有効にする …
-
-
Amazon VPCでIPv6を使用する
VPCのIPv6を設定してみました。 設定 [Amazon 提供の IPv6 C …
-
-
サービスディスカバリを使用してECSサービスの作成
ECSデベロッパーガイドのチュートリアル:サービスディスカバリを使用して、サービ …
-
-
SCPが影響しないサービスにリンクされたロールにEC2が引き受けるIAMロールは含まれないことを確認
ドキュメントで確認 サービスコントロールポリシーのユーザーガイドには、「SCPは …