ぺーぺーSEのブログ

備忘録・メモ用サイト。

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について

ARNAmazon 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

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メソッドでテストするところまで行う。
以下の順で行う。

  1. AWS Lambdaの作成
  2. API Gatewayの作成
    1. APIの作成
    2. リソース(パス)の作成
    3. HTTPメソッドの作成
  3. AWS LambdaとAPI Gatewayの連携設定
    1. APIのリソースとLambdaの関連付け
    2. AWS LambdaからAPI Gatewayへのレスポンスを作成
    3. API GatewayのメソッドにLambda関数の実行権限付与
    4. API Gatewayのメソッドのレスポンスを作成
  4. 設定したAPI Gateway + AWS Lambdaのテスト
  5. APIのデプロイ
  6. 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が表示されないのが気になる。。。