# サーバーレス環境構築手順書 # 前提 * node: 8.16 * serverlessインストール済み * AWSのアクセスキー取得済み * デプロイを行うIAMユーザーの AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY デプロイを行うIAMユーザーは下記の権限が必要となります。 - AWSLambdaFullAccess - IAMFullAccess - AmazonAPIGatewayAdministrator - AWSLambdaRole - AWSDeepRacerCloudFormationAccessPolicy - AmazonS3FullAccess # 構成 全体構成図 Lambda に4つ関数を追加し、それを API Gateway、CloudFront と接続します。 デプロイ操作用に Cloud9 を利用します。 ![](https://i.imgur.com/C2G5h2h.jpg) # S3 バケットを作成 アクセスログを保存するバケットと、コンテンツを置くバケットを追加します。 ## S3 アクセスログ用ケットを作成 (構成図のNo1) S3アクセルログを保存するバケットを作成します。任意のバケット名(この場では prod-j2-serverless-access-log )を指定してください。 ![](https://i.imgur.com/wVyTVW1.jpg) オプションの設定はデフォルト値でかまいません。次へをクリック。 ![](https://i.imgur.com/q2Q77mX.jpg) システムのアクセス許可の管理にて「Amazon S3 ログ配信グループにこのバケットへの書き込みアクセス権限をする」を指定し、次へをクリック。 ![](https://i.imgur.com/hSVRQqm.jpg) 次へをクリック。 ![](https://i.imgur.com/d1sVrcA.jpg) バケットを作成をクリック。 ![](https://i.imgur.com/qVsOYFF.jpg) ## CloudFrontアクセスログ用バケット(構成図のNo2) CloudFrontアクセスログ用バケットを作成します。 任意のバケット名(この場では prod-j2-serverless-cf-access-log )を指定、次へをクリック。 ![](https://i.imgur.com/60FrNDl.jpg) デフォルト設定のまま、次へをクリック。 ![](https://i.imgur.com/xiJNCMz.jpg) デフォルト設定のまま、次へクリック。 ![](https://i.imgur.com/Oi9phcR.jpg) ## コンテンツ用バケット(構成図のNo3) コンテンツ用のバケットを作成します。 任意のバケット名(この場では prod-j2-serverless-contents )を指定し、次へをクリック。 ![](https://i.imgur.com/KTRGfpZ.jpg) サーバーアクセルログを記録にて、「バケットへのアクセスリクエストを記録します。」のチェックボックスをチェック。ターゲットバケットを指定する。ここでは prod-j2-serverless-contents を指定。次へをクリック。 ![](https://i.imgur.com/g5BBp6F.jpg) デフォルト設定で次へをクリック。 ![](https://i.imgur.com/Knog7Ag.jpg) 確認し、バケット作成をクリック。 ![](https://i.imgur.com/RyRlJrl.jpg) # Cloud9 を作成(構成図のNo4) ![](https://i.imgur.com/YWb9plo.jpg) Name 及び Description を入力し、Next Step をクリック。 ![](https://i.imgur.com/RXlCFHy.png) Environment settings にてデフォルト設定で Next Step をクリック。 ![](https://i.imgur.com/ueRXhUM.jpg) Review(確認画面)で Create environment をクリックし、Cloud9を追加する。 ![](https://i.imgur.com/XcOOjcL.jpg) ## Cloud9 上にソースを展開 任意の方法で Cloud9 の環境にソースをコピーする。 一例で、外部サーバから scp でコピーする。 ``` $ scp xxx@xxxxxx.xxxx:realplan_serverless.zip . $ unzip realplan_serverless.zipo ``` ディレクトリ realpla_serverless が出来上がる想定です。 ![](https://i.imgur.com/m85PSkv.jpg) ## AWS のアクセスキー・シークレットキーを反映 ``` $ export AWS_ACCESS_KEY_ID=XXX $ export AWS_SECRET_ACCESS_KEY=XXX ``` ## serverlessインストール ``` $ cd realpla_serverless/backend $ npm install serverless serverless-offline -g $ npm install axios ``` ### インストール確認 ``` $ sls -v 1.46.1 ``` ![](https://i.imgur.com/s3IKOKD.jpg) ## serverless.yml の修正 - lambda が node.js 6.10 未対応となったため、設定を node.js 8.10 に変更 - デプロイ対象を dev から prod へ変更 - 「plugin: -serverless」 の設定は不要のため削除(あるとエラーが発生する) ``` < runtime: nodejs6.10 --- > runtime: nodejs8.10 31c31 < stage: ${opt:stage, 'dev'} --- > stage: ${opt:stage, 'prod'} 163,164c163,164 < plugins: < - serverless-offline --- > #plugins: > # - serverless-offline ``` ## serverlessからlambdaへデプロイ ## 全体デプロイ(No5) コードのデプロイを行う。 ``` $ sls deploy ``` コンソール上のメッセージ ``` (中略) endpoints: GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/api/rentToshinBukkenSearch GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/api/rentToshinTargetManshonSearch GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/api/rentToshinTenpoSearch GET - https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/prod/api/tyotyomokuSearch ``` APIの endpoint のURLを確認する。(CloudFrontにて設定するため) # CloudFront 設定(構成図のNo6) CloudFrontを設定し、S3 及び API Gateway と接続します。 CloudFrount コンソールの Create Distribution をクリック。 ![](https://i.imgur.com/PQE3gCu.jpg) Web項目の Get Started をクリック。 ![](https://i.imgur.com/CvDb90n.jpg) CloudFront を経由して S3 内のコンテンツへアクセスできるように設定する。 - Origin Domain Name ・・・ 先ほど作成したコンテンツ用のバケットを選択(ここでは prod-j2-serverless-contents) - Restrict Bucket Access ・・・ Yes を選択 - Origin Access Identity ・・・ Create a new identity を選択 - Grant Read Permissions on Bucket ・・・ Yes, Update Bucket Policy を選択 - Viewer Protocol Policy ・・・ Redirect HTTP to HTTPS - Query String Forwarding and Caching ・・・ Forward all, cache based on all を選択 - Default Root Object ・・・ デフォルトで表示されるファイル名を指定。ここでは index.html - Logging ・・・ On を選択 - Bucket for Logs ・・・ 先ほど作成したCloudFrontアクセスログ用のバケットを選択(ここでは prod-j2-serverless-cf-access-log) - Log Prefix ・・・ 任意のプレフィックを入力 ![](https://i.imgur.com/2RDtLzq.jpg) ## API Gateway を接続する設定を行う。 コンソールより該当の CloudFront をクリック。 ![](https://i.imgur.com/kP2Jdsj.jpg) Create Origin をクリック。 ![](https://i.imgur.com/OPRvJQr.jpg) Origin Domain Name に、API Gateway のドメイン(ここでは xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com )を設定。 Origin Protocol Policy を HTTPS only に設定。 Create をクリック。 ![](https://i.imgur.com/H6eA3Gu.jpg) Behaviors タブをクリック。Create Behavior をクリック。 ![](https://i.imgur.com/NSG2dwm.jpg) Path Pattern に /prod/** を指定する。(API のパス) Origin or Origin Group に Origin で指定した API の Domein 名を指定する。 Create をクリック。 ![](https://i.imgur.com/PTWeMus.jpg) # API Gateway の設定(構成図のNo7) API Gatewayの設定は serverless.yml での自動設定ではカバーできない箇所があるため、コンソール上から設定を行う。 API Gateway のコンソールを開く。 prod-backend をクリック。 ![](https://i.imgur.com/we2W9LQ.jpg) prod-backend をクリック。 次の4つのAPIについて設定をそれぞれ行う - /api/rentToshinBukkenSearch - /api/rentToshinTargetManshonSearch - /api/rentToshinTenpoSearch - /api/tyotyomokuSearch ### /api/rentToshinBukkenSearch の設定 /api/rentToshinBukkenSearch の GET をクリック。 ![](https://i.imgur.com/JKVbw21.jpg) ![](https://i.imgur.com/xYJI6nu.jpg) ### メソッドリクエストをクリック URL クエリ文字列パラメータを開く クエリ文字列の追加をクリック areaCd と bukkenId を追加 ![](https://i.imgur.com/Miblgpd.jpg) ### 統合リクエストをクリック ![](https://i.imgur.com/0ZF56cO.jpg) Lambda プロキシ統合の使用 のチェックを外す URL クエリ文字列パラメータを開く bukkenId と areaCd を追加 名前:bukkenId マッピング元:'method.request.querystring.bukkenId' 名前:areaCd マッピング元:'method.request.querystring.areaCd' マッピングテンプレートに application/json を追加。テンプレートに以下を設定。 ※マッピングテンプレート ``` ## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html ## This template will pass through all parameters including path, querystring, header, stage variables, and context through to the integration endpoint via the body/payload #set($allParams = $input.params()) { "body-json" : $input.json('$'), "params" : { #foreach($type in $allParams.keySet()) #set($params = $allParams.get($type)) "$type" : { #foreach($paramName in $params.keySet()) "$paramName" : "$util.escapeJavaScript($params.get($paramName))" #if($foreach.hasNext),#end #end } #if($foreach.hasNext),#end #end }, "stage-variables" : { #foreach($key in $stageVariables.keySet()) "$key" : "$util.escapeJavaScript($stageVariables.get($key))" #if($foreach.hasNext),#end #end }, "context" : { "account-id" : "$context.identity.accountId", "api-id" : "$context.apiId", "api-key" : "$context.identity.apiKey", "authorizer-principal-id" : "$context.authorizer.principalId", "caller" : "$context.identity.caller", "cognito-authentication-provider" : "$context.identity.cognitoAuthenticationProvider", "cognito-authentication-type" : "$context.identity.cognitoAuthenticationType", "cognito-identity-id" : "$context.identity.cognitoIdentityId", "cognito-identity-pool-id" : "$context.identity.cognitoIdentityPoolId", "http-method" : "$context.httpMethod", "stage" : "$context.stage", "source-ip" : "$context.identity.sourceIp", "user" : "$context.identity.user", "user-agent" : "$context.identity.userAgent", "user-arn" : "$context.identity.userArn", "request-id" : "$context.requestId", "resource-id" : "$context.resourceId", "resource-path" : "$context.resourcePath" } } ``` ### メソッドレスポンス HTTPのステータス、200、400、500を追加する。 ![](https://i.imgur.com/i9bEZdp.jpg) HTTP のステータス 200 を開く。 下記のレスポンスヘッダーを追加する。 - Cache-Control - Access-Control-Allow-Headers - Access-Control-Allow-Origin - Access-Control-Allow-Methods - Content-Type ![](https://i.imgur.com/IrPPN2v.jpg) ### 統合レスポンス 200 を開く。 ヘッダーのマッピングを設定 - Cache-Control: 'public, max-age=600' - Access-Control-Allow-Headers: 'Content-Type,X-Amz- Date,Authorization,X-Api-Key' - Access-Control-Allow-Origin: '*' - Access-Control-Allow-Methods: 'GET' - Content-Type: 'application/json;charset=UTF-8' ![](https://i.imgur.com/RlL9qZn.jpg) ### API のデプロイ /api/rentToshinBukkenSearch の GET を選択している状態で、アクションタブから「APIのデプロイ」をクリック。 ![](https://i.imgur.com/5hYHD2I.png) デプロイされるステージで「prod」を選択し、デプロイをクリック。 ![](https://i.imgur.com/pHIve5u.jpg) ### /api/rentToshinTargetManshonSearch の設定 /api/rentToshinBukkenSearch の GET をクリック。 ![](https://i.imgur.com/MlCHHyD.jpg) ![](https://i.imgur.com/q0F8Xgx.jpg) ### メソッドリクエストをクリック URL クエリ文字列パラメータを開く クエリ文字列の追加をクリック areaCd を追加 ![](https://i.imgur.com/Jik47v4.jpg) ### 統合リクエストをクリック Lambda プロキシ統合の使用 のチェックを外す。 URL クエリ文字列パラメータを開く。 areaCd を追加。 名前:areaCd マッピング元:'method.request.querystring.areaCd' マッピングテンプレートに application/json を追加。テンプレートに以下を設定。 ※上記マッピングテンプレートを参照 ![](https://i.imgur.com/xpnxMmk.jpg) ### メソッドレスポンス HTTPのステータス、200、400、500を追加する。 ![](https://i.imgur.com/Ok7NysM.jpg) HTTP のステータス 200 を開く。 - Cache-Control - Access-Control-Allow-Headers - Access-Control-Allow-Origin - Access-Control-Allow-Methods - Content-Type ![](https://i.imgur.com/SdxtG7A.jpg) ### 統合レスポンス Lambdaエラー正規表現に 400.*、ステータス 400 を追加。 Lambdaエラー正規表現に 500.*、ステータス 500 を追加。 ![](https://i.imgur.com/nTpZ0XD.jpg) 200 を開く。 ヘッダーのマッピングを設定 - Cache-Control: 'public, max-age=600' - Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key' - Access-Control-Allow-Origin: '*' - Access-Control-Allow-Methods: 'GET' - Content-Type 'application/json;charset=UTF-8' マッピングテンプレートの application/json を削除。 ![](https://i.imgur.com/qy9l3jz.jpg) ### API のデプロイ /api/rentToshinTargetManshonSearch の GET を選択している状態で、アクションタブから「APIのデプロイ」をクリック。 ![](https://i.imgur.com/5S9rkYK.png) デプロイされるステージで「prod」を選択し、デプロイをクリック。 ![](https://i.imgur.com/pHIve5u.jpg) ### /api/rentToshinTenpoSearch の設定 /api/rentToshinTenpoSearch の GET をクリック。 ![](https://i.imgur.com/wjwaMAD.jpg) ### メソッドリクエストをクリック URL クエリ文字列パラメータを開く クエリ文字列の追加をクリック tenpoCd を追加 ![](https://i.imgur.com/4EPhHki.jpg) ### 統合リクエストをクリック Lambda プロキシ統合の使用 のチェックを外す。 URL クエリ文字列パラメータを開く。 tenpoCd を追加。 名前:tenpoCd マッピング元:'method.request.querystring.tenpoCd' マッピングテンプレートに application/json を追加。テンプレートに以下を設定。 ※上記マッピングテンプレートを参照 ![](https://i.imgur.com/qmva2oY.jpg) ### メソッドレスポンス HTTPのステータス、200、400、500を追加する。 ![](https://i.imgur.com/Ok7NysM.jpg) HTTP のステータス 200 を開く。 - Cache-Control - Access-Control-Allow-Headers - Access-Control-Allow-Origin - Access-Control-Allow-Methods - Content-Type ![](https://i.imgur.com/SdxtG7A.jpg) ### 統合レスポンス Lambdaエラー正規表現に 400.*、ステータス 400 を追加。 Lambdaエラー正規表現に 500.、ステータス 500 を追加。 ![](https://i.imgur.com/xbjKxV1.jpg) 200 を開く。 ヘッダーのマッピングを設定 - Cache-Control: 'public, max-age=600' - Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key' - Access-Control-Allow-Origin: '*' - Access-Control-Allow-Methods: '*' - Content-Type: 'application/json;charset=UTF-8' マッピングテンプレートの application/json を削除。 ![](https://i.imgur.com/EG4iOIJ.jpg) ### API のデプロイ /api/rentToshinTenSearch の GET を選択している状態で、アクションタブから「APIのデプロイ」をクリック。 ![](https://i.imgur.com/uFvGa94.png) デプロイされるステージで「prod」を選択し、デプロイをクリック。 ![](https://i.imgur.com/sLSzWsm.jpg) ### /api/tyotyomokuSearch の設定 /api/tyotyomokuSearch の GET をクリック。 ![](https://i.imgur.com/OJMkPc3.jpg) ### メソッドリクエストをクリック URL クエリ文字列パラメータを開く クエリ文字列の追加をクリック sikutyousonCd を追加。 todoufukenCd を追加。 ![](https://i.imgur.com/3K12jYj.jpg) ### 統合リクエストをクリック Lambda プロキシ統合の使用 のチェックを外す。 URL クエリ文字列パラメータを開く。 sikutyousonCd,todoufukenCd を追加。 名前:sikutyousonCd マッピング元:'method.request.querystring.sikutyousonCd' 名前:todoufukenCd マッピング元:'method.request.querystring.todoufukenCd' マッピングテンプレートに application/json を追加。テンプレートに以下を設定。 ※上記マッピングテンプレートを参照 ![](https://i.imgur.com/8qSy5ym.jpg) ### メソッドレスポンス HTTPのステータス、200、400、500を追加する。 ![](https://i.imgur.com/Ok7NysM.jpg) HTTP のステータス 200 を開く。 - Cache-Control - Access-Control-Allow-Headers - Access-Control-Allow-Origin - Access-Control-Allow-Methods - Content-Type ![](https://i.imgur.com/vSARuMq.jpg) ### 統合レスポンス Lambdaエラー正規表現に ((.*invalid params.*)|(400 .*))、ステータス 400 を追加。 Lambdaエラー正規表現に 500.、ステータス 500 を追加。 ![](https://i.imgur.com/VTebrUP.jpg) 200 を開く。 ヘッダーのマッピングを設定 - Cache-Control: 'public, max-age=600' - Access-Control-Allow-Headers: '*' - Access-Control-Allow-Origin: '*' - Access-Control-Allow-Methods: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key' - Content-Type: 'application/json;charset=UTF-8' マッピングテンプレートの application/json を削除。 ![](https://i.imgur.com/PRxtOXa.jpg) ### API のデプロイ /api/tyotyomokuSearch の GET を選択している状態で、アクションタブから「APIのデプロイ」をクリック。 ![](https://i.imgur.com/DCgTnS0.png) デプロイされるステージで「prod」を選択し、デプロイをクリック。 ![](https://i.imgur.com/sLSzWsm.jpg) # コンテンツのアップロード / 配下に置くコンテンツのアップロードを行います。(この例では prod-j2-serverless-contets バケットへアップロード) Cloud9 環境か、 aws コマンドインストール済及び環境変数 AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY が反映されている環境で実行してください。 ``` $ aws s3 sync contents/ s3://prod-j2-serverless-contents/ ``` # 動作確認 全て設定後、以下のURLをブラウザからアクセスし、動作確認を行います。エラーなく、JSONを応答することを確認します。 xxxxxxxx.cloudfront.net は CloudFront のコンソールでドメインを確認してください。 ``` # S3 バケット内のコンテンツにアクセスできること https://xxxxxxxx.cloudfront.net/index.html # API はそれぞれ、CloudFront 経由でアクセスできることを確認する https://xxxxxxxx.cloudfront.net/prod/api/rentToshinTargetManshonSearch?areaCd=1 https://xxxxxxxx.cloudfront.net/prod/api/rentToshinTenpoSearch?areaCd=1 https://xxxxxxxx.cloudfront.net/prod/tyotyomokuSearch?todoufukenCd=1&sikutyousonCd=1 https://xxxxxxxx.cloudfront.net/prod/api/rentToshinBukkenSearch?bukkenId=4W919127&timestamp=1563262539248 ``` # 再構築する場合 環境を再構築する場合、下記の削除のコマンドを実行後、デプロイ手順を実施する。 ``` $ sls remove ```