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スタックの削除です。
最後までお読みいただきましてありがとうございました!
「AWS認定資格試験テキスト&問題集 AWS認定ソリューションアーキテクト - プロフェッショナル 改訂第2版」という本を書きました。

「AWS認定資格試験テキスト AWS認定クラウドプラクティショナー 改訂第3版」という本を書きました。

「ポケットスタディ AWS認定 デベロッパーアソシエイト [DVA-C02対応] 」という本を書きました。

「要点整理から攻略するAWS認定ソリューションアーキテクト-アソシエイト」という本を書きました。

「AWSではじめるLinux入門ガイド」という本を書きました。


開発ベンダー5年、ユーザ企業システム部門通算9年、ITインストラクター5年目でプロトタイプビルダーもやりだしたSoftware Engineerです。
質問はコメントかSNSなどからお気軽にどうぞ。
出来る限りなるべく答えます。
このブログの内容/発言の一切は個人の見解であり、所属する組織とは関係ありません。
このブログは経験したことなどの共有を目的としており、手順や結果などを保証するものではありません。
ご参考にされる際は、読者様自身のご判断にてご対応をお願いいたします。
また、勉強会やイベントのレポートは自分が気になったことをメモしたり、聞いて思ったことを書いていますので、登壇者の意見や発表内容ではありません。
ad
ad
関連記事
-
-
AWS GlueでAurora JDBC接続でS3へのジョブを実行
Aurora Serverless v1のMySQLタイプデータベースからS3へ …
-
-
「Getting started with AWS Glue DataBrew」をやってみました
AWS Glue DataBrewを体験してみたくて、開発者ガイドのチュートリア …
-
-
Backlogの実績工数をAmazon QuickSightでの可視化 – 仕組み編
Backlogの実績工数をAmazon QuickSightで可視化してわかった …
-
-
AWS X-Ray SDK for PythonをOrganizations組織内にLambda Layersで共有しました
ローカルでパッケージ作成 インストールコマンドはこちらAWS X-Ray SDK …
-
-
EC2 Image BuilderでRocket.ChatのAMIを作って起動テンプレートを更新しました
EC2 Image Builderの練習をしようと思い、Rocket.Chatの …
-
-
GoogleフォームからAPI Gatewayで作成したREST APIにPOSTリクエストする
「API GatewayからLambdaを介さずにSNSトピックへ送信」の続きで …
-
-
Amazon Connectから問い合わせ追跡レコード(CTR)をエクスポート
Amazon Connectから発信した電話に出たのか、出なかったのかを確認した …
-
-
IAM Access Analyzerの検出をEventBridgeルールで検知して通知する
やりたかったことは使用可能としているリージョンのIAM Access Analy …
-
-
Lambda関数をPython3.6から3.9に変更
CodeGuru ProfilerでLambda関数(Python 3.9)のパ …
-
-
AWS Lambda(Python3.7)でPandocを実行する際にCSSもLayerから読み込む
Pandocで必要そうなオプションを確認しておく 先日の「AWS Lambda( …