AWSコマンドラインインターフェース(AWS CLI)でAPI Gateway+AWS Lambdaを構築してみる
AWS CLIは、コマンドラインからAWSサービスを制御し、スクリプトを使用してこれらを自動化することができる。
AWS CLIの設定
インストール
ここからWindows用のインストーラを入手するか、Pythonのpipでインストールする(pip install awscli
)。
ただし、AWS CLIはすごい頻度でバージョンアップするため、pipでの導入がオススメ。
バージョンアップはpip install --upgrade awscli
で行う。
ここではWindowsで実施する。
キーの設定
インストールしたら「aws configure」コマンドでアクセスキー、シークレットキーを設定する。
$ aws configure AWS Access Key ID [None]: XXXXXXXXXXXXXXXXXXX AWS Secret Access Key [None]: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX Default region name [None]: ap-northeast-1 Default output format [None]: ENTER
使い方
リファレンスはここ。
基本的には下記のように使用できる。
aws [options] <command> <subcommand> [parameters]
「command」にAWSのサービス名(lambdaなど)を、「subcommand」にサービスに対する操作(create-functionなど)を入力する。
わからないときは最後に「help」をつけてコマンド実行すればリファレンスが表示される。
ARNについて
ARNはAmazon Resource Nameの略でAWSリソースを一意に識別する値。
下記のフォーマットになる。
arn:partition:service:region:account-id:resource
arn:partition:service:region:account-id:resourcetype/resource
arn:partition:service:region:account-id:resourcetype:resource
- partition
- リソースが配置されるパーティション
- 標準のAWSリージョンの場合、パーティションは「aws」
- service
- AWSのサービス名
- 「apigateway」や「ec2」など
- https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html#genref-aws-service-namespaces
- region
- リソースが配置されるリージョン
- 東京リージョンであれば「ap-northeast-1」
- http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-regions-availability-zones.html
- account-id
- リソースを保有しているアカウントID(数字のみ)
- 一部のARNはこのアカウント番号を必要としないため省略される
- 「resource」「resourcetype/resource」「resourcetype/resource」
- サービスにより様々
- リソースタイプの指標(IAMユーザやRDSなど)が含まれることがよくある
- さらにスラッシュ(/)またはコロン(:)、リソース名自体が続く
- 一部のサービスではパス(ファイルパス、URIなど)を指定できる(ARNのパス)
- https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html#arns-paths
https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html
API Gateway + AWS Lambda の作成
API Gateway + AWS LambdaをAWS CLIで構築して、GETメソッドでテストするところまで行う。
以下の順で行う。
- AWS Lambdaの作成
- API Gatewayの作成
- APIの作成
- リソース(パス)の作成
- HTTPメソッドの作成
- AWS LambdaとAPI Gatewayの連携設定
- APIのリソースとLambdaの関連付け
- AWS LambdaからAPI Gatewayへのレスポンスを作成
- API GatewayのメソッドにLambda関数の実行権限付与
- API Gatewayのメソッドのレスポンスを作成
- 設定したAPI Gateway + AWS Lambdaのテスト
- APIのデプロイ
- APIの確認
以降の作成手順ではいろいろと流出するとマズいID周りは以下のようにマスクしています。
- AWSアカウントID
- [account-id]
- 実行ロール
- [exec-role-name]
- 作成したAPIのID(rest-api-id)
- [rest-api-id]
- 作成したAPIのルートパスのID
- [rest-api-root-path-id]
- APIに追加するパス(cliPathSample)のID
- [rest-api-cliPathSample-path-id]
- デプロイのID
- [deployment-id]
- その他
- xxx
1.AWS Lambdaの作成
AWS LambdaにLambda関数を作成する。
Lambda関数名は「cliLambdaSample」、ランタイムは「java8」で作成する。
実行のロールについてはあらかじめ作成しておいて、「aws iam list-roles」コマンドで表示されたものから選ぶ。
aws lambda create-function^ --function-name cliLambdaSample^ --runtime java8^ --role arn:aws:iam::[account-id]:role/[exec-role-name]^ --handler org.sample.handler.PersonHandler::getPerson^ --zip-file fileb://LambdaSample-1.0-SNAPSHOT.jar
{ "CodeSha256": "xxx", "FunctionName": "cliLambdaSample", "CodeSize": 506685, "MemorySize": 128, "FunctionArn": "arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample", "Version": "$LATEST", "Role": "arn:aws:iam::[account-id]:role/[exec-role-name]", "Timeout": 3, "LastModified": "2016-02-03T07:54:00.319+0000", "Handler": "org.sample.handler.PersonHandler::getPerson", "Runtime": "java8", "Description": "" }
作成したLambda関数の確認。
aws lambda get-function^
--function-name cliLambdaSample
{ "Code": { "RepositoryType": "S3", "Location": "https://awslambda-ap-ne-1-tasks.s3-ap-northeast-1.amazonaws.com/snapshots/[account-id]/cliLambdaSample-xxx" }, "Configuration": { "Version": "$LATEST", "CodeSha256": "xxx", "FunctionName": "cliLambdaSample", "MemorySize": 128, "CodeSize": 506685, "FunctionArn": "arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample", "Handler": "org.sample.handler.PersonHandler::getPerson", "Role": "arn:aws:iam::[account-id]:role/[exec-role-name]", "Timeout": 3, "LastModified": "2016-02-03T07:54:00.319+0000", "Runtime": "java8", "Description": "" } }
2.API Gatewayの作成
2.1.APIの作成
API GatewayにAPIを作成する。
aws apigateway create-rest-api^
--name cliApiSample
{ "name": "cliApiSample", "id": "[rest-api-id]", "createdDate": 1454486286 }
作成したAPIの確認。
aws apigateway get-resources^ --rest-api-id [rest-api-id]
{ "items": [ { "path": "/", "id": "[rest-api-root-path-id]" } ] }
作成したAPIにはルートパスのリソースが作成されていることがわかる。
2.2.リソース(パス)の作成
作成したAPIに対してパスを追加する。
親(parent-id)はAPIのルートパスリソースを指定する。
aws apigateway create-resource^ --rest-api-id [rest-api-id]^ --parent-id [rest-api-root-path-id]^ --path-part cliPathSample
{ "path": "/cliPathSample", "pathPart": "cliPathSample", "id": "[rest-api-cliPathSample-path-id]", "parentId": "[rest-api-root-path-id]" }
作成したリソースを確認コマンド。
aws apigateway get-resource^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]
{ "path": "/cliPathSample", "pathPart": "cliPathSample", "id": "[rest-api-cliPathSample-path-id]", "parentId": "[rest-api-root-path-id]" }
2.3.APIのメソッドを作成
APIの「/cliPathSample」リソースに対してGETメソッドを作成する。
aws apigateway put-method^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET^ --authorization-type NONE
{ "apiKeyRequired": false, "httpMethod": "GET", "authorizationType": "NONE" }
作成したメソッドの確認。
aws apigateway get-method^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET
{ "apiKeyRequired": false, "httpMethod": "GET", "authorizationType": "NONE" }
3.AWS LambdaとAPI Gatewayの連携設定
3.1.APIのリソースとLambdaの関連付け
cliPathSampleリソースとLambda関数を作成したHTTPのGETメソッドで関連付ける。
ただし、API GatewayからAWS LambdaへはPOSTで連携することに注意。
また、uriは
「arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/[Lambda関数のARN]/invocations」
の形式で指定する。
「2015-03-31」という日付はおそらくAWS CLIに「aws lambda」コマンド実装されたリリース日(Release: AWS CLI 1.8.12)。
aws apigateway put-integration^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET^ --type AWS^ --integration-http-method POST^ --uri arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample/invocations
{ "httpMethod": "POST", "cacheKeyParameters": [], "type": "AWS", "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample/invocations", "cacheNamespace": "[rest-api-cliPathSample-path-id]" }
作成した連携設定を確認。
aws apigateway get-integration^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET
{ "httpMethod": "POST", "cacheKeyParameters": [], "type": "AWS", "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample/invocations", "cacheNamespace": "[rest-api-cliPathSample-path-id]" }
3.2.AWS LambdaからAPI Gatewayへのレスポンスを作成
GETのHTTPレスポンスをステータス200のときはJSONで設定。
aws apigateway put-integration-response^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET^ --status-code 200^ --response-templates {\"application/json\":\"\"}
{ "statusCode": "200", "responseTemplates": { "application/json": null } }
作成したレスポンスを確認。
aws apigateway get-integration-response^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET^ --status-code 200
{ "statusCode": "200", "responseTemplates": { "application/json": null } }
1つ上のレイヤでも確認。
aws apigateway get-integration^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET
{ "httpMethod": "POST", "integrationResponses": { "200": { "responseTemplates": { "application/json": null }, "statusCode": "200" } }, "cacheKeyParameters": [], "type": "AWS", "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample/invocations", "cacheNamespace": "[rest-api-cliPathSample-path-id]" }
3.3.API GatewayのメソッドにLambda関数の実行権限付与
cliPathSampleリソースのGETメソッドに対してLambda関数の実行権限を付与する。
statement-idは32桁で適当に作成。(ここでは、12345678901234567890123456789012)
source-arnは
「arn:aws:execute-api:ap-northeast-1:[account-id]:[rest-api-id]/[ステージ名]/[HTTPメソッド]/[リソース名]」
の形式。
aws lambda add-permission^ --function-name cliLambdaSample^ --statement-id 12345678901234567890123456789012^ --action lambda:InvokeFunction^ --principal apigateway.amazonaws.com^ --source-arn arn:aws:execute-api:ap-northeast-1:[account-id]:[rest-api-id]/test/GET/cliPathSample
{ "Statement": "{ \"Condition\":{ \"ArnLike\":{ \"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:[account-id]:[rest-api-id]/*/GET/cliPathSample\" } }, \"Action\":[\"lambda:InvokeFunction\"], \"Resource\":\"arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample\", \"Effect\":\"Allow\", \"Principal\":{ \"Service\":\"apigateway.amazonaws.com\" }, \"Sid\":\"12345678901234567890123456789012\" }" }
設定した実行権限の確認。
aws lambda get-policy^
--function-name cliLambdaSample
{ "Policy": "{ \"Version\":\"2012-10-17\", \"Statement\":[ { \"Condition\":{ \"ArnLike\":{ \"AWS:SourceArn\":\"arn:aws:execute-api:ap-northeast-1:[account-id]:[rest-api-id]/*/GET/cliPathSample\" } }, \"Action\":\"lambda:InvokeFunction\", \"Resource\":\"arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample\", \"Effect\":\"Allow\",\"Principal\":{ \"Service\":\"apigateway.amazonaws.com\" }, \"Sid\":\"12345678901234567890123456789012\" } ], \"Id\":\"default\" }" }
3.4.API Gatewayのメソッドのレスポンスを作成
aws apigateway put-method-response^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET^ --status-code 200^ --response-models {\"application/json\":\"Empty\"}
{ "responseModels": { "application/json": "Empty" }, "statusCode": "200" }
作成したレスポンスの確認。
aws apigateway get-method^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET
{ "apiKeyRequired": false, "httpMethod": "GET", "methodIntegration": { "integrationResponses": { "200": { "responseTemplates": { "application/json": null }, "statusCode": "200" } }, "cacheKeyParameters": [], "uri": "arn:aws:apigateway:ap-northeast-1:lambda:path/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample/invocations", "httpMethod": "POST", "cacheNamespace": "[rest-api-cliPathSample-path-id]", "type": "AWS" }, "methodResponses": { "200": { "responseModels": { "application/json": "Empty" }, "statusCode": "200" } }, "authorizationType": "NONE" }
4.設定したAPI Gateway + AWS Lambdaのテスト
aws apigateway test-invoke-method^ --rest-api-id [rest-api-id]^ --resource-id [rest-api-cliPathSample-path-id]^ --http-method GET^ --path-with-query-string ""
{ "status": 200, "body": "{\"name\":\"Taro\",\"age\":20}", "log": "Execution log for request test-request\n Wed Feb 03 08:21:49 UTC 2016 : Starting execution for request: test-invoke-request\n Wed Feb 03 08:21:49 UTC2016 : API Key: test-invoke-api-key\n Wed Feb 03 08:21:49 UTC 2016 : Method request path: {}\n Wed Feb 03 08:21:49 UTC 2016 : Method request query string: {}\n Wed Feb 03 08:21:49 UTC 2016 : Method request headers: {}\n Wed Feb 03 08:21:49 UTC 2016 : Method request body before transformations: null\n Wed Feb 03 08:21:49 UTC 2016 : Endpoint request URI: https://lambda.ap-northeast-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:ap-northeast-1:[account-id]:function:cliLambdaSample/invocations\n Wed Feb 03 08:21:49 UTC 2016 : Endpoint request headers: {Authorization=xxx, X-Amz-Date=20160203T082149Z, X-Amz-Source-Arn=arn:aws:execute-api:ap-northeast-1:[account-id]:[rest-api-id]/null/GET/cliPathSample, Accept=application/json, User-Agent=AmazonAPIGateway_[rest-api-id], Host=lambda.ap-northeast-1.amazonaws.com}\n Wed Feb 03 08:21:49 UTC 2016 : Endpoint request body after transformations: \n Wed Feb 03 08:21:50 UTC 2016 : Endpoint response body before transformations: {\"name\":\"Taro\",\"age\":20}\n Wed Feb 03 08:21:50 UTC 2016 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=xxxc, Connection=keep-alive, Content-Length=24, Date=Wed, 03 Feb 2016 08:21:49 GMT, Content-Type=application/json}\n Wed Feb 03 08:21:50 UTC 2016 : Method response body after transformations: {\"name\":\"Taro\",\"age\":20}\n Wed Feb 03 08:21:50 UTC 2016 : Method response headers: {Content-Type=application/json}\n Wed Feb 03 08:21:50 UTC 2016 : Successfully completed execution\n Wed Feb 03 08:21:50 UTC 2016 : Method completed with status: 200\n", "latency": 1242, "headers": { "Content-Type": "application/json" } }
5.APIのデプロイ
作成したAPIを公開してアクセスURIを取得する。
aws apigateway create-deployment^ --rest-api-id [rest-api-id]^ --stage-name test^ --stage-description ""^ --description ""
{ "id": "[deployment-id]", "createdDate": 1454488324 }
デプロイを確認。
ただし、下記のコマンドは1つのAPIに対してすべてのデプロイを表示する。
aws apigateway get-deployments^ --rest-api-id [rest-api-id]
{ "items": [ { "id": "[deployment-id]", "createdDate": 1454488324 } ] }
1つのデプロイを指定して内容を確認。
aws apigateway get-deployment^ --rest-api-id [rest-api-id]^ --deployment-id [deployment-id]
{ "id": "[deployment-id]", "createdDate": 1454488324 }
APIのステージ名を取得する。
ただし、下記のコマンドは1つのAPIに対してすべてのステージを表示する。
aws apigateway get-stages^ --rest-api-id [rest-api-id]
{ "item": [ { "stageName": "test", "cacheClusterEnabled": false, "cacheClusterStatus": "NOT_AVAILABLE", "deploymentId": "[deployment-id]", "lastUpdatedDate": 1454488324, "createdDate": 1454488324, "methodSettings": {} } ] }
1つのステージを指定して内容を確認。
aws apigateway get-stage^ --rest-api-id [rest-api-id]^ --stage-name test
{ "stageName": "test", "cacheClusterEnabled": false, "cacheClusterStatus": "NOT_AVAILABLE", "deploymentId": "[deployment-id]", "lastUpdatedDate": 1454488324, "createdDate": 1454488324, "methodSettings": {} }
6.APIの確認
以上の手順で作成したAPIのURIは以下のようになる。
https://[rest-api-id].execute-api.[リージョン名].amazonaws.com/[ステージ名][リソースのパス]
ここの例では、
https://[rest-api-id].execute-api.ap-northeast-1.amazonaws.com/test/cliPathSample
となる。
Management ConsoleのLambdaのところでAPI endpointsを確認しても上記のURIが表示されないのが気になる。。。