AWSでRESTfulAPIをAPIGateway+Lambdaで作ろうとすると、ブラウザ上でGUIをいじくるわけですが操作感が独特で慣れるまでちょっとばかし辛いものがあります。そんな時に活躍してくれるのが「Serverless Framework」。YAMLをチョロっと書くだけでそのあたりの設定を良い感じに行ってくれます。
今回はドキュメントの内容に沿って、Serverless Frameworkの導入から実行までを行います。
初期設定
インストール
Serverless FrameworkはNode.js上で動作するため、Node.jsの6以降をインストールしておきます。 https://nodejs.org/ja/nodejs.org
Serverless Frameworkその物のインストールはコマンド一発です。npmはNode.jsと同時に自動的に入ります。
$ npm install -g serverless
今回は以下のバージョンがインストールされました。
$ serverless --version Framework Core: 1.67.3 Plugin: 3.6.6 SDK: 2.3.0 Components: 2.29.3
IAMユーザーの作成
AWSのマネジメントコンソールにログインし、Serverlessフレームワークで利用するIAMユーザーを作成、アクセスキーとシークレットをメモしておきます。ドキュメントによるとこのときの権限はAdministratorAccessが必要とのこと。ちょっと怖いのだがw
IAMのアクセスキーとシークレットを環境変数にセットします。以下のコマンドを毎回入力するか、zshなら~/.zshrc
、bashなら~/.bashrc
などに書いておきます。
export AWS_ACCESS_KEY_ID=xxxxxxxxxxxxxxxxxxxx export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
ファイルに書いた場合は再読み込みを忘れずに。
$ source ~/.zshrc
なおAWS CLIの初期設定がすでに終わっている場合は、こちらの情報が自動的に使われますので上記の設定は不要です。 blog.katsubemakito.net
Serverlessアカウントを作成しログイン
このステップは省略しても構いません。一応Serverlessのサイトに登録しておくとWebブラウザ上から様々な操作が可能になります。serverlessのサイトでアカウントを作成し、CLI上でログインを行います。
その後、以下のコマンドを打つと自動的にWebブラウザが起動するのでログインします。
$ serverless login
CLIに戻り以下のように表示されていれば成功です。
Serverless: You sucessfully logged in to Serverless. Serverless: Please run 'serverless' to configure your service
サービスを作成する
プロジェクトの作成
新しくプロジェクトを作成するか、プロバイダや言語は何にするか、プロジェクトの名前を聞かれますのでそれぞれ入力します。
$ serverless Serverless: No project detected. Do you want to create a new one? Yes Serverless: What do you want to make? AWS Node.js Serverless: What do you want to call this project? hello Project successfully created in 'hello' folder.
Webブラウザから色々できるServerlessサイトの機能を利用するか聞かれます。必要がなければNoでスキップしてください。
Serverless: Would you like to enable this? No You can run the “serverless” command again if you change your mind later.
最初の1回だけタブキーを押すと自動補完が行われる設定を行うか聞かれます。これはやっておいた方が楽です。シェルの種類はご自分の環境に合わせて選択してください。
Serverless: Would you like to setup a command line <tab> completion? Yes Serverless: Which Shell do you use ? zsh Serverless: We will install completion to ~/.zshrc, is it ok ? Yes
最終的に新しくフォルダが作成され、中に以下の2つのファイルが生成されていれば成功です。
$ ls hello
handler.js serverless.yml
serverless.yml
このファイルでプロジェクトの様々な設定を管理します。実際の中身をコメント行と空行をスキップしてのぞいてみます。
$ cat serverless.yml | grep -v '^#' | grep -v '^\s*$'
以下の通りです。今回はHTTP経由でLambdaを実行させたいのでeventsから下を追加(コメントアウト)しています。またここには記載されていませんがデフォルトだとリージョンはus-east-1、ステージはdevに上がります。
service: hello provider: name: aws runtime: nodejs12.x functions: hello: handler: handler.hello events: - http: path: hello method: get
handler.js
実際に実行されるLambda関数です。今回はシンプルな結果にして様子を見たいのでinput: event,
の行はまるごと削除しておきます。
'use strict'; module.exports.hello = async event => { return { statusCode: 200, body: JSON.stringify( { message: 'Go Serverless v1.0! Your function executed successfully!', input: event, }, null, 2 ), }; // Use this code if you don't use the http event with the LAMBDA-PROXY integration // return { message: 'Go Serverless v1.0! Your function executed successfully!', event }; };
ローカルでテスト
serverless invoke local
でローカル上でLambda関数を実行できます。AWSへアップする前の確認に利用できますね。
$ serverless invoke local --function hello { "statusCode": 200, "body": "{\n \"message\": \"Go Serverless v1.0! Your function executed successfully!\"\n}" }
なお、localを付けないとAWSへすでに上がっているLambda関数を実行してくれます。
デプロイ
現在の内容で実際にAWSへアップします。これはコマンド一発。ファイルに修正をして再度上げたい場合も同様です。
$ serverless deploy
色々とメッセージが表示されますが、この中のendpointsの部分をメモしておきます。
endpoints: GET - https://q7t3eobpgb.execute-api.us-east-1.amazonaws.com/dev/hello
実行する
先ほどのendpointsのURLにブラウザで直接アクセスするか、
curlコマンドを実行してみます。
$ curl https://q7t3eobpgb.execute-api.us-east-1.amazonaws.com/dev/hello { "message": "Go Serverless v1.0! Your function executed successfully!" }
handler.jsの内容が実行されているのがわかりますね。
2つ目の関数を作成する
関数を追加したくなった際、もう一つプロジェクトを作っても良いのですが、serverless.ymlに追記することでも実現できます。
handler2.js
新しく「handler2.js」というファイル名で次のLambda関数を用意しました。
'use strict'; module.exports.hello2 = async event => { return { statusCode: 200, body: JSON.stringify( { message: 'I am handler2.js', }, null, 2 ), }; };
sererless.yml
sererless.ymlのファイル後半に先ほど追加したLambda関数の情報を追記しました。
service: hello provider: name: aws runtime: nodejs12.x functions: hello: handler: handler.hello events: - http: path: hello method: get hello2: handler: handler2.hello2 events: - http: path: hello2 method: get
「handler2.hello2」の部分は言い換えると「(ファイル名).(関数名)」を意味しています。今回はファイルを2つに分けましたが、最初に作成された「handler.js」内に複数の関数を定義する方法でも問題なく動作します。
実行する
デプロイすると今まで1つだったendpointsも2つ出てきましたね。
$ serverless deploy (中略) endpoints: GET - https://oqa3rh8s7l.execute-api.us-east-1.amazonaws.com/dev/hello GET - https://oqa3rh8s7l.execute-api.us-east-1.amazonaws.com/dev/hello2
実行してみるとそれぞれ無事に動いているのが確認できました。
$ curl https://oqa3rh8s7l.execute-api.us-east-1.amazonaws.com/dev/hello { "message": "Go Serverless v1.0! Your function executed successfully!" } $ curl https://oqa3rh8s7l.execute-api.us-east-1.amazonaws.com/dev/hello2 { "message": "I am handler2.js" }
AWS上から削除する
使わなくなったサービスをAWS上から削除するのもコマンド一発です。
$ serverless remove
コマンド実行後にcurlで取得すると403が返却されるようになり、
$ curl -i https://q7t3eobpgb.execute-api.us-east-1.amazonaws.com/dev/hello HTTP/2 403 content-type: application/json content-length: 23 date: Tue, 21 Apr 2020 10:37:38 GMT {"message":"Forbidden"}
さらにもうしばらく待つとドメイン毎、設定から消えていることが確認できます。
$ curl -i https://q7t3eobpgb.execute-api.us-east-1.amazonaws.com/dev/hello curl: (6) Could not resolve host: q7t3eobpgb.execute-api.us-east-1.amazonaws.com
もう一度同じ内容で作成したい場合、AWSから削除されただけでローカルのファイルはそっくりそのまま残っていますのでserverless deploy
するだけです。ただしドメインは別の物になるのでご注意を。
設定
ステージを指定
sererless.yml内のproviderの下でstageを指定できます。以下でqaに設定しています。デフォルトはdev。
service: hello provider: name: aws runtime: nodejs12.x stage: qa #(以下略)
なお実行時に一時的に変更したいだけの場合は、以下のようにオプションとして渡すことでYAMLの指定を上書きすることが可能です。例えば完成品を本番にデプロイしたいといった場合にはこちらを利用する感じでしょうか。
$ serverless deploy --stage qa
リージョンを指定
sererless.yml内のproviderの下でregionを指定できます。以下で東京に設定しています。デフォルトはus-east-1。当然と言えば当然なんですがリージョン変えるとURLも変わりますのでご注意くださいませ。
service: hello provider: name: aws runtime: nodejs12.x region: ap-northeast-1 #(以下略)
こちらも実行時に指定することでYAMLの設定を上書きすることができます。以下はオレゴンを指定しています。
$ serverless deploy --region us-west-2
独自ドメインを設定する
もっと使いこなす
クエリーを受け取る
GETでのリクエスト時に/(stage)/hello?foo=123
などURLのお尻にくっついているクエリーを取得したり、POSTでリクエストされた場合にリクエストボディの値を取得します。
blog.katsubemakito.net
外部サーバと通信する
外部サーバからHTTPで通信するサンプルです。特に制約は無いので普通にリクエストすればOKです。 blog.katsubemakito.net
DynamoDBと連携する
受け取ったデータをDynamoDBに保存するサンプルです。ServerlessFrameworkのおかげでテーブルの作成やIAMの設定もYAMLで大半が行えちゃいます。 blog.katsubemakito.net
S3と連携する
RESTful API経由でS3を操作します。保存や削除、バケット内のオブジェクトの一覧を取得するシンプルなサンプルです。 blog.katsubemakito.net
おまけ
既視感ヤバいなと思って調べたら2017年にも同じことやってることが判明するなどw
serverless (npm) 便利やなぁ(小並感)https://t.co/aCehDUkWtD
— 勝部麻季人 💦👏 (@katsube) 2017年12月16日