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 CDK とにかくサンプルでやってみる
Cloud9でAWS CDK環境で作った環境でサンプルプロジェクトからのデプロイ …
-
Amazon Timestreamのサンプルデータベースを起動しました
マネジメントコンソールTimestreamにアクセスして、[データベースを作成] …
-
Amazon S3オブジェクトロック
S3のオブジェクトロックを確認しました。 オブジェクトロックの有効化 現在、既存 …
-
AWSのサービス数を数えてみました(2020/5/23)
何をもってサービスという単位にするかというのはあるかもしれませんが、とりあえず情 …
-
AWS Service CatalogポートフォリオをOrganizations組織で共有する
AWS Service Catalogチュートリアルで作成したポートフォリオのO …
-
Amazon Linux 2023からAWS CLIをアンインストールする
AWS CLIのない検証用EC2 Linuxが欲しかったのでアンインストールしま …
-
AWS Toolkit for Eclipseをセットアップする
AWSでそろそろ課金がされつつありますので、夜中はインスタンスを自動停止して朝自 …
-
AWS Control TowerにOUを追加する
AWS Control TowerにOUを追加する 管理アカウントでAWS Co …
-
Amazon LinuxのNginx+RDS MySQLにレンタルWebサーバーからWordPressを移設する(失敗、手戻りそのまま記載版)
勉強のためブログサイトを長らくお世話になったロリポップさんから、AWSに移設する …
-
AWS CDKでリージョンをまたいだクロススタックリファレンスはできなかった
例えばこんなコードが実行できるかというと、 [crayon-678b5a68c8 …