やったことだけ書く備忘録

Serverless Framework使ってみたメモ

Serveless Framework使ってみる


特定のエンドポイントに対して大量のアクセスが来て、それを捌けるようなアプリケーションの構築案件があって、Lambda + API Gatewayならオートスケールだしいいかもと思って触ってみました。


インストール


npmで入る。



npm install -g serverless

serverless コマンドが使えるけど、長いので省略形の sls コマンドも用意されている(ただのエイリアスっぽい)。



プロジェクトを作る



sls project create

質問に対して入力していくとプロジェクトセットができる(一部伏せています):



Serverless: Initializing Serverless Project...
Serverless: Enter a name for this project: (serverless-hyohxe) serverless-sample
Serverless: Enter a new stage name for this project: (dev)
Serverless: For the "dev" stage, do you want to use an existing Amazon Web Services profile or create a new one?
> Existing Profile
Create A New Profile
Serverless: Select a profile for your project:
yyyyyyy
xxxxxxx
> default
Serverless: Creating stage "dev"...
Serverless: Select a new region for your stage:
us-east-1
us-west-2
eu-west-1
eu-central-1
> ap-northeast-1
Serverless: Creating region "ap-northeast-1" in stage "dev"...
Serverless: Deploying resources to stage "dev" in region "ap-northeast-1" via Cloudformation (~3 minutes)...


AWSのプロファイルはこのタイミングで新規作成できるっぽいけど、普段からaws使ってるのでExisiting Profileを使用した。RegionはTokyoを選択。
このタイミングでUser: arn:aws:iam::xxxxxxx ...みたいなエラーが出る時はPolicyがダメみたいなのでRoleなどを確認してみてください。



あと、Documentを見るとGetting Startedでは「AdministratorAccessのPoclicyつけろ」って書いてあるけど、DEEP DIVEの節では、「AdministratorAccessは簡単にするために書いているんだからね。PowerUserAccessが推奨だよ」って書いてあります。最初からそれでいいんじゃないの。

ファイル構成はこんな感じ:



.
├── _meta
│ ├── resources
│ │ └── s-resources-cf-dev-apnortheast1.json
│ └── variables
│ ├── s-variables-common.json
│ ├── s-variables-dev-apnortheast1.json
│ └── s-variables-dev.json
├── admin.env
├── package.json
├── s-project.json
└── s-resources-cf.json


Functionを作る


関数単位で作成して、各々がLambdaのfunctionに対応しているみたい。



cd serverless-sample/
sls function create function/function1


ランタイムを聞かれるので、nodejs4.3を選択。




Serverless: Please, select a runtime for this new Function
> nodejs4.3
python2.7
nodejs (v0.10, soon to be deprecated)
Serverless: For this new Function, would you like to create an Endpoint, Event, or just the Function?
> Create Endpoint
Create Event
Just the Function...
Serverless: Successfully created function: "functions/function1"


functions/function1ディレクトリができる。Endpoint別に分けて作成したりできそう。



.
├── _meta
│ ├── resources
│ │ └── s-resources-cf-dev-apnortheast1.json
│ └── variables
│ ├── s-variables-common.json
│ ├── s-variables-dev-apnortheast1.json
│ └── s-variables-dev.json
├── admin.env
├── functions
│   └── function1
│   ├── event.json
│   ├── handler.js
│   └── s-function.json
├── package.json
├── s-project.json
└── s-resources-cf.json


function内のファイルは、



  • event.json : ローカル実行用のLambda eventオブジェクトになる(handlerの第一引数)

  • handler.js : メインのLambda実行ファイル

  • s-function.json: AWSの設定とかAPIのハンドラ設定を記述。ややこしい


という構成になっている。基本的にLambda用ですね。
nodeのプロジェクトなら、ここにnpm installとかしてnode_moduleを置けばバンドルしてくれるみたい。便利ですね。



デプロイしてみる



CUIで選択してデプロイする:



sls dash deploy

ServerlessError: Function Deployment Failedというエラーが出ると、Lambdaにdeployする権限が無いらしい。(参考:https://github.com/serverless/serverless/issues/903) この状態でAWSのコンソール上にServerLessがIAM Roleを作成しているので、確認して設定ファイルに追記しないといけないらしいです(面倒):




# _meta/variables/s-variables-dev-appnortheast1.jsonに記述
{
...
"iamRoleArnLambda": "[RoleARNを記述]",
...
}


これで再度deployすると成功しました。Endpointも同時にdeployするとアクセスできるURLが表示されるので、それにアクセスすればレスポンスが確認できます。またはAPI Gatewayの画面からでも確認できますね。

以上、ざっくり使い始めた感触でした。



その他



API EndpointでGET/POSTなリクエストを受け取る時、Lambdaはeventオブジェクトとしてしか受け取れないので、はs-function.jsonの設定でeventオブジェクトへのマッピングを書かないといけないです。 これがApache Velocity形式で書かないといけない上に、JSON内の文字列で書くのは正気の沙汰じゃないと思う…



…ので、GETリクエストの時のクエリパラメータの受け取りとPOSTリクエストの時のPOSTボディの受け取りで上手く行った方法をメモしておきます。endpointsのセクション内の設定です。これをベースにしてパラメータキーの値を調整すれば使えるかと。



GETのクエリパラメータ



例) https://example.com/endpoint?foo=bar&hoge=huga の場合、




"endpoints": [
{
"path": "/endpoint",
"method": "GET",
"type": "AWS",
"authorizationType": "none",
"authorizerFunction": false,
"apiKeyRequired": false,
"requestParameters": {
"integration.request.querystring.foo": "method.request.querystring.foo",
"integration.request.querystring.hoge": "method.request.querystring.hoge"
},
"requestTemplates": {
"application/json": "{\n\"foo\": \"$input.params('foo')\",\n\"hoge\": \"$input.params('hoge')\"}"
},
....
}
]


と書くとhandler.jsonのeventではevent.foo / event.hogeで値が取得できます。



POSTボディ



いわゆる application/x-www-form-urlencodedなMimeTypeでPOSTされるデータです。通常はJSON形式のPOSTを想定しているのか、この形式のマッピングは面倒です。



ref: http://qiita.com/durosasaki/items/83af014aa85a0448770e



こんなの書いてられないので(というか設定できるのかな…)、回避策として、RawDataをそのままパスして、handler.js側でparseするのが賢いと思います。



"endpoints": [
{
"path": "/endpoint",
"method": "POST",
"type": "AWS",
"authorizationType": "none",
"authorizerFunction": false,
"apiKeyRequired": false,
"requestParameters": {
},
"requestTemplates": {
"application/x-www-form-urlencoded": "{\"message\": \"$input.body\"}"
},
....
}
]


としておいて、handler.jsで、



"use strict";

const 
qs = require("querystring");

exports.handler = function(eventcontextcb) {
    const 
postBody qs.parse(event.message);

    
// do something...
};
 


とすればPOSTボディが扱えました。



おまけ



オートスケールだしいいなって思ってパラメータで指定されたサイズのPlaceholder画像を生成して返すアプリを作ってみた。

…のですが、






というわけで無理でした。

あ、あと、LambdaのImageMagickは以前の脆弱性対応からか、policy.xml対応を行っていて、EPHEMERAL, HTTPS, HTTP, URL, FTP, MVG, MSL, TEXT, LABELがDisableになっているようです。


ref: https://alas.aws.amazon.com/ALAS-2016-699.html


なのでLambdaで画像にWaterMark載せたりするのできなくなってました。ご注意を。



結局アプリは愚直にGolangで書いたのでした。現場からは以上です。

« 前の記事 次の記事 »

0件のコメント

コメントを投稿する

 画像に表示されている文字を入力してください。